# Zillow ZPID Scraper — Cheap Bulk Property Details & Photos (`afanasenko/zillow-zpid-scraper`) Actor

Zillow property details by ZPID or property link, in bulk and cheap: price, Zestimate, beds, baths, price and tax history, schools, listing agent and phone, all photos. Export to CSV, JSON or Excel.

- **URL**: https://apify.com/afanasenko/zillow-zpid-scraper.md
- **Developed by:** [Andrey Afanasenko](https://apify.com/afanasenko) (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.50 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Zillow ZPID Scraper — Cheap Bulk Property Details & Photos

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/afanasenko/zillow-zpid-scraper)

> **Paste a list of Zillow ZPIDs or property links — ten or ten thousand — and get one row of property details for each: price, Zestimate, beds and baths, price and tax history, schools, the listing agent's name and phone, and every photo.**

Built for bulk: one lookup per property, no search pages in between, and a price per property that drops as your Apify plan grows. The columns are the same as in [Zillow Details Scraper](https://apify.com/afanasenko/zillow-property-agent-data-scraper), so a pipeline built for one works with the other.

***

### 🎯 What it does

You give the Actor ZPIDs (`29460381`) or property links (`https://www.zillow.com/homedetails/…/29460381_zpid/`), one per row. For each property it returns one flat row:

| Group | What you get |
|---|---|
| **Listing** | Status, price, price change, days on Zillow, listing type (agent, owner/FSBO, new construction, open house), views and saves |
| **Home** | Address, county, neighborhood, coordinates, type, beds, baths, living area, lot, year built, stories, heating, cooling, appliances, flooring, pool, garage, parking, basement |
| **Money** | Zestimate, rent Zestimate, price per sq ft, HOA fee, annual tax, last tax paid and assessed value, last sale date and price, full price history |
| **Contact** | Listing agent name and phone (the owner's phone on FSBO listings), agent profile link, co-agent, brokerage and its phone |
| **Media & area** | Main photo plus the full photo gallery, nearby schools with ratings |

Repeated properties are looked up once. Entries that are not a ZPID or a property link are skipped and listed in the run log.

***

### 📦 Output sample

One real row, trimmed for length (`photos` holds all 24 photos of this listing):

```json
{
  "zpid": "29460381",
  "hdpUrl": "https://www.zillow.com/homedetails/1107-Woodland-Ave-Austin-TX-78704/29460381_zpid/",
  "price": 1990000,
  "status": "FOR_SALE",
  "homeType": "SINGLE_FAMILY",
  "listingType": "FSBA",
  "streetAddress": "1107 Woodland Ave",
  "city": "Austin",
  "state": "TX",
  "zipcode": "78704",
  "county": "Travis County",
  "agentName": "Wade Giles",
  "cellPhone": "512-808-6756",
  "agentProfileUrl": "https://www.zillow.com/profile/WadeATX/",
  "brokerName": "Compass RE Texas, LLC",
  "pricePerSqft": 689,
  "propertyTax": 35175,
  "bedrooms": 3,
  "bathrooms": 3,
  "livingArea": 2887,
  "lotSize": "7,143 sqft",
  "yearBuilt": 2018,
  "hasPool": true,
  "daysOnZillow": "7 days",
  "lastTaxAssessedValue": 1872660,
  "priceHistory": [
    { "date": "2026-10-15", "price": 1990000, "event": "Listed for sale", "pricePerSquareFoot": 689 }
  ],
  "schools": [
    { "name": "Travis Heights Elementary School", "rating": 6, "grades": "PK-5", "distance": 0.3 }
  ],
  "mainPhoto": "https://photos.zillowstatic.com/fp/50f35bf9c59e4fa28231ccddb8f0f46a-p_f.jpg",
  "photos": [
    "https://photos.zillowstatic.com/fp/50f35bf9c59e4fa28231ccddb8f0f46a-cc_ft_1536.jpg",
    "https://photos.zillowstatic.com/fp/4ec5ff9fa0d3e113949108160d6dc9c8-cc_ft_1536.jpg"
  ]
}
```

The dataset has two views: **Overview** (photo, address, price, agent, phone, beds, baths, area) and **Full details** (all 70 columns).

***

### ⚡ Quick start

1. Paste your ZPIDs or Zillow property links into **ZPIDs or property links**, one per row. A comma-separated list in one row works too.
2. Optionally set **Max properties per run** to cap the spend.
3. Click **Start**. Download the results as CSV, JSON or Excel.

Where to find a ZPID: it is the number just before `_zpid` in a property link. You can paste the whole link.

***

### 🧭 When to use it

- **You already have the list.** ZPIDs from a CRM, an earlier export, a search you ran elsewhere — and you need fresh details for all of them.
- **Re-checking a portfolio.** Run the same list every week and compare price, status and days on Zillow.
- **Photos in bulk.** Every listing's gallery in the same row, no extra step.
- **Owner (FSBO) phone numbers.** On owner listings the phone in `cellPhone` is the owner's.

To find properties by ZIP code, by city or by a Zillow search link, or to get the listing agent's e-mail, use [Zillow Details Scraper](https://apify.com/afanasenko/zillow-property-agent-data-scraper) instead.

***

### 🛠 Input

| Field | What it does |
|---|---|
| **ZPIDs or property links** (`zpids`) | One property per row: a ZPID or a property link. Leave empty for a 3-property test run. |
| **Max properties per run** (`maxProperties`) | Look up at most this many properties, in list order. `0` = the whole list. |

***

### 💰 Pricing

This Actor uses **pay per event**. One event, `Property`, fires once per property that lands in your dataset.

| Your Apify plan | Price per property | Per 1,000 properties |
|---|---|---|
| Free | $0.004 | $4.00 |
| Bronze | $0.0035 | $3.50 |
| Silver | $0.003 | $3.00 |
| Gold and above | $0.0025 | $2.50 |

ZPIDs that are not found, entries that are not a ZPID, repeats, and properties that could not be loaded are never charged. A run that returns nothing costs nothing.

***

### 🆓 Free vs paid plan

| | Free plan | Paid plan |
|---|---|---|
| Properties per run | 100 | Unlimited (or your own **Max properties per run**) |
| All columns and photos | ✓ | ✓ |

On the free plan, up to 25 of the ZPIDs over the limit are added to the dataset as rows with only `zpid`, `hdpUrl` and a `notLookedUpReason` note — so you can see what was left out. They are not charged.

***

### 📡 Live status & storage records

While a run is going, the **Live Status** link on the run page shows progress, properties saved and spend so far. Three records are written to the run's key-value store:

| Record | What it holds |
|---|---|
| `RUN_SUMMARY` | How the run ended; properties requested, saved, not found and not loaded; invalid entries; wall-clock seconds |
| `USER_MESSAGE` | A plain-language note when a run needs explaining — nothing found, nothing valid in the input, a demo run |
| `FREE_LIMITS_APPLIED` | Which free-plan limits changed this run's output |

***

### 🤖 Programmatic / API use

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('afanasenko/zillow-zpid-scraper').call({
    zpids: ['29460381', 'https://www.zillow.com/homedetails/x/29120239_zpid/'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].price, items[0].cellPhone, items[0].photos.length);
```

***

### ❓ FAQ

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

The Actor reads property pages that Zillow publishes openly, with no login. How you use the data — and especially the phone numbers — is your responsibility; outreach in the US is governed by the TCPA, CAN-SPAM and state law.

#### Is there an agent e-mail column?

No. E-mail needs a second lookup per property, which is what keeps this Actor cheap. [Zillow Details Scraper](https://apify.com/afanasenko/zillow-property-agent-data-scraper) returns it, with the same other columns.

#### Why is `propertyTax` empty on some rows?

Zillow does not publish an annual tax figure for every listing — it is missing most often on rentals. `lastTaxPaid` and `lastTaxAssessedValue` from the tax history are often still there.

#### Why did a ZPID return nothing?

The listing was removed, merged into another property page, or the number lost a digit when copied. Not-found ZPIDs are listed in the run log and never charged.

#### How many properties can one run handle?

Thousands. Lookups run in parallel; a 1,000-property run usually takes about five minutes.

#### Can I schedule this?

Yes. Save your list as an Apify Task and schedule it daily or weekly.

***

### 🔗 Related actors

| Actor | What it does |
|---|---|
| [Zillow Details Scraper](https://apify.com/afanasenko/zillow-property-agent-data-scraper) | Property listings by ZIP, ZPID or URL, with the listing agent's e-mail |
| [Zillow Search by ZIP](https://apify.com/afanasenko/zillow-zip-search) | Focused ZIP-code property search |
| [Zillow Search by URL](https://apify.com/afanasenko/zillow-url-search) | Paste a Zillow search URL and get the listings behind it |
| [Zillow Agent Leads](https://apify.com/afanasenko/zillow-agent-leads-scraper) | Real-estate agents by area or name, with e-mail, phone and sales history |
| [Zillow MCP Server](https://apify.com/afanasenko/zillow-mcp-server) | The same Zillow property data as tools for an AI agent |

***

### 🛟 Support & feedback

Something missing, wrong, or slow? Open an issue on the **Issues** tab of this Actor. Every one is read, and a short note tends to ship a fix within a few days.

***

### ⚖️ Disclaimer

This Actor collects publicly available information from Zillow property pages. It is not affiliated with, endorsed by, or connected to Zillow Group, Inc. Use the data in line with applicable law and with the terms of the sites involved.

# Changelog

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

# Actor input Schema

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

One Zillow property per row: a ZPID (29460381) or a property link (https://www.zillow.com/homedetails/…/29460381_zpid/). Rows pasted as a comma-separated list are split. Repeated properties are looked up once. Entries that are neither are skipped and not charged. Leave empty for a 3-property test run.

## `maxProperties` (type: `integer`):

Cost control: look up at most this many properties from the list, in list order. 0 means the whole list. On the free plan a run looks up at most 100 properties whatever you set here.

## Actor input object example

```json
{
  "zpids": [],
  "maxProperties": 0
}
```

# Actor output Schema

## `liveStatus` (type: `string`):

No description

## `results` (type: `string`):

No description

## `runSummary` (type: `string`):

Aggregate run statistics — counts, mode, paid events fired, wall-clock time.

## `userMessage` (type: `string`):

Onboarding tip, paid-plan welcome, or diagnostic message — only present when the run has something to surface.

## `freeLimitsApplied` (type: `string`):

Free-tier caps that affected this run. Empty if no caps applied or user is on a paid plan.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("afanasenko/zillow-zpid-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("afanasenko/zillow-zpid-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 '{}' |
apify call afanasenko/zillow-zpid-scraper --silent --output-dataset

```

## MCP server setup

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