# Zillow Scraper API: Property, Search & Zestimate (`morgan-studio/zillow-property-scraper`) Actor

Zillow scraper API: get Zillow property data by URL, zpid, search URL or location, and export search results to JSON, CSV or Excel. Price, Zestimate, rent Zestimate, beds, baths, sqft, lot, year built, price history, photos, MLS and broker. For sale, rent and sold.

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

## Pricing

from $2.40 / 1,000 properties

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

## Zillow Scraper API: Property & Search Data

### What is Zillow Scraper API?

**Zillow Scraper API** is a **Zillow scraper** you call like an API: it gets **Zillow property data** from property URLs, zpids, Zillow search URLs or plain locations. For every home you get the price, status (for sale, for rent, recently sold, off market), address and coordinates, beds, baths, living area, lot size, year built, price per square foot, **Zestimate and rent Zestimate**, HOA fee, last sale price and date, days on Zillow, page views and saves, the listing description, full-size photo URLs, price history where Zillow shows it, the MLS and listing brokerage.

Searches work two ways: paste any Zillow search URL with the filters you set in your browser (price, beds, home type, rentals, sold), or type a location (`Phoenix, AZ`, a ZIP code) and pick for sale, for rent or recently sold. Search results come back as listing cards; switch on **Fetch full property details** to get the full property record for each one.

You pay per record delivered: **$0.0024 per property** ($2.40 per 1,000) and **$0.001 per search result** ($1 per 1,000), platform usage included. **Properties that are not found, blocked requests and invalid inputs are reported in the dataset and free.**

The easiest way to try it: paste a Zillow property link into **Property URLs or zpids** and press **Start**.

### What data can you get from Zillow?

| Field | Example |
|---|---|
| `zpid`, `url` | `49125964`, `https://www.zillow.com/homedetails/6220-2nd-Ave-NW-Seattle-WA-98107/49125964_zpid/` |
| `homeStatus` | `FOR_SALE`, `FOR_RENT`, `RECENTLY_SOLD`, `OFF_MARKET`, ... |
| `price`, `currency` | 1325000, USD |
| `streetAddress`, `city`, `state`, `zipcode` | 6220 2nd Avenue NW, Seattle, WA, 98107 |
| `latitude`, `longitude` | 47.67502, -122.35918 |
| `homeType` | `SINGLE_FAMILY`, `CONDO`, `TOWNHOUSE`, `MULTI_FAMILY`, ... |
| `bedrooms`, `bathrooms` | 5, 4 |
| `livingArea`, `livingAreaUnits` | 3380, sqft |
| `lotAreaValue`, `lotAreaUnits` | 4399.56, Square Feet |
| `yearBuilt`, `pricePerSquareFoot` | 1918, 392 |
| `zestimate`, `rentZestimate` | Zillow's value and rent estimates (null when Zillow does not show one) |
| `monthlyHoaFee`, `propertyTaxRate` | 135, 0.55 |
| `lastSoldPrice`, `dateSold` | 265000, 2012-01-27 |
| `daysOnZillow`, `datePosted`, `pageViewCount`, `favoriteCount` | 1, 2026-10-13, 150, 26 |
| `priceChange`, `priceChangeDate` | the latest price change and its date, when there is one |
| `description` | the listing description |
| `photoCount`, `photos` | 40, full-size photo URLs (1536 px) |
| `priceHistory` | `[{ "date": "2026-10-07", "price": 1325000 }]`, when the page shows it |
| `facts` | full and half baths, lot size text, property subtype, parking, HOA total, heating, cooling, appliances, flooring, stories (when listed) |
| `openHouseSchedule` | `[{ startTime, endTime }]` |
| `mlsId`, `mlsName`, `brokerageName`, `listingAgentName`, `listingStatusDetail`, `listingLastUpdated` | listing attribution as shown on Zillow |
| `fetchStatus`, `error` | `ok`, `null` |

Example property record (photos, history and description shortened):

```json
{
  "recordType": "property",
  "zpid": "49125964",
  "url": "https://www.zillow.com/homedetails/6220-2nd-Ave-NW-Seattle-WA-98107/49125964_zpid/",
  "homeStatus": "FOR_SALE",
  "price": 1325000,
  "currency": "USD",
  "streetAddress": "6220 2nd Avenue NW",
  "city": "Seattle",
  "state": "WA",
  "zipcode": "98107",
  "latitude": 47.67502,
  "longitude": -122.35918,
  "homeType": "SINGLE_FAMILY",
  "bedrooms": 5,
  "bathrooms": 4,
  "livingArea": 3380,
  "livingAreaUnits": "sqft",
  "lotAreaValue": 4399.56,
  "lotAreaUnits": "Square Feet",
  "yearBuilt": 1918,
  "pricePerSquareFoot": 392,
  "zestimate": null,
  "rentZestimate": 6058,
  "description": "Perched above a favorite Phinney Ridge block, this beloved Craftsman has been home to the same owners for 46 years...",
  "photoCount": 40,
  "photos": ["https://photos.zillowstatic.com/fp/c51f5d4b78c5d599d3e1c2b25b7f0621-cc_ft_1536.jpg"],
  "priceHistory": [{ "date": "2026-10-07", "price": 1325000 }],
  "facts": { "bathroomsFull": 2, "bathroomsHalf": 1, "lotSize": "4,399 sqft", "propertySubType": ["Single Family Residence"] },
  "mlsId": "2591886",
  "mlsName": "NWMLS as distributed by MLS GRID",
  "brokerageName": "Windermere Mercer Island",
  "listingStatusDetail": "Active",
  "fetchStatus": "ok",
  "error": null
}
```

