# Zillow Property Listings Scraper (`fetch_cat/zillow-property-listings-scraper`) Actor

Scrape public Zillow sale, rent, and sold property search results with prices, addresses, beds, baths, brokers, images, and map coordinates.

- **URL**: https://apify.com/fetch\_cat/zillow-property-listings-scraper.md
- **Developed by:** [Hanna Nosova](https://apify.com/fetch_cat) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 95.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.07 / 1,000 item extracteds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Zillow Property Listings Scraper

Scrape public Zillow property search results and export structured sale, rental, or recently sold listings to CSV, JSON, Excel, or the Apify API.

Use it to monitor housing inventory, collect comparable properties, enrich market research, build relocation shortlists, or track public listing changes by city or Zillow search URL.

### What does this Actor do?

Zillow Property Listings Scraper turns one or more Zillow locations or filtered search URLs into clean, deduplicated property-listing rows. It preserves search-card provenance, enforces explicit numeric filters before charging, and reports partial or empty outcomes without pretending a blocked response succeeded.

**At a glance**

- Search by city, ZIP code, neighborhood, or Zillow search URL.
- Preserve filters embedded in Zillow URLs with `searchQueryState`.
- Export stable ZPIDs, prices, address parts, beds, baths, area, status, coordinates, broker attribution, public card images, Zestimates when present, and provenance.
- Deduplicate before saving and charging.
- Keep valid rows when one search source fails, with per-source diagnostics in `RUN_SUMMARY`.
- Stop before the platform deadline and expose resumable URLs in `RUN_CHECKPOINT`.

### Who is it for?

- **Real-estate investors** tracking prices, inventory, and comparable homes.
- **Agents and brokerages** monitoring public listings in target markets.
- **Proptech and data teams** building internal dashboards from public property search results.
- **Relocation teams** creating shortlists across multiple cities.
- **Market researchers** comparing public sale and rental inventory over time.

### Example input

```json
{
  "locations": ["San Francisco, CA"],
  "listingType": "for_sale",
  "extractionMethod": "AUTO",
  "minBeds": 2,
  "maxItems": 25,
  "maxPages": 1,
  "proxy": { "useApifyProxy": true }
}
```

You can also paste Zillow search result URLs directly:

```json
{
  "startUrls": [
    { "url": "https://www.zillow.com/homes/for_rent/Austin,-TX_rb/" }
  ],
  "maxItems": 50,
  "maxPages": 2
}
```

### Output example

```json
{
  "zpid": "12345678",
  "url": "https://www.zillow.com/homedetails/12345678_zpid/",
  "address": "123 Market St, San Francisco, CA 94103",
  "addressCity": "San Francisco",
  "addressState": "CA",
  "addressZipcode": "94103",
  "price": "$1,250,000",
  "unformattedPrice": 1250000,
  "currency": "USD",
  "beds": 3,
  "baths": 2,
  "area": 1450,
  "propertyType": "SINGLE_FAMILY",
  "homeStatus": "FOR_SALE",
  "statusText": "For sale",
  "zestimate": 1210000,
  "rentZestimate": 5200,
  "latitude": 37.7749,
  "longitude": -122.4194,
  "brokerName": "Example Realty",
  "imageUrl": "https://photos.zillowstatic.com/...jpg",
  "imageUrls": ["https://photos.zillowstatic.com/...jpg"],
  "daysOnZillow": 12,
  "isFeatured": false,
  "listingType": "for_sale",
  "sourceUrl": "https://www.zillow.com/homes/for_sale/San-Francisco,-CA_rb/",
  "sourcePage": 1,
  "sourceRoute": "HTML",
  "scrapedAt": "2026-07-08T08:00:00.000Z"
}
```

### Input settings

| Setting | API key | Type | Description |
| --- | --- | --- | --- |
| Zillow search URLs | `startUrls` | array | Search-result URLs. Filtered URLs with `searchQueryState` preserve their map and filter state. |
| Locations | `locations` | array | City, ZIP code, neighborhood, or area names converted to Zillow search URLs. |
| Resume URLs | `resumeSearchUrls` | array | URLs copied from `RUN_CHECKPOINT` after a bounded deadline stop. They replace fresh URLs and locations. |
| Listing type | `listingType` | string | `for_sale`, `for_rent`, or `sold` for generated location searches. |
| Extraction method | `extractionMethod` | string | `AUTO`, `PAGINATION`, or `SEARCH_STATE`. AUTO is recommended. |
| Maximum listings | `maxItems` | integer | Global maximum unique rows, from 1 to 10,000. |
| Pages per search | `maxPages` | integer | Maximum pages per source, from 1 to 20. |
| Minimum price | `minPrice` | number | Keep rows at or above this numeric price. |
| Maximum price | `maxPrice` | number | Keep rows at or below this numeric price. |
| Minimum bedrooms | `minBeds` | number | Keep rows with at least this many bedrooms. |
| Minimum bathrooms | `minBaths` | number | Keep rows with at least this many bathrooms. |
| Proxy configuration | `proxy` | object | Existing runs default to a US residential Apify Proxy session. Omit groups for that default, use an explicit empty group list for standard Apify datacenter routing, supply other authorized groups, or disable the proxy. |

`AUTO` uses Zillow's structured search-state response when a URL already contains valid `searchQueryState`; otherwise it reads structured data embedded in search pages. `SEARCH_STATE` is strict and rejects location-only inputs or URLs without valid state instead of silently dropping filters.

### Output fields

| Group | Fields |
| --- | --- |
| Identity | `zpid`, `url`, `providerListingId` |
| Address | `address`, `addressStreet`, `addressCity`, `addressState`, `addressZipcode` |
| Price and estimates | `price`, `unformattedPrice`, `currency`, `zestimate`, `rentZestimate` |
| Property | `beds`, `baths`, `area`, `lotAreaValue`, `lotAreaUnit`, `propertyType` |
| Listing status | `homeStatus`, `statusText`, `daysOnZillow`, `isFeatured`, `isShowcaseListing` |
| Location and attribution | `latitude`, `longitude`, `brokerName` |
| Media/open house | `imageUrl`, `imageUrls`, `hasImage`, `has3DModel`, `hasVideo`, `hasOpenHouse`, `openHouseStartDate`, `openHouseEndDate` |
| Provenance | `listingType`, `sourceUrl`, `sourcePage`, `sourceRoute`, `scrapedAt` |

Fields are `null` or an empty array when Zillow does not include them in the search card. This Actor does not fabricate property-detail data.

The default key-value store also contains:

- `RUN_SUMMARY`: final status, saved/charged parity, retries, per-source results, warnings, and any fatal error.
- `RUN_CHECKPOINT`: the latest bounded progress marker and `resumeSearchUrls` when work remains.

### Pricing

This Actor uses Apify pay-per-event pricing. A one-time `start` event is charged when a run starts, and the primary `item` event is charged for each Zillow property listing saved to the dataset. Current rates depend on your Apify plan or custom agreement, so use the live [Apify Pricing tab](https://apify.com/fetch_cat/zillow-property-listings-scraper/pricing) as the source of truth before running production jobs.

Apify may also charge platform usage for compute, storage, proxies, or data transfer outside this Actor pricing. Check the Actor run and the live Pricing tab for the exact cost shown to your account.

### Input recipes

**Austin rentals**

```json
{"locations":["Austin, TX"],"listingType":"for_rent","maxItems":20,"maxPages":1}
```

**Denver homes between $500,000 and $1,500,000 with at least two bedrooms**

```json
{"locations":["Denver, CO"],"minPrice":500000,"maxPrice":1500000,"minBeds":2,"maxItems":25,"maxPages":2}
```

**Exact filtered Zillow search**

Open Zillow, apply filters, copy the resulting URL containing `searchQueryState`, and paste it into `startUrls` with `"extractionMethod":"AUTO"`.

### Tips for better results

- Start with a small `maxItems` value for your first run.
- Prefer a copied Zillow search URL when exact map bounds or Zillow-native filters matter.
- Keep `maxPages` conservative. Ordinary Zillow result pagination is commonly capped near 20 pages for one region/filter slice.
- If one source fails after other sources save rows, inspect `RUN_SUMMARY` instead of assuming the entire dataset is complete.
- Copy `RUN_CHECKPOINT.resumeSearchUrls` into the `resumeSearchUrls` input after a deadline-bounded partial run.
- Explicit numeric filters are applied before saving and charging. A run can legitimately finish `EMPTY_FILTERED` when Zillow returned candidates but all were excluded.

### Limits and practical notes

- Zillow can change its search-state or page payload. HTTP 200 challenge pages are treated as blocks, not as empty searches.
- Requests are sequential and retry budgets are bounded; the Actor does not promise unlimited throughput.
- Only public listing/search data is extracted. The actor does not access private accounts, messages, saved homes, or owner-only data.
- It detects but does not solve CAPTCHA/challenge pages.
- Search-card output is not the same as full property-detail output. Tax history, complete price history, schools, descriptions, agent contacts, and full photo galleries are outside this Actor's contract.

### API usage

Run the actor from cURL:

```bash
curl "https://api.apify.com/v2/acts/fetch_cat~zillow-property-listings-scraper/runs?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"locations":["San Francisco, CA"],"listingType":"for_sale","maxItems":20}'
```

Run it from Node.js:

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/zillow-property-listings-scraper').call({
  locations: ['San Francisco, CA'],
  listingType: 'for_sale',
  maxItems: 20,
});
console.log(run.defaultDatasetId);
```

Run it from Python:

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('fetch_cat/zillow-property-listings-scraper').call(run_input={
    'locations': ['San Francisco, CA'],
    'listingType': 'for_sale',
    'maxItems': 20,
})
print(run['defaultDatasetId'])
```

