# Zillow ZIP Code Search Scraper 💰 From $1.4/1K · Bulk ZIP Lists (`memo23/zillow-zip-code-search-scraper`) Actor

Give it a list of ZIP codes and get Zillow listings in them, for sale, for rent or recently sold. Turn on More results and raise Max items to split a dense ZIP past Zillow's 500-per-search cap. Price, status, address and coordinates per row; agent and broker with details on.

- **URL**: https://apify.com/memo23/zillow-zip-code-search-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Real estate, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 📮 Zillow ZIP Code Search Scraper

Give it **a list of ZIP codes** and get Zillow listings in them — for sale, for rent, or recently sold. One row per property, with price, status, address and coordinates.

Built for the job people actually do with ZIP codes: sweep a whole territory, a county's worth of codes, or a farm area, in a single run.

### ⭐ Why use this Zillow ZIP scraper?

- **Past the 500 cap** — Zillow returns at most 500 results per search. Turn on **Scrape beyond 500 results limit** and raise **Max Items** (default 100), and each ZIP is split into smaller map areas instead of silently stopping at 500.
- **A list, not one code at a time** — paste every ZIP you cover; each becomes its own search and they run together.
- **Sale, rent or sold** — one switch changes what the whole sweep returns.
- **Real filters** — price, beds, baths and home type go into Zillow's own search query rather than being thrown away after the fact. On the mobile endpoint, which the run can fall back to when the web search is blocked, price and status carry over and the finer filters do not.
- **Agent email enrichment (optional)** — add the listing agent's direct email and phone from a 1,200,000+ US agent database. Needs **Include property details** switched on as well, because the lookup runs during the per-property detail fetch.
- **Proxies included on paid plans** — on any paid Apify plan the run goes out through the actor's own residential proxy pool at no extra cost, and the proxy input is not read. Free-plan runs use Apify's default datacenter proxy, which Zillow refuses, so there you need to set **Proxy configuration** to Apify RESIDENTIAL or your own residential URLs.

### 📋 What data does it extract?

| Field group | Columns |
| --- | --- |
| **Identity** | `ID` (ZPID), `URL`, `Address`, `City`, `State`, `Zip Code`, `Latitude`, `Longitude` |
| **Listing** | `Price`, `Status`, `Acres` |
| **People** | `Agent Name`, `Agent Number`, `Broker Name`, `Broker Number` — with **Include property details** on |
| **Agent email (optional)** | `contactEmail`, `contactPhone`, `agentEmailSource` — with **Agent email enrichment** and **Include property details** on |
| **Beds / baths / size** | `Beds`, `Baths`, `Sq Ft`, `Year Built` — with **Include property details** and **Flattened output** both on |
| **Run metadata** | `Date` (the date the run executed, not a listing date) |
| **Optional depth** | `details` — full property record with description, price history, tax history, schools, photos |

### 🧾 Supported inputs

| Input | Example |
| --- | --- |
| ZIP code | `78704` |
| Several ZIPs | one per line: `78704`, `90210`, `33139` |
| City or neighborhood | `Austin, TX`, `Brooklyn, NY` |

### 💡 Use cases

- **Agents & teams** — sweep every ZIP in your farm area on a schedule and watch new inventory appear.
- **Investors** — pull whole ZIPs of recently sold homes to build comps and spot price movement.
- **Lenders & title** — map activity across the ZIP codes you are licensed in.
- **Proptech & data teams** — ZIP is the unit most property datasets already key on, so these rows join straight onto what you have.
- **Market research** — compare inventory and price across neighbouring codes.

### 🚀 How it works

Each ZIP is resolved to Zillow's own region, then queried through the search API with your filters applied server-side. With **Scrape beyond 500 results limit** on, any search reporting more than 500 matches is split into map quadrants, and each quadrant is split again until every part fits under the cap.

### ⚙️ Input configuration