Example search result (a recently sold home from a Denver search):

```json
{
  "recordType": "search-result",
  "zpid": "13056017",
  "url": "https://www.zillow.com/homedetails/1995-S-Newport-St-Denver-CO-80224/13056017_zpid/",
  "homeStatus": "RECENTLY_SOLD",
  "price": 730000,
  "streetAddress": "1995 S Newport Street",
  "city": "Denver",
  "state": "CO",
  "zipcode": "80224",
  "bedrooms": 4,
  "bathrooms": 4,
  "livingArea": 2726,
  "zestimate": 705900,
  "rentZestimate": 3961,
  "taxAssessedValue": 667100,
  "dateSold": "2026-10-14",
  "brokerName": "LIV Sotheby's International Realty",
  "searchUrl": "https://www.zillow.com/denver-co/sold/",
  "position": 1,
  "fetchStatus": "ok"
}
```

Rental searches also return apartment buildings as one card: `isBuilding: true`, `buildingId`, `buildingName`, `minRent`, `maxRent`, `availableUnits` and a `units` list with price and beds.

### How to scrape Zillow property data

1. Add property URLs or zpids, and/or search URLs, and/or locations.
2. For locations, pick **For sale**, **For rent** or **Recently sold**.
3. Set **Max results per search** (default 100).
4. Optional: switch on **Fetch full property details** to turn every search result into a full property record.
5. Press **Start**, then download the dataset as JSON, CSV or Excel, or read it through the Apify API.

#### Input example

```json
{
  "propertyUrls": [
    "https://www.zillow.com/homedetails/2734-E-Vista-Dr-Phoenix-AZ-85032/8011097_zpid/",
    "1772396"
  ],
  "searchUrls": ["https://www.zillow.com/denver-co/sold/"],
  "locations": ["Seattle, WA", "37206"],
  "listingType": "for_sale",
  "maxResultsPerSearch": 100,
  "fetchDetails": false
}
```

### Export Zillow search results to CSV or Excel

Paste a Zillow search URL with your filters, or type a city or ZIP code, then download the dataset from the Output tab as CSV, Excel or JSON, or from `https://api.apify.com/v2/datasets/<datasetId>/items?format=xlsx`. Each listing is one row with price, address, beds, baths, living area, Zestimate and status.

### A Zillow API you can use today

Zillow's own data APIs are for approved partners. This actor reads Zillow's public pages and you call it over the Apify API, with results in the same request:

```bash
curl -X POST "https://api.apify.com/v2/acts/morgan-studio~zillow-property-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"propertyUrls": ["1772396"]}'
```

### Zillow scraper in Python