### MCP and agents

Use this actor from Apify MCP-compatible agents with:

```text
https://mcp.apify.com?tools=fetch_cat/zillow-property-listings-scraper
```

Add it to Claude Desktop or Claude Code with a command like:

```bash
claude mcp add apify-zillow --url "https://mcp.apify.com?tools=fetch_cat/zillow-property-listings-scraper"
```

Example MCP server JSON config:

```json
{
  "mcpServers": {
    "apify-zillow": {
      "url": "https://mcp.apify.com?tools=fetch_cat/zillow-property-listings-scraper"
    }
  }
}
```

Example prompts:

- "Scrape up to 20 Zillow for-sale listings in San Francisco and summarize median price."
- "Collect rental listings for Austin and return address, price, beds, baths, and URL."
- "Compare public Zillow inventory for Denver and San Francisco using this actor."

### Legality and responsible use

Use this Actor only within your authorization and applicable law. It extracts listing/search information without collecting Zillow login credentials. Do not use it for private account data, messages, saved homes, or purposes outside your permitted data scope. Keep request volume and retention within your authorization.

### FAQ

**Does this actor need a Zillow account?**
No. It is designed for public search result pages only.

**Can it scrape rentals and sold properties?**
Yes. Use `listingType` for location inputs or paste matching Zillow search URLs in `startUrls`.

