# Zillow Property Scraper — full record by zpid (`mu0i/zillow-property-scraper`) Actor

Extract the full Zillow property record for any zpid or listing URL: price, Zestimate, rent Zestimate, home facts, price and tax history, schools, agent, walk scores and photos. Works for for-sale, rental and off-market homes. Export JSON, CSV or Excel, run via API or on a schedule.

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

## Pricing

from $1.20 / 1,000 property records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

**Get the full Zillow property record** for any **zpid** or listing URL — price, **Zestimate** and rent
Zestimate, address and coordinates, the home facts (beds, baths, living area, lot, year built, home type,
parking, heating, cooling, appliances, HOA, tax), the **price history** and **tax history**, assigned
**schools** with ratings, the **listing agent and broker** with license and phone, MLS id, **walk / transit /
bike scores**, nearby homes, open houses, engagement counts, the description and the **photo gallery**. It
works for homes that are **for sale, for rent, or off market** — every zpid has a record. Structured JSON
from Zillow's own mobile API, no browser, no proxy setup. Export to **JSON, CSV, Excel or XML**, run it on a
schedule, call it from the **API**, or use it from an AI agent through Apify's integrations.

- 🏠 **Off-market homes included** — a zpid that has not been listed in years still returns a full record
  with a Zestimate.
- 📊 **Price and tax history, schools, agent, scores, photos** — the whole page, as typed fields.
- 🔗 **Paste zpids or Zillow links** — the zpid is read out of any zillow.com property URL.
- ⚡ **Twenty records per call, three calls in flight** — a run of 200 is ten round trips.
- 💵 **Pay per record**, never for a zpid that does not exist.

### What Zillow property data can you extract?

| Group | Fields |
|---|---|
| Identity and price | `zpid`, `url`, `status`, `statusText`, `price`, `pricePerSqft`, `zestimate`, `rentZestimate`, `daysOnZillow`, `timeOnZillow` |
| Address and location | street, city, state, ZIP, county; latitude and longitude |
| Facts (23 curated) | bedrooms, bathrooms (full / half), living area, year built, home type and subtype, lot area, stories, parking, garage, heating, cooling, appliances, HOA per month, annual tax, assessed value, on-market date, new construction |
| History | `priceHistory[]` (listings, price cuts, sales — with source and price per sq ft), `taxHistory[]` (tax paid, assessed value, year-over-year rates) |
| People | `agent` (name, license, phone), `broker` (name, phone), `mls` (id, name, last updated) |
| Neighbourhood | `schools[]` (name, level, grades, distance, GreatSchools rating, student–teacher ratio, enrollment), `scores` (walk, transit, bike), `nearbyHomes[]` |
| Media and extras | `hero`, `photos[]` (the gallery), `description`, `openHouse[]`, `listingFlags`, `engagement` (views, saves) |

### How to get a Zillow property record

1. Click **Try for free** at the top of this page. Apify creates a free account if you do not have one — no card is needed to run this.
2. Put zpids or Zillow property links into **zpids or Zillow URLs** — one per line. The zpid is read out of a link (`…/64947237_zpid/`), so any zillow.com property URL works.
3. Press **Start**. You are billed per property, so the number of lines is your budget.
4. Rows show up in the **Dataset** tab *while the run is still going*. Export to JSON, CSV, Excel or XML from there, or read them over the API.

Choose **Core fields only** when you want the headline (price, Zestimates, address, beds/baths/area/year/type,
hero image) at ~0.7 KB per row instead of ~17 KB — the same price, far less to parse.

