# Zillow Scraper: US Listings, Price Drops & ZIP Market Stats (`datasmithlab/zillow-property-scraper`) Actor

Export Zillow sale/rental listings by city or ZIP, track price changes and summarize collected listings by ZIP. Limits and access determine coverage; summaries are sample-based and REMOVED is not proof of a sale.

- **URL**: https://apify.com/datasmithlab/zillow-property-scraper.md
- **Developed by:** [Datasmithlab](https://apify.com/datasmithlab) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 listings

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 Scraper: US Listings, Price Drops & ZIP Market Stats

Export Zillow sale/rental listings by city, county, ZIP or search URL, with prices, Zestimate, rent estimates and home details where available.

Zillow shows at most 820 homes per search. ZIP splitting expands coverage, but individual ZIP caps, postal-city coverage, filters, access and maxItems still apply. The entire city market is not guaranteed. Check SEARCHES for available/seen/matched/written listings, pages and skipped searches; status=ok alone does not prove a complete scan.

Monitoring tracks new listings and price changes. REMOVED is absence from the comparable search, not proof of a sale or rental. Removal detection requires complete, stable scans and has safeguards.

ZIP summaries describe collected matching listings. A small total limit can leave later ZIPs unread; missing fields reduce the sample for individual metrics. These are not automatically complete ZIP-market statistics. No login or browser is required; agent names and contact details are not collected.

### Quick start

Start with one ZIP, up to 20 listings, summaries and monitoring off. Check SEARCHES before increasing limits. A first ZIP can consume the total limit before later ZIPs are read. A limited snapshot is not a complete monitoring baseline.

```json
{
  "locations": [
    "78701"
  ],
  "mode": "forSale",
  "maxItems": 20,
  "onlyNewOrChanged": false,
  "marketSummary": false,
  "splitByZip": true
}
```

### Track observed Zillow price changes in Google Sheets

Use the inactive n8n starter with your own Apify and Google credentials. Start with 20 sale listings in one ZIP, Actor tracking and market summaries off, and a $0.10 Actor charge cap. Compare prices only when the same listing is observed again; missing prices retain the last known price, and absent listings are not marked sold or removed. The table retains the last price event and its timestamp; execution summaries identify current-run changes. Two real 20-listing snapshots delivered successfully without duplicates or observed price changes. Synthetic tests verify price-drop logic; they do not prove a real market price drop. Limited snapshots are not complete ZIP coverage. Run sequentially and validate before enabling the daily schedule. Tested on self-hosted n8n 2.26.4; no official n8n directory acceptance claimed.

- [Download starter ZIP](https://github.com/Datasmith-lab/datasmithlab-zillow-n8n/releases/latest/download/zillow-prices-to-sheets-starter.zip)
- [View the walkthrough](https://datasmith-lab.github.io/datasmithlab-zillow-n8n/)
- [Read the setup guide](https://github.com/Datasmith-lab/datasmithlab-zillow-n8n#setup)

### What you get

- **Prices as numbers.** `price: 375000` (monthly rent for rentals), `pricePerSqft: 125.33`, `zestimate`, `rentZestimate`, `taxAssessedValue`.
- **The home.** `beds`, `baths`, `livingAreaSqft`, `lotAreaSqft`, `homeType` (`SINGLE_FAMILY`, `CONDO`, `TOWNHOUSE`, `MULTI_FAMILY`, `APARTMENT`, `LOT`, `MANUFACTURED`...), `status`.
- **Market signals.** `daysOnZillow`, `zillowPriceChange` (e.g. `-15000`) and `zillowPriceChangeDate`.
- **Location.** `address`, `street`, `city`, `state`, `zipcode`, `latitude`, `longitude`.
- **Rentals.** Apartment communities come as one row (`isBuilding: true`) with `buildingName`, `units` (beds and price per floor plan), `minRent`, `maxRent` and `availableUnits`. `price` is the lowest rent (`null` when Zillow only says "Call" for price). They have no single bed count or size, so **Min/Max beds** and **sqft** filters leave them out.
- **Broker** (`brokerName`, the company), `imageUrl`, `photoCount`, `url`.
- **Reports** in the run's key-value store: `SEARCHES` (one line per city and ZIP searched: listings available, pages read, status), `MARKET_SUMMARY` and `HEALTH`.

### How to search

| You want | Set |
|---|---|
| Homes for sale in a city | **Cities, counties or ZIP codes** `Austin, TX` |
| One neighborhood-sized area | a ZIP code, `78704` |
| A whole county | `Travis County, TX` |
| Rentals | **For sale or for rent** `For rent` |
| 3+ beds under $500k, listed this week | **Min beds** `3`, **Max price** `500000`, **Max days on Zillow** `7` |
| Only houses and townhomes | **Home types** `Houses`, `Townhomes` |
| A daily new-listing / price-drop feed | **Only new or changed listings** on, schedule the Actor daily |
| Market stats per ZIP | **ZIP market summary** on |
| A Zillow page you already have open | paste it in **Zillow search URLs** (map and filter settings in the URL are ignored; set filters in the input) |

Filters are applied by the Actor while reading, so **you only pay for listings that match**.

### Output example

```json
{
  "recordType": "listing",
  "id": "zillow:55476612",
  "url": "https://www.zillow.com/homedetails/8323-Gentlewood-Ct-Houston-TX-77095/55476612_zpid/",
  "mode": "forSale",
  "status": "FOR_SALE",
  "homeType": "SINGLE_FAMILY",
  "price": 375000,
  "beds": 4,
  "baths": 3,
  "livingAreaSqft": 2992,
  "pricePerSqft": 125.33,
  "lotAreaSqft": 8751.2,
  "address": "8323 Gentlewood Ct, Houston, TX 77095",
  "zipcode": "77095",
  "latitude": 29.905025,
  "longitude": -95.65849,
  "zestimate": 368400,
  "rentZestimate": 2630,
  "taxAssessedValue": 365150,
  "daysOnZillow": 10,
  "zillowPriceChange": null,
  "brokerName": "Corcoran Prestige Realty",
  "changeType": "NEW",
  "previousPrice": null,
  "firstSeenAt": "2026-10-09T08:00:00Z"
}
```

Market summary row:

```json
{
  "recordType": "marketSummary",
  "zipcode": "78701",
  "city": "Austin",
  "mode": "forSale",
  "listings": 222,
  "medianPrice": 650000,
  "p25Price": 481249.25,
  "p75Price": 1230000,
  "medianPricePerSqft": 716.41,
  "medianDaysOnZillow": 94,
  "newLast7Days": 8,
  "priceCutShare": 0.4324,
  "medianPriceCut": 25000.5,
  "medianPriceToZestimate": 1.03,
  "medianGrossRentYield": 0.07
}
```

### Pricing

FREE-tier event rates checked on 11 October 2026 (FREE is the tier name, not a free run):

- `apify-actor-start`: $0.001 per event.
- `listing`: $0.0015 per event.
- `market-summary`: $0.01 per event.

Start event count depends on memory: one per GB, minimum one. Zero output can still incur start and applicable run costs. Row prices do not guarantee the total invoice. Store pricing is authoritative; rates and tier discounts may change.

Pay per event: a small fee per run start, per listing row (including `REMOVED` rows in monitoring mode) and per ZIP summary row. Summary rows are only produced when you turn them on, one per ZIP code with matching listings, and they do not count toward **Max listings**. Listings outside your filters, and unchanged listings in monitoring mode, are free.

### Good to know

- **Big areas take a while.** A city above 820 listings is read ZIP by ZIP at about one page per second (41 listings per page). Austin for sale is ~75 ZIP codes. Use **Max listings** to cap cost.
- **A single ZIP can still be above 820** (dense downtown rentals). Its report line then says `capped` and the first 820 are returned.
- **ZIP codes come from the [GeoNames](https://www.geonames.org) US postal code list** (CC BY 4.0). A city is covered by the ZIP codes whose postal city has that name, so a few homes Zillow puts inside the city limits but under a neighboring postal city may be missing; add those ZIP codes yourself if you need them.
- **Monitoring memory** is kept per set of searches and filters. Change them and the next run starts fresh (everything is `NEW` once).
- **`REMOVED`** means the home is no longer in that search (sold, rented or withdrawn). It is reported only when every search and ZIP was read to the end and the count did not change while reading. If more than half of the remembered homes vanish at once, or every search suddenly shows 0 results, nothing is marked removed in that run.
- **Recently sold homes are not supported**: Zillow does not show the sale price in search results.
- **Blocking.** Requests go out without a proxy. Only if Zillow blocks them does the Actor switch to the proxy in the input (US residential by default) and try a new IP at most three times. It never solves CAPTCHAs. If Zillow keeps blocking, the search is reported as `blocked` and the run stops.
- This Actor is independent and not affiliated with Zillow Group.

Found a bug or need a field? Open an issue on this page. We read every one and reply.

# Actor input Schema

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

One per line: 'Austin, TX', 'Travis County, TX' or a 5-digit ZIP code ('78701'). Cities and counties above Zillow's 820-result limit are split into their ZIP codes automatically.

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

Or paste Zillow city, county or ZIP search pages (e.g. https://www.zillow.com/austin-tx/rentals/). Map and filter settings in the URL are not used; set filters below. Pasted URLs are not split by ZIP.

## `mode` (type: `string`):

Applies to the locations above. Pasted URLs keep their own (…/rentals/ = for rent).

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

Stop after this many listing rows (you pay per row). Market summary rows are not counted.

## `minPrice` (type: `integer`):

For rent: monthly rent. Filters are applied by the scraper; listings that don't match are not charged.

## `maxPrice` (type: `integer`):

Leave empty for no limit.

## `minBeds` (type: `integer`):

Leave empty for any. Apartment buildings (rentals) have no single bed count and are left out when this is set.

## `maxBeds` (type: `integer`):

Leave empty for any.

## `minBaths` (type: `integer`):

Leave empty for any.

## `minSqft` (type: `integer`):

Leave empty for any.

## `maxSqft` (type: `integer`):

Leave empty for any.

## `maxDaysOnZillow` (type: `integer`):

Only listings this new (e.g. 7 = listed in the last week).

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

Leave empty for all.

## `onlyNewOrChanged` (type: `boolean`):

For scheduled runs: each run returns only listings that are NEW, had a PRICE_DROP or PRICE_UP since the last run with the same settings, and (when every search was read completely) REMOVED listings. The first run returns everything as NEW.

## `marketSummary` (type: `boolean`):

Add one row per ZIP code: listings, median and quartile price, median $/sqft, median days on Zillow, new in the last 7 days, share and median size of price cuts, price vs Zestimate and (for sale) gross rent yield. Uses every matching listing, also unchanged ones in monitoring mode.

## `splitByZip` (type: `boolean`):

Zillow shows at most 820 listings per search. When a city or county has more, it is searched ZIP by ZIP. Turn off to read only the first 820.

## `proxyConfiguration` (type: `object`):

Requests go out without a proxy first. Only if Zillow blocks them is this proxy used.

## Actor input object example

```json
{
  "locations": [
    "78701"
  ],
  "mode": "forSale",
  "maxItems": 20,
  "onlyNewOrChanged": false,
  "marketSummary": false,
  "splitByZip": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Listings table (JSON/CSV/Excel export).

## `marketSummary` (type: `string`):

One row per ZIP code (when enabled).

## `allFields` (type: `string`):

Every field, including units, photos and coordinates.

## `searches` (type: `string`):

For each search and ZIP: listings available, pages read, status.

## `health` (type: `string`):

Empty-field ratios, proxy use, failed searches.

# 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 = {
    "locations": [
        "78701"
    ],
    "mode": "forSale",
    "maxItems": 20,
    "onlyNewOrChanged": false,
    "marketSummary": false,
    "splitByZip": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("datasmithlab/zillow-property-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 = {
    "locations": ["78701"],
    "mode": "forSale",
    "maxItems": 20,
    "onlyNewOrChanged": False,
    "marketSummary": False,
    "splitByZip": True,
}

# Run the Actor and wait for it to finish
run = client.actor("datasmithlab/zillow-property-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 '{
  "locations": [
    "78701"
  ],
  "mode": "forSale",
  "maxItems": 20,
  "onlyNewOrChanged": false,
  "marketSummary": false,
  "splitByZip": true
}' |
apify call datasmithlab/zillow-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datasmithlab/zillow-property-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/ijQjYwIM4tk0yiFZb/builds/Kdh5wUfKcPdUpDv5I/openapi.json