**Why did my run stop with a block message?**
Zillow may block automated traffic. Lower `maxPages`, keep concurrency low, and use Apify residential proxy settings.

**Can I use exact Zillow filter URLs?**
Yes. Paste the filtered Zillow search URL into `startUrls`. `AUTO` preserves a valid `searchQueryState`; `SEARCH_STATE` requires it explicitly.

**Does it use Zillow GraphQL?**
No. GraphQL evidence currently applies mainly to full property-detail queries. This Actor uses Zillow search-card state and search-page data so it does not multiply detail requests or silently expand the paid output contract.

**Why did a zero-result run fail?**
An unexplained empty discovery fails to prevent misleading success. A zero-row run succeeds only as `EMPTY_FILTERED` when Zillow returned candidates and your explicit numeric filters excluded all of them.

**Does it scrape property detail pages?**
The first version focuses on search-result listing data. Detail-page enrichment can be added later if demand and reliability justify it.

### Related actors

- [Google Maps Scraper](https://apify.com/fetch_cat/google-maps-scraper)
- [Zillow Property Details Scraper](https://apify.com/fetch_cat/zillow-property-details-scraper)
- [Rightmove Property Listings Scraper](https://apify.com/fetch_cat/rightmove-property-listings-scraper)
- [Idealista Property Listings Scraper](https://apify.com/fetch_cat/idealista-property-listings-scraper)
- [Google Search Results Scraper](https://apify.com/fetch_cat/google-search-results-scraper)

### Support

If a run fails or the output looks wrong, open an issue or report a bug from the Actor page. Include the Apify run ID or run URL, input JSON, expected output, actual output, and one reproducible public URL from a Zillow search. Remove any credentials or private data before posting.

### Privacy and data handling

This Actor runs with Apify limited permissions and processes the location/search inputs needed for the documented run. Results, `RUN_SUMMARY`, and `RUN_CHECKPOINT` remain in the run's Apify storage. FetchCat does not use your inputs or outputs for advertising or model training and does not retain them outside Apify run storage except for transient support debugging when you explicitly share run details. You are responsible for lawful use, authorized retention, and avoiding unnecessary personal or sensitive data.

# Actor input Schema

## `startUrls` (type: `array`):

One or more Zillow search-result URLs. Filtered URLs containing searchQueryState can use the structured search-state route and preserve their map and filter settings.

## `locations` (type: `array`):

City, ZIP code, neighborhood, or area names. The Actor converts each value to a Zillow search URL using listingType.

## `resumeSearchUrls` (type: `array`):

Optional URLs copied from RUN\_CHECKPOINT.resumeSearchUrls after a bounded deadline stop. When supplied, these replace fresh start URLs and locations.

## `listingType` (type: `string`):

Used for generated location searches. A pasted search URL keeps the mode and filters encoded in that URL.

## `extractionMethod` (type: `string`):

AUTO uses Zillow's structured search-state response for URLs with searchQueryState and HTML pagination otherwise. PAGINATION always reads search pages. SEARCH\_STATE requires filtered URLs with searchQueryState.

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

Maximum unique listings saved across every search source. Range: 1-10,000.

## `maxPages` (type: `integer`):

Maximum result pages requested for each search source. Zillow commonly caps ordinary pagination near 20 pages.

## `minPrice` (type: `number`):

Keep listings whose numeric price is at least this value. Listings without a numeric price are excluded when this filter is active.

## `maxPrice` (type: `number`):

Keep listings whose numeric price is no more than this value. Must be at least minPrice.

## `minBeds` (type: `number`):

Keep listings with at least this many bedrooms.

## `minBaths` (type: `number`):

Keep listings with at least this many bathrooms.

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

Existing runs use a US residential Apify Proxy session by default because Zillow frequently blocks datacenter traffic. Omit groups for that default, provide an empty group list for standard Apify datacenter routing, provide other authorized groups, or disable proxy use.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.zillow.com/homes/for_sale/San-Francisco,-CA_rb/"
    }
  ],
  "locations": [
    "San Francisco, CA"
  ],
  "resumeSearchUrls": [],
  "listingType": "for_sale",
  "extractionMethod": "AUTO",
  "maxItems": 20,
  "maxPages": 1,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

## `runCheckpoint` (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 = {
    "startUrls": [
        {
            "url": "https://www.zillow.com/homes/for_sale/San-Francisco,-CA_rb/"
        }
    ],
    "locations": [
        "San Francisco, CA"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetch_cat/zillow-property-listings-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 = {
    "startUrls": [{ "url": "https://www.zillow.com/homes/for_sale/San-Francisco,-CA_rb/" }],
    "locations": ["San Francisco, CA"],
}

# Run the Actor and wait for it to finish
run = client.actor("fetch_cat/zillow-property-listings-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.zillow.com/homes/for_sale/San-Francisco,-CA_rb/"
    }
  ],
  "locations": [
    "San Francisco, CA"
  ]
}' |
apify call fetch_cat/zillow-property-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=fetch_cat/zillow-property-listings-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dWFnXVVnn84CXqdrz/builds/oC5RJ9gkwLMNHL4dm/openapi.json
