# Zillow Listings Scraper (`scrapyx/zillow-listings-scraper`) Actor

Zillow homes for sale, for rent or recently sold in any US city or ZIP: price, address, beds, baths, living area, lot, home type, days on Zillow, tax assessed value, sold date, coordinates, and unit prices for rental buildings.

- **URL**: https://apify.com/scrapyx/zillow-listings-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (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 $1.26 / 1,000 results

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

## Zillow Listings Scraper (For Sale, Rent, Sold)

Homes **for sale, for rent or recently sold** on Zillow, for any US city or
ZIP code. For each home: price, full address, beds, baths, living area, lot
size, home type, days on Zillow, tax assessed value, Zestimate where Zillow
shows one, sold date, coordinates and the listing URL — and, for rental
buildings, the starting price of every unit type.

Reads Zillow's public city and ZIP pages. No login, no browser.

### What it is for

- **Market monitoring** — new listings and price levels by city or ZIP.
- **Rental research** — rents by bedroom count, including apartment complexes.
- **Comps** — recently sold homes with dates (and prices where the state
  publishes them — see 3).

### Input

| field | what it does |
| --- | --- |
| `locations` | `austin-tx`, `san-diego-ca`, `austin-tx-78701` (or "Austin, TX"). |
| `listingType` | `for_sale`, `for_rent`, `sold`. |
| `homeType` | `any`, `houses`, `condos`, `townhomes`. |
| `maxItems` | Homes per location (default 82; 41 per page). |

### Four things worth knowing before you trust the data

#### 1. Zillow stops after about 20 pages, whatever the total says

Austin shows 5,757 homes for sale, but Zillow serves only ~20–21 pages of 41
before answering with an error. Split big cities by ZIP code to reach more.
The summary reports Zillow's total next to what was returned.

#### 2. Rentals are mostly whole buildings

40 of the first 41 Austin rentals were apartment complexes with **no single
price** — just "from" prices per unit type ("1 bed from $1,320"). Each such
row gets `unitPrices` (per bedroom count) and `priceFrom` (the lowest), so
you don't get a column of empty prices.

#### 3. Sold prices are missing in non-disclosure states

Recently sold homes in **Austin, TX came with no sale price at all** (0 of 41),
while **San Diego, CA** came with prices on every row. Texas and about ten
other states do not make sale prices public record, so Zillow can't show
them. When a sold search returns no prices, the summary says so in plain
words (`priceNote`) — the dates and home details are still there.

#### 4. Filters are checked against the rows

Home type and listing type are part of the page address on Zillow; the Actor
checks the first page's homes actually match what you asked for and returns
nothing (with an explanation) if they don't.

### Proxy

**US residential is required and is the default.** Zillow refused every
Apify server and datacenter address measured, and served US residential
addresses — but only for some browser fingerprints, so the Actor uses the two
that passed. Pages are about 0.6 MB; residential transfer is billed on the
compressed size.

### Output

```json
{
  "recordType": "LISTING",
  "zpid": "185179147",
  "statusType": "FOR_SALE",
  "priceValue": 524900,
  "addressStreet": "12500 Turkey Ridge Ct",
  "addressCity": "Austin",
  "addressZipcode": "78729",
  "beds": 4,
  "baths": 2,
  "livingArea": 2314,
  "lotArea": 0.2717,
  "lotAreaUnit": "acres",
  "homeType": "SINGLE_FAMILY",
  "daysOnZillow": 9,
  "taxAssessedValue": 490354,
  "detailUrl": "https://www.zillow.com/homedetails/12500-Turkey-Ridge-Ct-Austin-TX-78729/185179147_zpid/"
}
```

Every row also carries Zillow's full listing object.

### Limits

- Zillow's filter panel (price, beds, etc.) is not used — its robots.txt
  disallows the filter parameter. City, ZIP, listing type and home type are
  the permitted filters; filter the output for the rest.
- Home detail pages are not fetched.

# Actor input Schema

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

US city or ZIP as in a zillow.com URL: 'austin-tx', 'san-diego-ca', 'austin-tx-78701' ('Austin, TX' also works). One search each.

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

Checked against every first page's rows.

## `homeType` (type: `string`):

Checked against the rows; a type Zillow didn't apply returns no rows.

## `maxItems` (type: `integer`):

41 per page. Zillow stops serving after roughly 20 pages per search; split big cities by ZIP.

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

Searches in parallel.

## `minRequestInterval` (type: `number`):

Global pacing.

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

US residential is REQUIRED: Zillow refused every Apify server and datacenter address measured, and served US residential addresses.

## Actor input object example

```json
{
  "locations": [
    "austin-tx",
    "san-diego-ca"
  ],
  "listingType": "for_sale",
  "homeType": "any",
  "maxItems": 82,
  "maxConcurrency": 2,
  "minRequestInterval": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "locations": [
        "austin-tx",
        "san-diego-ca"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/zillow-listings-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 = { "locations": [
        "austin-tx",
        "san-diego-ca",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/zillow-listings-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 '{
  "locations": [
    "austin-tx",
    "san-diego-ca"
  ]
}' |
apify call scrapyx/zillow-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/zillow-listings-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/3dlwBy8bAMhP8wMeE/builds/O4NcFqaVEY9jg3JmT/openapi.json
