# Zillow Scraper - Listings, Zestimate, Sold & Price History (`topapi/zillow-scraper`) Actor

Scrape Zillow listings by city, ZIP, map area or search URL (for sale, for rent, sold) for $0.85 per 1,000: price, Zestimate, beds, baths, sqft, photos. Optional property details: price and tax history, schools, comps, full fact sheet. Goes past the 820-result cap. No login.

- **URL**: https://apify.com/topapi/zillow-scraper.md
- **Developed by:** [Top Api](https://apify.com/topapi) (community)
- **Categories:** Real estate, Automation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.85 / 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.

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

### What does Zillow Scraper do?

**Zillow Scraper** extracts Zillow listings from [zillow.com](https://www.zillow.com) and turns a city, ZIP code, neighborhood, county, map area or Zillow search URL into structured rows: one row per home for sale, for rent or recently sold, with price, address, beds, baths, square feet, Zestimate and photos. Built for real estate investors, analysts and proptech teams who need Zillow data in a spreadsheet or an API without copying listings by hand.

Zillow scraper · Zillow API alternative · Zillow data scraper · Zillow listings scraper · Zestimate scraper · Zillow sold homes scraper

<a href="https://console.apify.com/actors/0Pj0GUAnQ42ehYseC"><img src="https://api.apify.com/v2/key-value-stores/qNQ9zP0xaj2yxGeMY/records/zillow-scraper-source.png" alt="Zillow listings search page that Zillow Scraper turns into rows" style="width:70%"></a>

- **Every Zillow search tab:** for sale, for rent (including apartment buildings with their floor plans) and recently sold, with the same filters as zillow.com - price, beds, baths, square feet, lot, year built, HOA, days on Zillow, home types, keywords, pool, garage, views, open houses, price cuts.
- **Past Zillow's 820-result limit:** Zillow lists 20 pages of 41 homes per search. Zillow Scraper splits the map into smaller areas by itself, so a whole city comes back (5,557 Austin listings available; 1,000 delivered in 30 seconds on a test run).
- **Property details on demand:** description, year built, price history, tax history, nearby schools, nearby homes, comparable homes, HOA, parking, MLS number, parcel number, page views and saves, every photo in full size and the full fact sheet (about 25 to 90 facts per home, depending on the listing).
- **Zestimate history:** up to 10 years of monthly Zestimate values per home.
- **Look up single properties** by Zillow URL, ZPID or street address.
- **Monitoring:** schedule it daily and get only the listings you have not received before, optionally with price and status changes.
- **No login, cookies or Zillow API key.**
- **Export anywhere:** JSON, CSV, Excel, XML; schedules, webhooks, Make, Zapier, n8n, Google Sheets; the Apify API and MCP server.

### What data can you get from Zillow?

<table>
<tr>
<td>🆔 Zillow ID (<code>zpid</code>) and link</td>
<td>🏷️ Status: for sale, for rent, sold, pending, coming soon</td>
<td>💲 Price, sold price, price change</td>
</tr>
<tr>
<td>📍 Address, ZIP, county, coordinates</td>
<td>🛏️ Beds, baths, living area, lot size</td>
<td>🏠 Home type and listing type (MLS-listed, by owner, new construction, foreclosure, auction)</td>
</tr>
<tr>
<td>📈 Zestimate and rent Zestimate</td>
<td>🧾 Tax-assessed value, annual tax, tax rate</td>
<td>📅 Days on Zillow, date posted, date sold</td>
</tr>
<tr>
<td>📷 Photos (carousel, or every photo in full size)</td>
<td>🕒 Open house times</td>
<td>🏢 Apartment buildings: units, rents, specials</td>
</tr>
<tr>
<td>📜 Price history (<code>listingPriceHistory</code>)</td>
<td>🧮 Tax history (<code>listingTaxHistory</code>)</td>
<td>🏫 Nearby schools with ratings</td>
</tr>
<tr>
<td>🏘️ Nearby homes and comparable homes</td>
<td>📉 Zestimate history (10 years, monthly)</td>
<td>🔎 Fact sheet (about 25-90 facts): heating, cooling, parking, HOA, appliances, roof, zoning</td>
</tr>
<tr>
<td>🗂️ MLS number and parcel number</td>
<td>👀 Page views and saves on Zillow</td>
<td>📝 Full description and highlights</td>
</tr>
</table>

On a 1,000-listing Austin test run, price, address, coordinates, beds, baths, home type, days on Zillow and photos were filled on 100% of rows and living area on 97%. On a 100-listing run with property details, description, year built, price history, nearby schools, nearby homes, parcel number and MLS number were filled on 100% of rows, tax history on 87% and page views on 93%.

### How to scrape Zillow with Zillow Scraper

1. [Create a free Apify account](https://console.apify.com/sign-up) - $5 of monthly credit, no card needed.
2. Open [Zillow Scraper](https://apify.com/TopApi/zillow-scraper) and click **Try for free**.
3. Type a city, ZIP code or neighborhood into **Locations** (or paste a Zillow search URL), pick **For sale**, **For rent** or **Recently sold**, and set **Max results**.
4. Optional: add filters, and switch on **Include property details** for price history, tax history, schools and comps.
5. Click **Start**. Rows stream into the dataset as they are found.
6. Open the **Storage** tab and **Export** as JSON, CSV or Excel - or let a schedule run it for you.

### ⬇️ Input

| Parameter | Type | Description |
|---|---|---|
| **🔍 What to scrape** | | |
| `searchLocation` | List | Cities, ZIP codes, neighborhoods or counties: `"Austin, TX"`, `"78704"`, `"Travis County, TX"`. An exact street address returns that one property. |
| `listingStatus` | Select | `forSale` (default), `forRent` or `sold` - applies to Locations, ZIP codes and map areas. |
| `searchUrls` | List of `{"url": ...}` objects | Zillow search URLs, e.g. `[{"url": "https://www.zillow.com/austin-tx/sold/"}]`, or a URL with `?searchQueryState=`. The URL's filters and map area are kept. |
| `startUrls` | List of `{"url": ...}` objects | Zillow property URLs, e.g. `[{"url": "https://www.zillow.com/homedetails/29375136_zpid/"}]`. One row each, with property details. |
| `zipCodes` | List | US ZIP codes to search, e.g. `78704`. |
| `zpids` / `addresses` | List of strings | Zillow property IDs, e.g. `["29375136"]`, or addresses like `["123 Main St, City, ST 12345"]`. One row each, with property details. |
| `mapBounds` | Object | A map rectangle: `{"north": 30.29, "south": 30.25, "east": -97.72, "west": -97.76}`. |
| `latitude`, `longitude`, `distanceMiles` | Number | Search around a point; radius in miles (default 5). |
| `searchResultsDatasetId` | String | Dataset of an earlier Zillow run: every row with a zpid or property URL is fetched again with full property details. |
| **🎯 Filters** (applied by Zillow) | | |
| `sortBy` | Select | `relevance` (Zillow's default), `newest`, `priceLowToHigh`, `priceHighToLow`, `bedrooms`, `bathrooms`, `squareFeet`, `lotSize`. |
| `homeTypes` | Multi-select | `house`, `townhouse`, `multiFamily`, `condo`, `lot`, `apartment`, `manufactured`. Empty = all. |
| `minPrice` / `maxPrice` | Integer | USD; monthly rent when the status is For rent. |
| `minBeds` / `maxBeds` / `minBaths` | Number | Bedroom and bathroom bounds. |
| `minSqft` / `maxSqft` / `minLotSize` / `maxLotSize` | Integer | Living area and lot, square feet. |
| `minYearBuilt` / `maxYearBuilt` / `maxHoaFee` | Integer | Year built window; monthly HOA ceiling. |
| `daysOnZillow` | Select | Listed within (or, for sold, sold within) 1 / 7 / 14 / 30 / 90 days, 6 / 12 / 24 / 36 months. |
| `keywords` | String | Zillow's keyword filter, e.g. `"pool"`. |
| `listingTypes` | Multi-select | For sale: MLS-listed, by owner, new construction, foreclosures, auctions, coming soon, foreclosed, pre-foreclosures, pending & under contract, accepting backup offers. |
| `mustHave` / `views` / `parkingSpots` | Multi-select / Integer | Pool, A/C, waterfront, single story, garage, basement, 3D tour, open house, price cut; city / mountain / park / water view; minimum parking spots. |
| `customFilterState` | Object | Any other Zillow `filterState` key, merged last. |
| **✂️ Refine results** | | |
| `minDaysOnZillow` | Integer | Keep listings on Zillow at least this many days. |
| `withZestimateOnly` / `withPhotosOnly` | Boolean | Keep only rows with a Zestimate / with a photo. Default `false`. |
| **➕ Extra data** | | |
| `includeDetails` | Boolean | Property details for every home row - charged as **property-details** at $0.0016 per row that gets them. Apartment-building rows carry floor-plan rents but no property details, and are not charged for them. With `compact` on, the compact row keeps the details it was charged for (see `compact`). Default `false`. |
| `includeZestimateHistory` | Boolean | With details: monthly Zestimate for up to 10 years. No extra charge. |
| **🔁 Monitoring** | | |
| `monitorMode` | Boolean | Return only listings not delivered by previous runs. Pair with a daily schedule. The memory is saved during the run as well, so a run that Apify restarts or migrates still remembers everything it delivered. |
| `trackPriceChanges` | Boolean | Also return a known listing when its price or status changed (`monitorChange`, `previousPrice`). |
| `monitorStoreName` | String | Named key-value store for the memory. Default `zillow-scraper-monitor`. |
| **📦 Output** | | |
| `maxResults` | Integer | Default `100`; `0` = up to 100,000 rows, the most one run delivers. |
| `maxResultsPerSearch` | Integer | Limit per location / URL / ZIP. `0` = none. |
| `extractionMethod` | Select | `PAGINATION_WITH_ZOOM_IN` (default, full inventory), `PAGINATION` (up to ~820 per search, sorted), `MAP_MARKERS` (500 per call, one photo per row). |
| `compact` / `flatOutput` | Boolean | `compact`: core fields only, for AI assistants and LLMs - `zpid`, link, status, price, address, beds, baths, area, home type, Zestimates, days on Zillow, coordinates, photo and `searchInput`. A row that got property details also keeps what they were charged for: year built, description, price per square foot, annual tax, monthly HOA, parcel and MLS numbers, views and saves, price and tax history, schools, comparable homes, Zestimate history, every photo URL, `resoFacts` and `detailsSource`. `flatOutput`: dot-named columns for spreadsheets. |
| **⚙️ Advanced** | | |
| `proxyConfiguration` | Proxy | Leave as is: Apify's own connection first, Apify datacenter proxy sessions added by the actor. |
| `maxConcurrency` | Integer | Parallel connections, default 4. |

#### Input JSON

```json
{
  "searchLocation": ["Austin, TX", "78704"],
  "listingStatus": "forSale",
  "minBeds": 3,
  "maxPrice": 750000,
  "homeTypes": ["house", "townhouse"],
  "includeDetails": true,
  "maxResults": 200
}
```

#### Pick the listing status before anything else

Zillow keeps homes for sale, rentals and sold homes in separate searches, so `listingStatus` decides which one every location is searched in. **Do:** `"listingStatus": "sold"` with `"daysOnZillow": "90"` for sales of the last 90 days · **Don't:** search for sale and filter by "sold" afterwards - sold homes are not in that search.

#### Paste a Zillow search URL to keep every filter you set on the map

Draw an area or set filters on zillow.com, copy the address bar and put it in `searchUrls`. Zillow Scraper keeps the URL's filters and map area as they are; the filter inputs apply to Locations, ZIP codes and map areas only.

In the input form you paste the URLs one per line. In JSON or an API call, `searchUrls` and `startUrls` are lists of objects with a `url` key (a plain string is rejected by Apify before the run starts):

```json
{
  "searchUrls": [{ "url": "https://www.zillow.com/austin-tx/sold/" }],
  "startUrls": [{ "url": "https://www.zillow.com/homedetails/29375136_zpid/" }],
  "zpids": ["29477119"]
}
```

#### Use the map methods to go past 820 results

Zillow shows at most 20 pages of 41 homes per search. With the default `PAGINATION_WITH_ZOOM_IN`, a search that has more homes than that is split into four smaller map areas, again and again, until every area fits; duplicates are removed. `MAP_MARKERS` reads 500 homes per call the same way and is the fastest route to a full inventory, with one photo per row instead of the photo carousel.

#### Turn on property details only when you need them

Search rows already carry price, address, beds, baths, area, home type, days on Zillow, tax-assessed value and photos. `includeDetails` opens each property page for the history, schools, comps and facts - it takes about two seconds per home and is charged per row that gets it.

### ⬆️ Output

Every listing becomes one dataset item. Here is the table view of a run for ZIP `78704` with property details on:

<a href="https://console.apify.com/actors/0Pj0GUAnQ42ehYseC"><img src="https://api.apify.com/v2/key-value-stores/qNQ9zP0xaj2yxGeMY/records/zillow-scraper-output.png" alt="Zillow Scraper output dataset with Zillow listings and property details" style="width:70%"></a>

A search row as JSON (shortened):

```json
{
  "zpid": "29575637",
  "propertyUrl": "https://www.zillow.com/homedetails/8302-Racine-Trl-Austin-TX-78717/29575637_zpid/",
  "listingStatus": "forSale",
  "listingPrice": { "amount": 389900, "currency": "USD", "formatted": "$389,900" },
  "listingAddress": { "street": "8302 Racine Trl", "city": "Austin", "state": "TX", "zipCode": "78717", "full": "8302 Racine Trl, Austin, TX 78717" },
  "coordinates": { "latitude": 30.491026, "longitude": -97.74046 },
  "homeType": "SINGLE_FAMILY",
  "bedrooms": 4,
  "bathrooms": 2,
  "livingArea": 1515,
  "lotArea": { "value": 5989.5, "unit": "sqft" },
  "daysOnZillow": 9,
  "taxAssessedValue": 422216,
  "photoCount": 25,
  "searchInput": "Austin, TX"
}
```

A row with property details adds (shortened; zpid 29477119, 1509 Grayford Dr, listed at $1,895,000):

```json
{
  "yearBuilt": 1964,
  "pricePerSquareFoot": 682,
  "taxAnnualAmount": 20025,
  "parcelId": "308059",
  "mls": { "id": "2477927", "name": "Unlock MLS" },
  "pageViewCount": 625,
  "favoriteCount": 74,
  "listingPriceHistory": [{ "date": "2026-10-07", "event": "Listed for sale", "price": 1895000, "source": "Unlock MLS", "sourceType": "mls" }],
  "listingTaxHistory": [{ "year": 2025, "taxPaid": 22096.26, "value": 1269986 }],
  "nearbySchools": [{ "name": "Joslin Elementary School", "distance": 0.6, "grades": "PK-5", "type": "Public", "isAssigned": true }],
  "nearbyProperties": ["... 8 nearby homes"],
  "comparableHomes": ["... 5 comparable homes"]
}
```

#### Fields

| Field | Type | What it is | Fill on test run |
|---|---|---|---|
| `zpid`, `propertyUrl` | string | Zillow property ID and page | 100% |
| `listingPrice` | object | Asking price or rent `{amount, currency, formatted}` | 100% (for sale) |
| `listingSoldPrice`, `dateSold` | object, string | Sale price where Zillow publishes it; sale date | date 100% (sold) |
| `listingAddress`, `coordinates` | object | Street, city, state, ZIP, county; latitude / longitude | 100% |
| `bedrooms`, `bathrooms`, `livingArea` | number | Size of the home | 100% / 100% / 97% |
| `homeType`, `listingType` | string, object | Single family, condo...; MLS-listed / by owner / new / foreclosure / auction flags | 100% |
| `daysOnZillow`, `priceChange` | number | Time on market; last price change | 100% / 49% |
| `zestimate`, `rentZestimate` | number | Shown by Zillow on a minority of active listings, most sold homes | 20% / 22% (for sale) |
| `taxAssessedValue`, `lotArea` | number, object | Assessed value; lot size | 88% / 98% |
| `mainImage`, `listingPhotos` | string, array | Photos | 100% |
| `description`, `yearBuilt`, `pricePerSquareFoot` | details | Listing text, year built, price per square foot. Phone numbers, e-mail addresses, licence numbers, links to non-tour websites, and names in contact phrasing (after "call", "contact" or "text", beside a role title such as Realtor, or beside a phone number or e-mail) in the text read `[contact removed]` | 100% |
| `listingPriceHistory`, `listingTaxHistory` | details | Price events with their data source (MLS, owner, public record, Zillow); yearly tax and assessed value | 100% / 87% |
| `nearbySchools`, `nearbyProperties`, `comparableHomes` | details | Schools with rating and distance; nearby homes; Zestimate comps | 100% / 100% / 90% |
| `zestimateHistory` | details | Monthly Zestimate, up to 10 years | 88% |
| `hoa`, `monthlyHoaFee`, `parking`, `propertyFeatures`, `resoFacts` | details | Association: `hoa.fee` as Zillow states it, per `hoa.feeFrequency` (Monthly, Quarterly, Annually); `monthlyHoaFee` = that fee per month (Zillow's own figure, or the stated fee divided by its period; null when the listing only says it has an HOA fee, with no amount). Parking, and the full fact sheet (about 25-90 facts, depending on the listing) | HOA 38%, others 100% |
| `mls`, `parcelId`, `countyFIPS`, `datePosted` | details | Listing and record identifiers | 100% / 100% / 87% / 100% |
| `pageViewCount`, `favoriteCount` | details | Views and saves on Zillow (active listings) | 93% |
| `virtualTourUrl` | details | 3D or video tour on a tour host (Zillow, Matterport, YouTube, Vimeo, Property Panorama and similar); null when the only tour is on another website | 40% |

Fill figures: search fields from a 1,000-row Austin run; detail fields from a 100-row run in ZIP 78704 (for-sale homes); `virtualTourUrl` from 126 properties across the Austin, Denver, Miami and Seattle test runs.

### How can I use Zillow data?

- 🏘️ **Real estate investors** - pull every listing in a ZIP with price, size and days on Zillow, sort by price per square foot and find homes sitting longest on the market.
- 📊 **Market analysts** - track inventory, price cuts and sold prices by neighborhood week over week with a daily schedule.
- 🧾 **Appraisers and lenders** - pull price history, tax history and Zillow's comparable homes for a list of addresses.
- 🏢 **Rental operators** - collect rents, floor plans and leasing specials of apartment buildings in a city.
- 🤖 **AI and proptech teams** - feed compact rows to an LLM or a valuation model through the API or MCP.
- 🏗️ **Builders and developers** - find lots and new-construction listings with lot size, zoning and schools.

### How much does it cost to scrape Zillow?

Zillow Scraper is pay-per-result: **$0.85 per 1,000 listings** (`listing`, $0.00085 each), no start fee. **Property details** add **$1.60 per 1,000** (`property-details`, $0.0016 per row that gets them). A property looked up by URL, ZPID or address is one listing plus its details: $0.00245.

| Rows | Listings only | With property details |
|---:|---:|---:|
| 10 | $0.0085 | $0.0245 |
| 100 | $0.085 | $0.245 |
| 1,000 | $0.85 | $2.45 |
| 10,000 | $8.50 | $24.50 |

Apify's platform usage is included. Measured: 41 listings in 6 seconds, 1,000 listings in 31 seconds, 100 listings with property details and Zestimate history in about 3.5 minutes, all on 256 MB.

### Integrations, API, scheduling & MCP

- **Schedules:** run Zillow Scraper daily or weekly from the **Schedules** tab; with `monitorMode` each run returns only new listings.
- **Webhooks:** fire a URL when a run finishes - push listings to your CRM, Slack or a sheet.
- **No-code:** Make, Zapier, n8n, Google Sheets, Airtable, Slack via [Apify integrations](https://docs.apify.com/integrations).
- **API:** call it from Node.js or Python with `apify-client` - code on the [API tab](https://apify.com/TopApi/zillow-scraper/api/python) and the [Apify API reference](https://docs.apify.com/api/v2).
- **MCP / AI assistants:** connect Claude, Cursor or any MCP client through the [MCP tab](https://apify.com/TopApi/zillow-scraper/api/mcp) and ask for Zillow listings in plain language.

### More scrapers from TopApi

<table>
<tr>
<td>⭐ <a href="https://apify.com/TopApi/google-maps-reviews-scraper">Google Maps Reviews Scraper</a> - reviews of local businesses around a property</td>
<td>🔎 <a href="https://apify.com/TopApi/facebook-search-posts-scraper">Facebook Search Posts Scraper</a> - local posts by keyword, date and location</td>
<td>💼 <a href="https://apify.com/TopApi/indeed-jobs-scraper">Indeed Jobs Scraper</a> - hiring and salaries in a housing market</td>
</tr>
<tr>
<td>🎵 <a href="https://apify.com/TopApi/tiktok-scraper">TikTok Scraper</a> - home-tour and neighborhood videos by hashtag</td>
<td>▶️ <a href="https://apify.com/TopApi/youtube-shorts-scraper">YouTube Shorts Scraper</a> - real estate Shorts by keyword or hashtag</td>
<td>🚗 <a href="https://apify.com/TopApi/autoscout24-listings-scraper">AutoScout24 Listings Scraper</a> - car listings with prices and specs</td>
</tr>
<tr>
<td colspan="3">🧭 <a href="https://apify.com/TopApi">All TopApi actors</a></td>
</tr>
</table>

### Limits & empty runs

- **Results per search:** Zillow serves 20 pages of 41 homes; the default method splits the map to go further. A city of 5,557 listings returned 1,000 rows in 30 seconds with 2 map splits.
- **Speed:** each connection is paced to about one request per second, the rate Zillow serves without refusing; four connections run in parallel. A refused connection pauses and resumes, or is replaced.
- **Empty dataset:** the run's status message says why - Zillow has no listings for these filters, every listing was removed by your refine filters, monitoring found nothing new, or Zillow refused every connection. There is no start fee, so a run that delivers no rows has no charges.
- **Restarts:** if Apify migrates or restarts a run, the rows already in the dataset count toward `maxResults` and the per-search limit, are never delivered or charged twice, and stay in the monitor memory.
- **Apartment buildings:** building rows (`cardType` `apartmentBuilding`, no ZPID) carry the building's floor-plan rents, available units and specials, but no property details; `includeDetails` adds details to home rows only and charges only for rows that get them.
- **Not available:** sold prices in states where Zillow does not publish them (Texas is one); Zestimates that Zillow hides on many active listings.
- **No personal contact details:** rows carry property data only. In the listing text, phone numbers, e-mail addresses, licence numbers and links to websites other than tour hosts are replaced by `[contact removed]`, and so are names in contact phrasing ("call Jane Smith", "Jane Smith, Realtor", "Jane Smith 512-...", "Jane Smith of <firm>"). The text is matched by patterns, so a name written in an unusual way can remain. A tour hosted on another website is left out (`virtualTourUrl` null). An association's own phone number is kept (`hoa.associationPhone`, and the same number in the association entries of `resoFacts`).

### FAQ

#### How many listings can Zillow Scraper collect in one run?

As many as Zillow has for the search, up to 100,000 rows per run: the default method splits the map past Zillow's 820-result page limit. Set `maxResults` to `0` for up to 100,000 rows, or a smaller number to cap the bill.

#### Is there a Zillow API?

Zillow offers several APIs, but they need an approved API key and come with usage limits. Zillow Scraper reads the same public pages a visitor sees and returns them as JSON, so you can use it like a Zillow API through Apify, with no key.

#### Can I run Zillow Scraper on a schedule to get new listings automatically?

Yes. Save your input as a task, open **Schedules**, pick the cadence and switch on `monitorMode`: each run then returns only listings not delivered before. Add `trackPriceChanges` to also get listings whose price or status changed.

#### How do I get price history, tax history and schools with Zillow Scraper?

Switch on `includeDetails`. Every home row then carries `listingPriceHistory`, `listingTaxHistory`, `nearbySchools`, `nearbyProperties`, `comparableHomes`, the full fact sheet and every photo. With `compact` on, the compact row keeps the histories, schools, comparable homes, fact sheet and photo URLs. Add `includeZestimateHistory` for 10 years of monthly Zestimates.

#### Can I scrape Zillow rentals and sold homes with Zillow Scraper?

Yes. Set `listingStatus` to `forRent` or `sold`. Rentals include apartment buildings with their floor-plan rents and specials; sold rows carry the sale date and, where Zillow publishes it, the sale price.

#### Can I integrate Zillow Scraper with other apps?

Yes - Make, Zapier, n8n, Google Sheets, Slack and more via [Apify integrations](https://docs.apify.com/integrations), or use [webhooks](https://docs.apify.com/integrations/webhooks) to trigger an action when a run finishes.

#### Can I use Zillow Scraper with the Apify API or in Python?

Yes. Use `apify-client` for [Node.js](https://apify.com/TopApi/zillow-scraper/api/javascript) or [Python](https://apify.com/TopApi/zillow-scraper/api/python); the API tab has ready-to-paste code.

#### Can I use Zillow Scraper through an MCP server?

Yes. Open the [MCP tab](https://apify.com/TopApi/zillow-scraper/api/mcp), connect your MCP client (Claude Desktop, Cursor and others) and ask for Zillow listings in plain language. Turn on `compact` for rows sized for AI assistants.

#### Do I need a Zillow account, cookies or an API key?

No. Zillow Scraper reads only what Zillow shows publicly; you pass locations, URLs, ZPIDs or addresses and nothing else.

#### Why did my Zillow Scraper run return no results?

Most often the filters match no homes (check the same filters on zillow.com), the location was not recognized (try "City, ST" or a ZIP code), or monitoring found nothing new since the last run. The status message and the `RUN_SUMMARY` record name the cause.

#### Is it legal to scrape Zillow data?

Zillow Scraper extracts publicly available property data such as prices, addresses and listing details. Results can still contain personal information, which is protected by regulations such as GDPR; scrape personal data only with a legitimate reason, and consult a lawyer if unsure. See Apify's post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

#### Your feedback

We keep improving Zillow Scraper. Found a bug or missing a field? Open an issue on the [Issues tab](https://apify.com/TopApi/zillow-scraper/issues/open).

# Actor input Schema

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

Cities, ZIP codes, neighborhoods or counties, one per line, e.g. "Austin, TX", "78704", "Travis County, TX". An exact street address returns that one property.

## `listingStatus` (type: `string`):

Which Zillow tab to search for Locations, ZIP codes and map areas. Search URLs keep the status set in the URL.

## `searchUrls` (type: `array`):

Any zillow.com search page, e.g. https://www.zillow.com/austin-tx/sold/ or a URL with ?searchQueryState=... The filters and map area in the URL are kept as they are. In JSON / API input each URL is an object: \[{"url": "https://www.zillow.com/austin-tx/sold/"}].

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

Zillow property pages (/homedetails/...\_zpid/). Each becomes one row with full property details, e.g. https://www.zillow.com/homedetails/29375136_zpid/. In JSON / API input each URL is an object: \[{"url": "https://www.zillow.com/homedetails/29375136_zpid/"}].

## `zipCodes` (type: `array`):

US ZIP codes to search with the status and filters above, e.g. 78704, 90210. Same as typing them into Locations.

## `zpids` (type: `array`):

Zillow property IDs, e.g. 29375136. Each becomes one row with full property details.

## `addresses` (type: `array`):

Street addresses in the form "123 Main St, City, ST 12345". Zillow resolves each to its property; you get one row with full property details.

## `mapBounds` (type: `object`):

Search a rectangle on the map: {"north": 30.29, "south": 30.25, "east": -97.72, "west": -97.76}. Uses the status and filters above.

## `latitude` (type: `number`):

Search around a point: latitude, e.g. 30.2672. Needs Longitude; the radius is Distance (miles).

## `longitude` (type: `number`):

Search around a point: longitude, e.g. -97.7431.

## `distanceMiles` (type: `integer`):

Radius around Latitude / Longitude, in miles. Default 5.

## `searchResultsDatasetId` (type: `string`):

ID of a dataset from an earlier Zillow run (this actor or another). Every row with a zpid or property URL is fetched again with full property details.

## `sortBy` (type: `string`):

Order Zillow returns listings in. With a result limit, this decides which listings you get.

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

Only these home types. Empty = all types.

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

Lowest price in USD (monthly rent when Listing status is For rent), e.g. 300000.

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

Highest price in USD (monthly rent when Listing status is For rent), e.g. 750000.

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

At least this many bedrooms, e.g. 3.

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

At most this many bedrooms.

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

At least this many bathrooms, e.g. 2 or 1.5.

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

Smallest living area in square feet, e.g. 1500.

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

Largest living area in square feet.

## `minLotSize` (type: `integer`):

Smallest lot in square feet (1 acre = 43,560), e.g. 5000.

## `maxLotSize` (type: `integer`):

Largest lot in square feet.

## `minYearBuilt` (type: `integer`):

Earliest year built, e.g. 1990.

## `maxYearBuilt` (type: `integer`):

Latest year built, e.g. 2020.

## `maxHoaFee` (type: `integer`):

Highest monthly HOA fee in USD, e.g. 200. Zillow keeps homes with no HOA data.

## `daysOnZillow` (type: `string`):

Listed within this window (for sale / rent), or sold within it when Listing status is Recently sold. Pairs well with a daily schedule.

## `keywords` (type: `string`):

Zillow's keyword filter on the listing text, e.g. "pool" or "mother-in-law".

## `listingTypes` (type: `array`):

For sale only. Empty = Zillow's default (MLS-listed, by owner, new construction, foreclosure, auction, coming soon). Pick to narrow or to add pending / pre-foreclosure.

## `mustHave` (type: `array`):

Zillow's amenity and listing filters, e.g. Pool + Garage. Empty = no requirement.

## `views` (type: `array`):

Only homes Zillow lists with this view.

## `parkingSpots` (type: `integer`):

At least this many parking spots, e.g. 2.

## `customFilterState` (type: `object`):

Any other Zillow filterState keys, merged last, e.g. {"isTownhouse": {"value": false}}. Copy them from a Zillow search URL's searchQueryState.

## `minDaysOnZillow` (type: `integer`):

Keep only listings on Zillow at least this many days, e.g. 60 for stale listings.

## `withZestimateOnly` (type: `boolean`):

Keep only listings that show a Zestimate on the search card.

## `withPhotosOnly` (type: `boolean`):

Keep only listings that have at least one photo.

## `includeDetails` (type: `boolean`):

Adds description, year built, price and tax history, schools, nearby homes, comparables, HOA, parking, MLS id, parcel number, all photos and the full fact sheet (about 25-90 facts, depending on the listing). $0.0016 per listing that gets them. Apartment-building rows (no ZPID) carry floor-plan rents, not property details. With Compact output on, the compact row keeps the details it was charged for.

## `includeZestimateHistory` (type: `boolean`):

With property details: adds up to 10 years of monthly Zestimate values per home. No extra charge.

## `monitorMode` (type: `boolean`):

Remember delivered listings per search (named key-value store) and skip them next time. Pairs with a daily schedule. The memory is also saved during the run, so a restarted run keeps it.

## `trackPriceChanges` (type: `boolean`):

With monitoring: also return a listing seen before when its price or status changed, with monitorChange and previousPrice.

## `monitorStoreName` (type: `string`):

Named key-value store that holds the memory. Use a different name per independent schedule.

## `maxResults` (type: `integer`):

Total rows for the run. 0 = up to 100,000 rows (the most one run delivers). Zillow shows 41 per page and up to 820 per search; the map method below goes past that.

## `maxResultsPerSearch` (type: `integer`):

Limit per location / URL / ZIP when you pass several. 0 = no per-search limit.

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

Zillow lists at most 20 pages (820 homes) per search. The two map options split the area into smaller boxes to reach every listing.

## `compact` (type: `boolean`):

Core fields only (price, address, beds, baths, area, Zestimate, link, search input), flat - sized for AI assistants and MCP. A row that got property details also keeps what they were charged for: year built, description, price and tax history, schools, comparable homes, Zestimate history, photo URLs and the fact sheet.

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

Nested objects become dot-named columns (listingAddress.city, listingPrice.amount) for spreadsheets.

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

Leave as is: the actor starts on Apify's own connection and adds Apify datacenter proxy sessions by itself. Choosing a proxy here replaces both.

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

Connections working at once; each is paced to about one request per second. Default 4.

## Actor input object example

```json
{
  "searchLocation": [
    "Austin, TX"
  ],
  "listingStatus": "forSale",
  "sortBy": "relevance",
  "daysOnZillow": "",
  "withZestimateOnly": false,
  "withPhotosOnly": false,
  "includeDetails": false,
  "includeZestimateHistory": false,
  "monitorMode": false,
  "trackPriceChanges": false,
  "monitorStoreName": "zillow-scraper-monitor",
  "maxResults": 41,
  "maxResultsPerSearch": 0,
  "extractionMethod": "PAGINATION_WITH_ZOOM_IN",
  "compact": false,
  "flatOutput": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxConcurrency": 4
}
```

# Actor output Schema

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

The dataset of Zillow listings (one item per listing or property).

## `summary` (type: `string`):

Per-search counts (Zillow's total, calls, read, filtered, seen before, delivered), property lookups not found or unreachable, and connection stats.

# 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": [
        "Austin, TX"
    ],
    "listingStatus": "forSale",
    "maxResults": 41
};

// Run the Actor and wait for it to finish
const run = await client.actor("topapi/zillow-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": ["Austin, TX"],
    "listingStatus": "forSale",
    "maxResults": 41,
}

# Run the Actor and wait for it to finish
run = client.actor("topapi/zillow-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": [
    "Austin, TX"
  ],
  "listingStatus": "forSale",
  "maxResults": 41
}' |
apify call topapi/zillow-scraper --silent --output-dataset

```

## MCP server setup

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