# Zillow Property Details Scraper | from $0.80/1K | CSV (`x_guru/zillow-property-details-scraper`) Actor

Get Zillow property details from URLs, ZPIDs or full addresses: prices, Zestimate, photo URLs, histories and available listing contacts. Export CSV/JSON. Paid plans: $0.80/1K. Free: $2/1K, up to 25 properties per collection.

- **URL**: https://apify.com/x_guru/zillow-property-details-scraper.md
- **Developed by:** [Hundevmode Labs](https://apify.com/x_guru) (community)
- **Categories:** Real estate, Business
- **Stats:** 4 total users, 3 monthly users, 92.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 paid plan: property with details

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 Property Details Scraper — Prices & History 📋

Turn **Zillow property URLs, ZPIDs or full US addresses** into detailed property records. Export prices, available Zestimate and rent estimates, descriptions, photo URLs, price and tax histories, property facts and listing contacts to CSV or JSON.

**Start small:** enter `89070667` under **Property IDs (ZPIDs)**, set **Maximum results per run** to `5`, then click **Start**. No additional setup or Zillow login is required.

### 💳 Pay per saved result

| Result | Paid Apify plans / 1,000 | Free plan / 1,000 |
| --- | ---: | ---: |
| Property with available details | $0.80 | $2.00 |

Property descriptions, photo URLs and available histories, facts, schools and listing contacts are included. Failed or unmatched property inputs do not create a paid result.

Your Apify account determines the rate automatically; input cannot select a cheaper plan. Apify's standard start event costs **$0.00005 per GB of allocated memory, minimum one event**. At the default 256 MB, each run costs one start event. Platform usage is included in PPE pricing; no additional dataset-item fee is configured. Errors and diagnostics are not paid results. Each continuation batch has its own start fee and budget.

#### Control your spending on Free and paid plans

Minimum permitted Max total charge: $0.00205, covering the start event and at least one result at the highest Free rate. This is a minimum budget setting, not a minimum bill: only the start and saved result events are charged. The same result rates apply to all paid Apify plans.

Set **Max total charge** in Apify run settings before starting. Through the API, use `maxTotalChargeUsd`. This is separate from `maxResults`: a large requested count does not override the spending limit. The Actor checks whether the remaining run budget permits another result and stops when it does not. Apify can also mark a run ABORTED when that limit is reached.

Free accounts use their available Apify credits at $2.00/1,000 detailed rows. A Free collection is capped at **25 properties**. The allowance is shared across continuation batches and is retained by Resurrect. For the Details Actor the allowance is always 25 properties. Free runs also cap requests at 40, collection time at 180 seconds and compressed downloads at 5 MB; raising advanced settings cannot raise these caps. Paid accounts use the input limits. Independent fresh runs have independent allowances; this is not an account-wide monthly quota. [Apify account usage limits](https://docs.apify.com/account/billing#limits) apply to the entire account. Exhausting prepaid credits on a paid plan can allow additional paid usage when overage is enabled; set a run budget if you want a fixed maximum for this collection.

Saved dataset rows remain in storage, subject to Apify retention and account access. Continue only after the account permits runs again, using the latest `PAGINATION.nextInput` if available and a new run budget. Continuation does not replenish credits or start paid runs automatically. An immediate platform stop can interrupt checkpoint saving; use the latest available checkpoint and compare saved rows if no continuation was created.

### What is this Actor for?

Use this Zillow Property Details Scraper when you already know which properties you want to enrich: a shortlist, a CRM export or a property-data pipeline. It fetches available property-page details without requiring a city search.

| What you already have | Input to use |
| --- | --- |
| Zillow property-page links | Zillow property URLs |
| Numeric Zillow property IDs | Property IDs (ZPIDs) |
| Complete street addresses | Full US property addresses, including unit and ZIP |

To **find** homes for sale, rentals or sold listings by city, ZIP code or search URL, use **Zillow Scraper**. This Actor is the focused option for an existing property list; it does not search city inventories.

### How to get Zillow property details

1. Paste property URLs, or enter ZPIDs or full addresses. You can combine methods.
2. Set **Maximum results per run**. Start with a small batch to inspect the output.
3. Click **Start**. Every successfully collected property is saved once, with the details available from Zillow.
4. Open the results and download CSV, Excel or JSON. Check **Collection issues** for inputs that could not be matched or fetched.

#### Example: property IDs

```json
{
  "zpids": ["89070667"],
  "maxResults": 5
}
```

#### Example: a Zillow property URL

```json
{
  "startUrls": [
    {"url": "https://www.zillow.com/homedetails/89070667_zpid/"}
  ],
  "maxResults": 5
}
```

#### Example: an exact address

```json
{
  "addresses": ["837 Washington Ave APT 3B, Bronx, NY 10451"],
  "maxResults": 5
}
```

Include the street number, apartment if applicable, city, two-letter state and five-digit ZIP. Only an exact normalized address and unit match is accepted. Ambiguous or unmatched addresses are reported separately; another property is not substituted.

### What property data can I export?

Each saved row represents one unique property. The dataset is flat for CSV exports, and **missing values are `null`**.

| Data | Columns |
| --- | --- |
| Identity and location | `zpid`, `url`, `address`, `streetAddress`, `city`, `state`, `zipcode`, `latitude`, `longitude` |
| Listing and valuations | `status`, `price`, `currency`, `zestimate`, `rentZestimate`, `monthlyRent`, `pricePeriod` |
| Property attributes | `bedrooms`, `bathrooms`, `livingArea`, `homeType`, `yearBuilt`, lot size, `daysOnZillow` |
| Sale information | `soldDate`, `lastSoldPrice`, `mlsId`, `listingLastUpdated` |
| Description and photos | `description`, `primaryImageUrl`, `photoCount`, `photosJson` |
| Available histories and features | `priceHistoryJson`, `taxHistoryJson`, `factsJson`, `schoolsJson` |
| Available listing contacts | `brokerName`, `agentName`, `agentPhone`, `agentEmail`, `listingPhone` |
| Collection information | `inputAddress`, `detailStatus`, `source`, `scrapedAt` |

This excerpt comes from a private Apify cloud test. Field availability varies by property:

```json
{
  "zpid": "89070667",
  "address": "837 Washington Avenue #3B, Bronx, NY 10451",
  "soldDate": "2009-08-17",
  "lastSoldPrice": 173000,
  "photoCount": 13
}
```

Photo output contains URLs rather than downloaded image files. Histories, photos, facts and schools are encoded as JSON strings to keep each record in one CSV row. Listing-agent and brokerage contacts are **not property-owner contacts**. Emails, phone numbers, valuations and histories are returned only when available from the source.

### Input options

| Field | Purpose | Default |
| --- | --- | --- |
| `startUrls` | Property URLs containing a ZPID, as `[{"url":"…"}]` | Empty |
| `zpids` | Numeric Zillow property IDs | Empty |
| `addresses` | Complete US street addresses, including unit and ZIP | Empty |
| `maxResults` | Maximum unique properties saved in this run | 50 via API; 5 suggested in the form |
| `resumeFromRunId` | Continue the last finished batch | Unset |
| `propertyDatasetId` | Existing Dataset containing property IDs or URLs | Unset |
| `datasetField` | Identifier column: `zpid` or `url` | `zpid` |
| `advanced` | Request, time and traffic limits | Optional |

Provide at least one property URL, ZPID or full address. Each manually entered input list accepts up to 100 entries; an input Dataset supports up to 100,000 rows. If you combine methods, the result limit is shared across all of them. Duplicate IDs and URLs are removed before fetching; resolving an address alias can require an extra request but never creates a duplicate result in the same run or continuation chain.

### Continue a larger property list

After a batch, open **Continue collection: next batch input** (`PAGINATION`). If `hasMore` is true, copy the full `nextInput` into another run of this same Actor. The next dataset contains only newly collected properties. Keep all batch datasets to assemble the export.

Use the **latest** batch's continuation input. Keep property inputs unchanged; you can change `maxResults` and advanced limits. The previous run must be finished, belong to this Actor and your account, and retain its storage.

The result cap applies to each run. If you want 75 rows and the first batch saved 50, set the next batch's cap to 25. Collection can return fewer rows when inputs are duplicated, unavailable, unmatched or blocked. New runs are started by you, and a new run does not guarantee a different IP or that a Zillow block has ended.

### Automatic collection and recovery

Connection recovery is included in the price and handled automatically. You do not need a Zillow login or any additional service. If a temporary access restriction cannot be recovered within the collection limits, the Actor saves its progress and provides continuation input. Availability is not guaranteed for every property or run.

#### Collect details from an existing Dataset

Paste an accessible Apify Dataset ID into **Property list from Apify Dataset** and choose the `zpid` or `url` column. Up to 100,000 source rows are supported. The property list is frozen before collection, so continuation uses the same unique property IDs even if rows are later appended to the source. Invalid or missing identifiers are reported separately. Only Zillow property URLs containing a ZPID are accepted in the `url` column.

```json
{
  "propertyDatasetId": "YOUR_DATASET_ID",
  "datasetField": "zpid",
  "maxResults": 100
}
```

Replace the example ID with your Dataset ID. The same result, request, time and budget limits apply. A source Dataset is an input list; it is not modified, and old rows are not copied into the output.

### 🔁 What to do after an error or early stop

| Outcome | What to do next |
| --- | --- |
| Result, request, time or traffic limit | Open `PAGINATION`. If `hasMore` is true, copy **the full `nextInput`** into the next run's JSON input. Adjust the result cap or advanced limits as needed. |
| Access temporarily unavailable | Automatic recovery has already been attempted. Keep the saved dataset, wait, then continue with the full `nextInput`. Repeated access failures stop collection rather than retrying indefinitely. |
| Free collection allowance reached | Saved rows remain available. Continuation and Resurrect do not renew the allowance. After upgrading to a paid Apify plan, continue this same query with `resumeFromRunId` set to its latest run ID. |
| Budget reached | Apify can mark the run ABORTED when its charge budget is reached. Keep the saved dataset and use the latest `nextInput` with a new run budget. Budgets are per run, not a shared total across the chain. |
| Invalid input or changed continuation query | Correct the input. Do not repeat the same invalid run. Keep the original query when continuing, or start a fresh independent search with the corrected query. |
| `hasMore` is false | Inspect the summary and issues. Missing source data or failed exact-address matching can remain; a completed request queue is not a guarantee of complete source coverage. |
| Run failed before a checkpoint was saved | There is no usable continuation. Start again from your original input and compare any saved rows; a fresh independent run cannot guarantee deduplication against the old dataset. |

Use continuation from the **latest finished run of this same Actor and account**. Previously saved rows are not copied into the new dataset or charged again along that chain. Apify **Resurrect** restarts the same run with the same storage; `resumeFromRunId` creates a separate batch and dataset. Do not run both recovery methods at once. A Resurrect can create another standard start event; saved rows are not charged again. Request, time and traffic usage is restored from the latest checkpoint for the same run. A hard interruption can lose usage since that checkpoint, so the last few requests may not be included in restored counters.

### Collection limits and pricing

Default collection limits are 80 requests, 600 seconds and 100 MB of compressed response traffic. Leave advanced settings unchanged for a first run. Request retries are bounded, and failed inputs are recorded in **Collection issues** rather than inserted into the property dataset.

A completed run can still contain unavailable or failed inputs. Review the coverage summary and collection issues alongside the result count. The Actor reports its progress rather than promising that every input can be fetched.

**Private preview:** PPE is configured for the two private test Actors. They have not been published in Apify Store. The result rates and standard start fee above are the configured policy; owner tests are separate from billing by an external customer.

### Choose the right Zillow actor

Choose this actor when you already have property URLs, ZPIDs, full addresses or a property Dataset. Use **Zillow Scraper** to discover listings first, **Zillow Agents Scraper** to search the agent directory, or **Zillow Market Data Scraper** for regional monthly housing indexes.

### Frequently asked questions

#### Where do I find a Zillow ZPID?

Look for the numeric ID before `_zpid` in a Zillow property URL. For `https://www.zillow.com/homedetails/89070667_zpid/`, the ZPID is `89070667`.

#### Can I look up a property by address?

Yes. Enter the complete street address with the city, two-letter state, five-digit ZIP and unit when applicable. Only an exact match is saved.

#### Does every property include Zestimate, photos and price history?

No. Available source data is returned; missing fields are `null`. A Zestimate is a source estimate, not an appraisal produced by this Actor.

#### Can I collect agent emails or owner contacts?

Available listing contacts may be returned. Agent email coverage is not guaranteed, and listing agents are not property owners. This Actor does not provide an owner-contact database.

#### Can I choose the number of properties?

Yes. `maxResults` accepts 1–100,000 per run. Each manually entered input list accepts up to 100 entries; an input Dataset supports up to 100,000 rows, and request, time, budget and source limits can stop a batch earlier. Continue unfinished work using `PAGINATION.nextInput`.

#### Is this an official Zillow API?

No. This is an independent scraper of publicly accessible Zillow data, callable through the Apify API. Zillow does not sponsor or endorse it.

# Actor input Schema

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

Paste property-page URLs from zillow.com, one per entry. Each URL must contain a numeric ZPID, for example https://www.zillow.com/homedetails/89070667_zpid/. City and search URLs belong in Zillow Scraper.

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

Enter numeric Zillow property IDs, one per entry. Find the ID before \_zpid in a property URL. Duplicates are removed across input methods.

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

Maximum unique rows to save (1–100,000 on paid plans), subject to source availability, collection limits and budget. Free: up to 25 properties across one collection and its continuation chain. Entering a larger number does not raise the Free allowance. Use Max total charge in Apify run settings to cap spending.

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

Include street number, unit if applicable, city, two-letter state and five-digit ZIP. Only an exact address and unit match is saved; ambiguous or unmatched inputs are reported separately.

## `propertyDatasetId` (type: `string`):

Optional: paste the 17-character Dataset ID from a previous Zillow search or your own import. The Actor reads up to 100,000 rows, freezes the property list, and collects details for each unique valid property. You must have read access. Invalid rows are reported separately.

## `datasetField` (type: `string`):

Choose the source Dataset column: zpid for numeric property IDs, or url for Zillow property URLs containing a ZPID.

## `resumeFromRunId` (type: `string`):

Paste the finished run ID from this same Actor and account. Prefer copying the full PAGINATION.nextInput from the previous run. Keep the query unchanged. This run saves and charges only new rows, plus the standard start fee. Maximum results per run and the Apify budget both apply to this new batch.

## `advanced` (type: `object`):

Leave these settings unchanged for your first run. Optional limits control how much work one batch can do. Free runs additionally cap requests at 40, time at 180 seconds and compressed downloads at 5 MB; higher input settings cannot raise those caps.

## Actor input object example

```json
{
  "zpids": [
    "89070667"
  ],
  "maxResults": 1,
  "datasetField": "zpid"
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

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

No description

## `errors` (type: `string`):

No description

## `requests` (type: `string`):

No description

## `pagination` (type: `string`):

No description

## `detailRetry` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "zpids": [
        "89070667"
    ],
    "maxResults": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("x_guru/zillow-property-details-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 = {
    "zpids": ["89070667"],
    "maxResults": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("x_guru/zillow-property-details-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 '{
  "zpids": [
    "89070667"
  ],
  "maxResults": 1
}' |
apify call x_guru/zillow-property-details-scraper --silent --output-dataset

```

## MCP server setup

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