Do not have zpids? Run the [Zillow Search Scraper](https://apify.com/mu0i/zillow-search-scraper) on a city
or ZIP: every row carries the zpid, and its **Add the full property record** option returns this record for
every listing in one go.

### What one Zillow record is, measured

Two of Zillow's own app operations are fired in parallel — one carries the histories, schools, agent,
Zestimate, HOA, MLS, scores and the facts; the other the numeric core, hero image and gallery — and together
they answer in about **0.8 seconds** and cover 24 of 25 field groups **without a login**.

**Off-market homes have records too.** zpid `1`, a house in Anchorage that has not been listed in years,
returns a full record: `"Off market"`, a price, a Zestimate of $788,800, a rent Zestimate of $4,443, the facts,
the tax history and its assigned schools. A scraper that parses listing pages needs a listing to exist;
this needs a zpid.

**What a for-sale record carries, on the sample below:** 23 curated facts, 13 price-history events
(listings, price cuts and sales), tax history, 3 schools with GreatSchools ratings and student–teacher ratios,
the agent's name, license and phone, the broker, the MLS id and last update, walk 99 / transit 83 / bike 56,
29 gallery photos, the next open house, and 987 views / 65 saves.

### Input

| field | | |
|---|---|---|
| `properties` | required | zpids or zillow.com property URLs, one per line. A zpid given twice is fetched and charged once |
| `detailLevel` | `full` | `full` (everything, ~17 KB per home) or `core` (the headline, ~0.7 KB) |
| `includePhotos` | on | Full record only. The gallery arrives in the same call, so leaving it on is free; turn it off to keep rows small |
| `fullSizePhotos` | off | Full record only. Adds a `media` block with every photo in every size Zillow serves (~50 KB, one extra upstream call) |

Every field, with its default — paste the whole block and delete what you do not need:

```json
{
  "properties": [
    "64947237",
    "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/"
  ],
  "detailLevel": "full",
  "includePhotos": true,
  "fullSizePhotos": false
}
```

### Output example

One row per property, with the `input` it came from. The full record, exactly as it lands in your dataset
(lists shortened, description trimmed):

```json
{
  "input": "64947237",
  "zpid": "64947237",
  "url": "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/",
  "status": "FOR_SALE",
  "statusText": "Condo for sale",
  "price": 2995000,
  "currency": "USD",
  "pricePerSqft": 1523,
  "zestimate": 2794400,
  "rentZestimate": null,
  "address": {
    "street": "2040 Broadway St APT 303",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94115",
    "county": "San Francisco County"
  },
  "location": { "lat": 37.794956, "lng": -122.43119 },
  "facts": {
    "bedrooms": 3,
    "bathrooms": 3,
    "bathroomsFull": 2,
    "bathroomsHalf": 1,
    "livingArea": 1967,
    "livingAreaUnits": "sqft",
    "yearBuilt": 1988,
    "homeType": "Condo",
    "propertySubType": ["Condominium"],
    "lotArea": 9448.164,
    "lotAreaUnits": "Square Feet",
    "stories": null,
    "parking": 1,
    "hasGarage": true,
    "heating": ["Central", "Radiant"],
    "cooling": null,
    "appliances": ["Dishwasher", "Disposal", "Range Hood", "Dryer", "Washer"],
    "hoaMonthly": 1935,
    "taxAnnual": 26569,
    "taxAssessedValue": 2174000,
    "onMarketDate": 1789948800000,
    "cumulativeDaysOnMarket": null,
    "isNewConstruction": null
  },
  "daysOnZillow": 2,
  "timeOnZillow": "2 days",
  "description": "Set within a boutique Pacific Heights building, this expansive three-bedroom, two-and-a-half-bath residence offers appro…",
  "hero": "https://photos.zillowstatic.com/fp/bb3edae2974ab6dbd226ce588e0ff835-p_b.jpg",
  "photos": [
    "https://photos.zillowstatic.com/fp/bb3edae2974ab6dbd226ce588e0ff835-d_b.jpg",
    "https://photos.zillowstatic.com/fp/059e37695ea99b6c830a7c189e46a90c-d_b.jpg",
    "…"
  ],
  "agent": { "name": "Gregg Lynn", "license": "DRE #01467774", "phone": "415-595-4734" },
  "broker": { "name": "Sotheby's International Realty", "phone": "415-901-1700" },
  "mls": { "id": "426146415", "name": "SFAR", "lastUpdated": "2026-09-21 15:45:34", "source": "Phoenix" },
  "priceHistory": [
    { "date": "2026-09-21", "event": "Listed for sale", "price": 2995000, "priceChangeRate": 0.3613636363636364, "pricePerSquareFoot": 1523, "source": "SFAR", "time": 1789948800000 },
    { "date": "2020-04-09", "event": "Sold", "price": 2200000, "priceChangeRate": -0.081419624217119, "pricePerSquareFoot": 1118, "source": "SFAR", "time": 1586390400000 },
    "…"
  ],
  "taxHistory": [
    { "time": 1758676727982, "taxPaid": 26568.5, "taxIncreaseRate": 0.24318716, "value": 2174000, "valueIncreaseRate": 0.24015972 },
    "…"
  ],
  "schools": [
    {
      "name": "Sherman Elementary School",
      "grades": "K-5",
      "level": "Elementary",
      "type": "Public",
      "distance": 0.3,
      "rating": 6,
      "link": "https://www.greatschools.org/california/san-francisco/6432-Sherman-Elementary-School/",
      "studentTeacherRatio": 11.81,
      "enrollment": 291,
      "address": { "street": "1651 Union Street", "city": "San Francisco", "state": "CA", "zip": "94123" }
    },
    "…"
  ],
  "nearbyHomes": [
    { "zpid": 15072690, "price": 1700000, "bedrooms": 2, "bathrooms": 2, "livingArea": 1330, "status": "RECENTLY_SOLD", "homeType": "CONDO", "address": { "streetAddress": "2040 Broadway St APT 102", "city": "San Francisco", "state": "CA", "zipcode": "94115" } },
    "…"
  ],
  "scores": { "walk": 99, "transit": 83, "bike": 56 },
  "openHouse": [{ "startTime": "2026-09-27 14:00:00", "endTime": "2026-09-27 16:00:00" }],
  "listingFlags": { "is_FSBA": true, "is_FSBO": false, "is_openHouse": true, "is_pending": false, "is_newHome": false, "is_comingSoon": false, "is_foreclosure": false, "is_bankOwned": false, "is_forAuction": false },
  "engagement": { "favorites": 65, "views": 987 },
  "note": null
}
```

**Core fields only** keeps `zpid`, `url`, `status`, `statusText`, `price`, `zestimate`, `rentZestimate`,
`pricePerSqft`, `address`, `location`, `daysOnZillow`, `hero` and the headline `facts` (`bedrooms`,
`bathrooms`, `livingArea`, `yearBuilt`, `homeType`, `lotArea`, `hoaMonthly`).

### How much does it cost to extract Zillow property data?

Pay per result — you are billed for records you receive, not for time or compute.

| Event | Per 1,000 | What one unit is |
|---|---:|---|
| `property` | $2.00 | one property record in the dataset |

**Paid Apify plans pay less than this.** The table above is the free-plan rate. Starter, Scale and Business each get a lower per-unit price — up to **40% off** on Business — and the Actor's Pricing tab shows every tier before you run anything.

**Is it free to try?** Yes: Apify's free plan comes with monthly credit, enough for roughly 2,500 records at
the rate above, and no card is needed.

**Starting a run costs $0.00001** — a cent per thousand runs — and there is no run minimum. **You are never billed for a run that found nothing.** An unknown zpid or a line that is not a zpid becomes a row saying so in the dataset — never a silently empty result, and never a charge. A run that fails because the data could not be *reached* fails loudly, because that one is worth retrying. Your run budget (`maxTotalChargeUsd`) is met exactly: the run delivers what fits and stops, never one record over.

### Use cases

- **Valuation and comps** — Zestimate, rent Zestimate, price history and nearby sales for any home, listed or not.
- **Enrich a listing feed** — turn the zpids from the Zillow Search Scraper, or from your own CRM, into full records.
- **Investor screening** — tax history, HOA, year built, lot size and days on market as typed fields for filters.
- **Agent and broker lead data** — the listing agent's name, license and phone, and the brokerage, per listed home.
- **Portfolio monitoring** — schedule the same zpids weekly and diff price, status and Zestimate.

### Integrations and API

Every Actor is an API endpoint. This starts a run, waits for it, and returns the rows in one call — swap in your token from **Settings → Integrations**:

```bash
curl -X POST 'https://api.apify.com/v2/acts/mu0i~zillow-property-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{ "properties": ["64947237", "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/"] }'
```

From JavaScript with the Apify client:

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('mu0i/zillow-property-scraper').call({ properties: ['64947237'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

From Python:

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_TOKEN')
run = client.actor('mu0i/zillow-property-scraper').call(run_input={'properties': ['64947237']})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

Schedule it, get a **webhook** when a run finishes, or connect it to **Make, Zapier, Google Sheets, Slack**
and the rest of Apify's integrations from the Actor's Integrations tab. Every Apify Actor is also a tool for
AI agents through the **Apify MCP server**, so an assistant can look up a home for you in a sentence.

### Good to know

**No address input.** Zillow's app does resolve addresses, but its address → zpid path has not been measured
end to end, and a near-miss would ship the *wrong house* with no warning — the worst kind of wrong. Until it
is measured, give a zpid or a link; a search on the ZIP with the **Zillow Search Scraper** is the way from an
address to a zpid.

**Agent and broker are null where Zillow has none.** Off-market homes carry no listing agent, and many
rental buildings list a property manager rather than an agent. The fields report what Zillow holds, not a
guess.

**Some facts are simply not on file.** `cooling`, `stories`, `cumulativeDaysOnMarket` and `rentZestimate`
are null on the sample above because Zillow does not carry them for that condo. A null here is Zillow's
answer; nothing is estimated in.

**A zpid given twice is fetched and charged once.** A record Zillow answers only partially (rare — its detail
operation did not respond) is delivered with a `note` saying which part is missing, and charged. **Runs do
not time out on you:** if your run timeout is about to hit, the Actor stops ahead of it with everything
collected so far and says so in the status message. A temporary problem on our side is retried for about
half a minute, then per property, before a row is given up on; rows already delivered always stand.

### Related Zillow Actors

| Actor | What it does |
|---|---|
| [Zillow Search Scraper — listings by city or ZIP](https://apify.com/mu0i/zillow-search-scraper) | Type a place, get one row per listing — up to 1,000 per place — with an option to attach this full record to every row. |

### FAQ

**Is it legal to scrape Zillow property data?** This Actor reads data that is publicly available to any
visitor without logging in, and scraping public data is generally lawful. What you do with it is your
responsibility: comply with Zillow's terms where they apply to you, treat agent names and phone numbers as
personal data under GDPR and CCPA, and do not republish records wholesale. This is not legal advice.

**Do I need a Zillow API key?** No. Zillow's public property API has been closed for years; this Actor
needs no key, no account and no proxy setup.

**Does it work for homes that are not for sale?** Yes — that is the point. Every zpid has a record, listed
or not; off-market homes return the facts, the histories, the schools and a Zestimate.

**Where do I get a zpid?** It is the number before `_zpid` in every Zillow property URL, and every row of the
[Zillow Search Scraper](https://apify.com/mu0i/zillow-search-scraper) carries one.

**How fresh is the data?** Every run reads Zillow live at the moment it runs; nothing is cached between runs.

**How fast is it?** Twenty records go up in one call and come back together, three calls in flight; a
single record answers in under a second.

**Is the Zestimate accurate?** It is Zillow's own estimate, passed through unchanged; the Actor never
computes or adjusts a value.

**What export formats are there?** JSON, CSV, Excel and XML from the Dataset tab, or any of them over the API.

**Something is wrong.** Open a ticket in the **Issues** tab of this Actor with the run id from the run's
URL; every run carries one, and it is enough to find exactly what happened.

# Changelog

This Actor's version history is a separate document: https://apify.com/mu0i/zillow-property-scraper/changelog.md

# Actor input Schema

## `properties` (type: `array`):

One per line. Either a bare zpid (64947237) or any zillow.com property link — the zpid is read out of the URL (…/64947237\_zpid/), so nothing is fetched to parse it. Off-market homes work: every zpid has a record.

## `detailLevel` (type: `string`):

Full is everything (~17 KB per home: facts, histories, schools, agent, photos). Core is the headline only (~0.7 KB: price, Zestimate, address, beds/baths/area/year/type, hero image) — same price per row, far less to parse.

## `includePhotos` (type: `boolean`):

Full record only. The gallery (up to ~30 image URLs) arrives in the same call, so leaving it on costs nothing extra; turn it off to keep rows small.

## `fullSizePhotos` (type: `boolean`):

Full record only. Adds a `media` block with each photo in every size Zillow serves (about 50 KB per home, one extra upstream call). Off unless you are building a gallery.

## Actor input object example

```json
{
  "properties": [
    "64947237",
    "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/"
  ],
  "detailLevel": "full",
  "includePhotos": true,
  "fullSizePhotos": false
}
```

# Actor output Schema

## `properties` (type: `string`):

One row per property: price, Zestimates, address, facts, histories, schools, agent, scores, photos.

# 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 = {
    "properties": [
        "64947237",
        "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mu0i/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 = { "properties": [
        "64947237",
        "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("mu0i/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 '{
  "properties": [
    "64947237",
    "https://www.zillow.com/homedetails/2040-Broadway-St-APT-303-San-Francisco-CA-94115/64947237_zpid/"
  ]
}' |
apify call mu0i/zillow-property-scraper --silent --output-dataset

```

## MCP server setup

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