With the `apify-client` package:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("morgan-studio/zillow-property-scraper").call(
    run_input={"locations": ["Denver, CO"], "listingType": "sold", "maxResultsPerSearch": 50}
)
for home in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(home["streetAddress"], home["price"], home["zestimate"])
```

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

Pay per event, platform usage included:

| Event | Price | When |
|---|---|---|
| Property | $0.0024 | one full property record delivered (`fetchStatus: ok`) |
| Search result | $0.001 | one listing card from a search |
| Actor start | $0.00005 | once per run |

1,000 full property records cost $2.40. 1,000 search results cost $1. Not-found properties, blocked requests and invalid inputs are written to the dataset with their `fetchStatus` and cost nothing. A run stops cleanly when it reaches the maximum cost you set for it.

### Limits and good to know

- Data is what Zillow shows on its public pages, logged out. Fields Zillow does not show for a home come back `null` (for example many active listings have no Zestimate, and sold homes often have no description).
- `priceHistory` is filled when Zillow renders it into the page; in our tests about 4 in 10 property pages carried it.
- Zillow shows at most about 20 pages (about 800 listings) per search. For more, split the search by ZIP code or price band.
- Zillow uses bot protection. The actor fetches pages directly first and retries through Apify Proxy on fresh sessions when Zillow answers with a bot check. Keep Apify Proxy on.
- US listings only (Zillow's coverage).
- No login, no cookies, no browser.

### Status values

`ok` (charged), `not-found` (the property or search does not exist or has no listing data), `blocked` (Zillow's bot check on every try), `error` (network or unexpected HTTP), `invalid-input` (not a Zillow property URL, zpid or search URL), `no-results` (a search with no listings). Only `ok` is charged.

### Is it legal to scrape Zillow?

This actor reads public pages that anyone can open without an account, and returns facts about properties. It does not log in or collect private data. Zillow's Terms of Use restrict automated access; check that your use fits them and the laws where you work. Photos belong to their owners; the actor returns links, not copies.

### FAQ

**Is there a free Zillow API?** Not a public one for listing data. This actor is pay per record: $0.0024 per property and $0.001 per search result, and failed items are free.

**How do I export Zillow search results to Excel?** Run a search URL or a location, then download the dataset as Excel (`format=xlsx`) or CSV.

**Can I use it from Python?** Yes, with `apify-client` as shown above, or with plain HTTP to the Apify API.

**Does it get sold homes and rentals?** Yes. Set **Listing type** to `sold` or `for_rent` for a location, or paste a Zillow search URL with those filters.

### Support

Questions or a broken field: open an issue on the actor's Issues tab and include the run id.

### Ready-made examples

Each one opens with its input filled in; copy it to your account and run.

- [Export Zillow search results to CSV](https://apify.com/morgan-studio/zillow-property-scraper/examples/export-zillow-search-results-to-csv)
- [Zillow listings to Excel by ZIP code](https://apify.com/morgan-studio/zillow-property-scraper/examples/zillow-listings-to-excel-by-zip-code)
- [Zillow property data by URL or zpid](https://apify.com/morgan-studio/zillow-property-scraper/examples/zillow-property-data-by-url-or-zpid)
- [Zillow rentals by city: rent prices and listings](https://apify.com/morgan-studio/zillow-property-scraper/examples/zillow-rentals-by-city-rent-prices)
- [Zillow sold homes by ZIP code](https://apify.com/morgan-studio/zillow-property-scraper/examples/zillow-sold-homes-by-zip-code)

### More actors from the same developer

- [Amazon Product Scraper & Price API (ASIN, Keyword)](https://apify.com/morgan-studio/amazon-product-price-scraper)
- [App Store Reviews Scraper: Apple & Google Play API](https://apify.com/morgan-studio/app-store-reviews-scraper)
- [YouTube Transcript API & Scraper with Timestamps](https://apify.com/morgan-studio/youtube-transcript-scraper)

### Changelog

- **2026-10-15**: README and listing reworded for search; new sections on API use, scheduling and export; links to the ready-made examples. No change to the scraper or the prices.
- 0.1: first release. Property URLs and zpids, search URLs, locations (for sale, for rent, sold), optional full details for search results, rental buildings, direct-first fetching with proxy fallback.

# Actor input Schema

## `propertyUrls` (type: `array`):

One property per line: a Zillow property URL (https://www.zillow.com/homedetails/.../12345678_zpid/) or the bare zpid number. Each returns a full property record. Duplicates are skipped.

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

Zillow search result URLs, one per line, copied from your browser with any filters you set there (price, beds, home type, for rent, sold). Pages are followed until Max results per search.

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

Places to search, one per line: a city and state (Phoenix, AZ), a ZIP code (85032), a county or a neighborhood as Zillow names it. Uses the Listing type below.

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

Which listings a Location searches: homes for sale, rentals, or recently sold. Search URLs keep their own filters.

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

How many listings to take from each search URL or location (1 to 1000). Zillow shows about 41 listings per page and at most about 20 pages per search; narrow the search (ZIP, price band) to go deeper.

## `fetchDetails` (type: `boolean`):

Off: each search result is a listing card (price, address, beds, baths, sqft, Zestimate, days on Zillow), charged as a search result. On: the actor opens every result's property page and returns the full property record instead, charged as a property.

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

Property pages fetched in parallel (1 to 10). The default is gentle and reliable.

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

Pages are fetched directly first. If Zillow answers with a bot check, the actor retries through Apify Proxy on fresh sessions. Keep Apify Proxy on for reliable runs.

## Actor input object example

```json
{
  "propertyUrls": [
    "https://www.zillow.com/homedetails/2734-E-Vista-Dr-Phoenix-AZ-85032/8011097_zpid/",
    "1772396"
  ],
  "searchUrls": [
    "https://www.zillow.com/minneapolis-mn/",
    "https://www.zillow.com/austin-tx/rentals/"
  ],
  "locations": [
    "Phoenix, AZ",
    "55412"
  ],
  "listingType": "for_sale",
  "maxResultsPerSearch": 100,
  "fetchDetails": false,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per property or listing: status, price, address, beds, baths, sqft, Zestimate and fetchStatus.

## `allRecords` (type: `string`):

Every record with all fields, including photos, price history and facts.

# 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 = {
    "propertyUrls": [
        "https://www.zillow.com/homedetails/2734-E-Vista-Dr-Phoenix-AZ-85032/8011097_zpid/"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("morgan-studio/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 = {
    "propertyUrls": ["https://www.zillow.com/homedetails/2734-E-Vista-Dr-Phoenix-AZ-85032/8011097_zpid/"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("morgan-studio/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 '{
  "propertyUrls": [
    "https://www.zillow.com/homedetails/2734-E-Vista-Dr-Phoenix-AZ-85032/8011097_zpid/"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call morgan-studio/zillow-property-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,morgan-studio/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/z0rcrtYv1pQzZ3i3V/builds/hEwXRCtrmT3JawoyL/openapi.json