| Field | Type | Notes |
| --- | --- | --- |
| `searchLocation` | array | One ZIP per line, e.g. `78704`. City names work too |
| `status` | enum | `forSale`, `forRent`, `sold` |
| `moreResults` | boolean | Split dense ZIPs to get past the 500-result cap |
| `priceMin` / `priceMax` | integer | Price range |
| `bedsMin` / `bathsMin` | integer | Minimums |
| `homeTypes` | array | House, condo, townhouse, land, … |
| `includePropertyDetails` | boolean | Adds the full record and agent contacts per row (slower) |
| `flatOutput` | boolean | Needs `includePropertyDetails` on; on a plain search it changes nothing. With both on, the nested `details` blob is dropped and flat spreadsheet columns are appended, `Beds`, `Baths`, `Sq Ft` and `Year Built` among them |
| `enrichEmails` | boolean | Agent email lookup, billed per email found. Needs `includePropertyDetails` on |
| `maxItems` | integer | Stop after this many listings |

Every field, with its type and default, is also listed on the actor’s own [input schema page](https://apify.com/memo23/zillow-zip-code-search-scraper/input-schema).

### 📦 Output sample

```json
{
  "ID": "29473051",
  "URL": "https://www.zillow.com/homedetails/2107-Arpdale-St-Austin-TX-78704/29473051_zpid/",
  "Address": "2107 Arpdale St, Austin, TX 78704",
  "City": "Austin",
  "State": "TX",
  "Zip Code": "78704",
  "Price": 1075000,
  "Status": "FOR_SALE",
  "Latitude": 30.248713,
  "Longitude": -97.779
}
```

That is an excerpt. Every row also carries the rest of the standard column set — about 30 columns, the same headers on every run — and on a ZIP sweep most of them are empty. Description, zoning and the agent and broker columns fill once **Include property details** is switched on.

### 🔑 Key output fields

- `Zip Code` — the ZIP the row actually sits in, so a multi-ZIP run can be grouped without re-parsing addresses.
- `Status` — `FOR_SALE`, `FOR_RENT`, `RECENTLY_SOLD`, matching the sweep you asked for. With **Include property details** and **Flattened output** both on it is re-read from the property's own page, so a listing that moved in between can come back as Zillow's live state instead (`PENDING`, `SOLD`).
- `Price` — asking price, or sold price on a closed sale. Blank where Zillow publishes no figure.
- `ID` — the ZPID on for-sale and sold rows, matching the zpid inside the row's own `URL`. A for-rent sweep also returns Zillow's building and cluster pins: those rows carry a `latitude--longitude` pseudo-id in `ID` and a `/b/` or `/apartments/` URL with no zpid in it.
- `details` — present with **Include property details** on and **Flattened output** off; that same switch is what fills the agent and broker columns.
- `contactEmail` — the email the enrichment toggle looks up, with `contactPhone` and `agentEmailSource` beside it. Rows that reached their detail record carry the three columns once the toggle is on, empty where no match was found; a listing whose detail fetch failed outright comes back as the bare search row without them. With **Flattened output** on there is also an `Agent Email` column, taken from Zillow's own listing attribution and usually empty; enrichment fills `contactEmail`, not that one.

The standard columns are Title Case (`Address`, `Zip Code`, `Agent Name`) so they read cleanly as spreadsheet headers. The enrichment additions keep Zillow-style camelCase — `contactEmail`, `contactPhone`, `agentEmailSource` — as does the nested `details` key.

### ❓ FAQ

**I asked for a whole ZIP and got exactly 500 rows.**
Turn on **Scrape beyond 500 results limit**. Without it, Zillow's own cap stops the search at 500 and the rest is never served.

**Why are `Agent Name` and `Broker Name` empty?**
Those come from each listing's detail record. Switch on **Include property details** and they fill, at the cost of one extra fetch per property.

**Why did a run stop early?**
Usually **Max Items**, which defaults to 100 — raise it and the sweep keeps going. The other cause is the "Maximum cost per run" limit; when that is what cut the run short, the run says so in its status message. A run does not resume where the last one stopped, so raise the limit rather than re-running.

**Do sold listings include the sale price?**
Usually. Not in non-disclosure states, where a sale price is not public record — Texas is the one we have measured, and there Zillow publishes no figure, so `Price` comes back blank.

**Can I mix ZIPs and city names?**
Yes. Each line is resolved independently, so `78704` and `Brooklyn, NY` can sit in the same run.

**Do I need proxies or an API key?**
No API key, and no login is used. On a paid Apify plan the actor's own residential proxies are included at no extra cost and the proxy input is not read. On the free plan the run uses Apify's default datacenter proxy, which Zillow refuses, so set **Proxy configuration** to Apify RESIDENTIAL or your own residential URLs.

### 🛟 Support

Open an issue on the actor's **Issues** tab with the run ID and the ZIP that looked wrong — that is enough to trace it.

### 🧩 Additional services

Need a custom pipeline (specific columns, delivery to your DB/S3/webhook, merged multi-source feeds)? Open an issue describing what you need or contact the author through the actor page.

### 🔎 Explore more scrapers

Eleven Zillow actors, all maintained by the same author. The six listing scrapers under **Listings and properties** emit the same standard columns as this one, so rows from any of them line up in one sheet; some add a column or two of their own on top.

**Listings and properties**

- [Zillow Scraper](https://apify.com/memo23/zillow-scraper-ppe) — the flagship: the same engine with more to set than this page has, including pasted Zillow URLs, the full filter set and change monitoring. This one is trimmed to a ZIP list plus the core filters.
- [Zillow Detail Scraper](https://apify.com/memo23/zillow-detail-scraper) — the full record for specific properties, by URL, ZPID or plain address.
- [Zillow Rentals Scraper](https://apify.com/memo23/zillow-rentals-scraper) — rentals, with the rent range on apartment-complex rows.
- [Zillow Open Houses Scraper](https://apify.com/memo23/zillow-open-houses-scraper) — upcoming open houses with their exact dates and times.
- [Zillow Foreclosure Scraper](https://apify.com/memo23/zillow-foreclosure-scraper) — pre-foreclosure, auction and bank-owned (REO) records with auction dates and amounts.
- [ZILLOW | Bypass Limit of 500 | Search | Agent | with Email](https://apify.com/memo23/zillow-cheerio-scraper) — the earlier search build, kept in step with the flagship, with the same agent email enrichment.

**People and contacts**

- [Zillow Agents Leads](https://apify.com/memo23/zillow-agents-leads-scraper-ppe) — agent contacts pulled from a database of 1,200,000+ US agents.
- [Zillow Agents Scraper](https://apify.com/memo23/apify-zillow-agents-cheerio) — agent finder and profile pages, with email discovery.
- [Zillow Property Managers Scraper](https://apify.com/memo23/apify-zillow-property-managers-cheerio) — property managers and owners, with emails.
- [Zillow Lenders Scraper](https://apify.com/memo23/zillow-lenders-scraper) — mortgage lenders from Zillow’s own lender directory.

Beyond Zillow: [all actors by memo23](https://apify.com/memo23), 100+ maintained scrapers for real estate, jobs, directories and reviews. Other sites, other authors: the [Apify Store](https://apify.com/store).

### 🤖 For AI Agents & LLM Apps

This actor is MCP-ready: call it from AI agents (Claude, GPT, LangChain, LlamaIndex, or the Apify MCP server) to answer questions like *"how many homes are for sale under $500k in 78704 right now?"*. ZIP codes are a unit an agent can derive from a user's question without building a Zillow URL, and the structured JSON with stable field names makes rows directly usable as tool results.

To wire it up: the ready-made [Node.js](https://apify.com/memo23/zillow-zip-code-search-scraper/api/javascript) and [Python](https://apify.com/memo23/zillow-zip-code-search-scraper/api/python) client snippets call this actor in a few lines (full client reference: [JavaScript](https://docs.apify.com/api/client/js/docs), [Python](https://docs.apify.com/api/client/python/docs)), and the [MCP tab](https://apify.com/memo23/zillow-zip-code-search-scraper/api/mcp) exposes it as a tool to an MCP client. In your own Apify Console, where you are signed in, the actor's [integrations](https://console.apify.com/actors/wts2O7u5RgXMuVyyc/integrations/options) push each run straight to Google Sheets, Slack, a webhook or your own storage ([how integrations work](https://docs.apify.com/integrations)).

### ⚠️ Disclaimer

This actor is not affiliated with, endorsed by, or connected to Zillow Group. It extracts only publicly visible listing information for lawful purposes such as market research and personal planning; no login is used and no private data is accessed. You are responsible for how you use the data — respect Zillow’s terms and applicable laws. Apify’s own write-up on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) is a good starting point, and personal data in the output (agent names, phone numbers, emails) falls under rules such as [EU Regulation 2016/679](https://eur-lex.europa.eu/eli/reg/2016/679/oj).

***

*zillow zip code scraper · scrape zillow by zip · zillow postal code search · bulk zillow zip search · zillow listings by zip code · zillow zip API · real estate zip code data · export zillow zip search to excel*

# Actor input Schema

## `searchLocation` (type: `array`):

One ZIP code per line, e.g. 78704. Each becomes its own search. City names ("Austin, TX") work too.

## `status` (type: `string`):

Which listings to return for the search location(s).

## `moreResults` (type: `boolean`):

Zillow caps a single search at 500 results. Turn this on and the search is split into smaller map areas, so a dense ZIP gets past that cap. Raise Max items to match: the default of 100 stops the run long before the split has delivered everything.

## `priceMin` (type: `integer`):

Minimum sale price, or minimum monthly rent when status is For rent. Leave blank for no minimum.

## `priceMax` (type: `integer`):

Maximum sale price, or maximum monthly rent when status is For rent. Leave blank for no maximum.

## `bedsMin` (type: `integer`):

Minimum bedrooms.

## `bathsMin` (type: `integer`):

Minimum bathrooms.

## `homeTypes` (type: `array`):

Limit to specific property types. Leave empty for all.

## `includePropertyDetails` (type: `boolean`):

Include property details in the output.

## `flatOutput` (type: `boolean`):

Needs Include Property Details switched on as well — the flat columns are built during the per-property detail fetch, so on a plain search this toggle changes nothing. With both on, the nested `details` GraphQL blob is dropped and flat scalar columns are appended instead: Listing Date, Days on Zillow, Year Built, Status, Beds, Baths, Sq Ft, MLS ID, MLS Status, Annual Tax, Tax Assessed Value, a price-history summary, New Roof flag, Permit History, Detail URL. Smaller rows, easier to import into spreadsheets. The `Agent Email` / `Broker Email` columns come from Zillow's own listing attribution, which is usually empty — the looked-up email is `contactEmail`, from the enrichment toggle below.

## `enrichEmails` (type: `boolean`):

If enabled, adds the listing agent's email (and phone) to every property we can match — from our database of 1,200,000+ U.S. agents, ~99.9% of which have an email on file. Adds contactEmail, contactPhone and agentEmailSource columns, empty on a miss so the column set stays stable. Billed per email found; only charged when an email is returned, never for misses. Needs Include Property Details switched on as well — the lookup runs during the per-property detail fetch.

## `maxItems` (type: `integer`):

Maximum number of items to scrape.

## `maxConcurrency` (type: `integer`):

Maximum number of requests the scraper runs in parallel. Anything above 32 is capped at 32 — the native HTTP client crashes beyond that.

## `maxRequestRetries` (type: `integer`):

Upper bound on how many times a failed request is retried before the scraper gives up. Some request types use a lower internal cap (4 or 10 tries) whatever you set here.

## `proxy` (type: `object`):

On a paid Apify plan this field is not read at all: the run always goes out through the actor's own residential proxy pool, at no extra cost to you. On the free plan it is read, and leaving it empty means Apify's default datacenter proxy, which Zillow refuses — so on the free plan set it to Apify RESIDENTIAL or your own residential proxy URLs.

## Actor input object example

```json
{
  "searchLocation": [
    "78704",
    "90210"
  ],
  "status": "forSale",
  "moreResults": false,
  "includePropertyDetails": false,
  "flatOutput": false,
  "enrichEmails": false,
  "maxItems": 100,
  "maxConcurrency": 20,
  "maxRequestRetries": 5
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchLocation": [
        "78704",
        "90210"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/zillow-zip-code-search-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "searchLocation": [
        "78704",
        "90210",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/zillow-zip-code-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchLocation": [
    "78704",
    "90210"
  ]
}' |
apify call memo23/zillow-zip-code-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/zillow-zip-code-search-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/wts2O7u5RgXMuVyyc/builds/3ddkD9KQmsm8e7tmv/openapi.json
