# Zillow Search Scraper - Homes For Sale & Sold by City or ZIP (`benthepythondev/zillow-scraper`) Actor

Scrape Zillow homes for sale and recently sold homes by city, ZIP code or search URL, with no 500-result limit. Optional full details: agent phone, price history, schools.

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

## Pricing

from $1.70 / 1,000 listings

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 Search Scraper - Homes For Sale & Sold by City or ZIP

Search Zillow for homes for sale or recently sold homes in any US city or ZIP code and get every listing as structured data: price, address, beds, baths, size, status, days on Zillow, Zestimate and broker. Large areas are split automatically, so a search is not cut off at 500 results. Export to JSON/CSV/Excel, run on a schedule, call via API, or connect to Make, Zapier or n8n.

### 🔎 What is the Zillow Search Scraper?

It is an Apify Actor that runs Zillow's own search for the places you name and saves one row per listing. You can search by city ("Austin, TX"), by ZIP code ("78704") or by pasting a search URL from zillow.com.

Zillow shows at most about 500 homes for one map view. When an area holds more, the Actor cuts the map into smaller tiles and reads each tile, the way you would zoom in by hand. In our test one run collected all 5,073 homes for sale in Austin in 20 seconds.

Turn on **Include property details** and each home also gets its full Zillow record: listing agent with phone number, price history, tax history, schools, home facts, climate risk scores and photo links.

No browser is started and no third-party unblocker is used, which keeps runs quick and cheap.

#### What data does it extract?

Every listing:

- **Identity:** `zpid`, `url`, `listingType` (home or building), `homeStatus`, `statusText`, `listingTags`
- **Price:** `price` (asking price, or sale price for sold homes), `zestimate`, `rentZestimate`, `taxAssessedValue`
- **Location:** `address`, `street`, `city`, `state`, `zip`, `latitude`, `longitude`
- **Home:** `bedrooms`, `bathrooms`, `livingArea` and `lotSize` in square feet, `homeType`
- **Market:** `daysOnZillow`, `soldDate` for sold homes, `openHouse`, `listingNote` (price cuts and other card notes), `brokerName`
- **Media:** `imageUrl`, `has3DTour`

With **Include property details**:

- **Listing agent:** `agentName`, `agentPhone`, `agentEmail`, `coAgentName`, `brokerPhone`, `mlsId`, `mlsName`
- **History:** `priceHistory[]`, `taxHistory[]`, `lastSoldPrice`, `lastSoldDate`
- **More facts:** `yearBuilt`, `pricePerSqft`, `monthlyHoaFee`, `taxAnnualAmount`, `parcelId`, `county`, `neighborhood`, `facts` (heating, cooling, parking, flooring, roof and more)
- **Around the home:** `schools[]`, `climateRisk`, `nearbyHomes[]`
- **Listing content:** `description`, `highlights`, `photos[]`, `virtualTourUrl`, `openHouses[]`, `pageViews`, `favorites`

### ⬇️ Input

| Field | Type | What it does |
|---|---|---|
| `locations` | array | Cities ("Austin, TX"), ZIP codes ("78704") or full Zillow search URLs |
| `listingType` | string | `forSale` or `sold` |
| `maxResults` | integer | Maximum listings to save across all locations |
| `minPrice`, `maxPrice` | integer | Price range in dollars |
| `minBeds`, `minBaths` | integer | Minimum bedrooms and bathrooms |
| `homeTypes` | array | Any of `houses`, `townhomes`, `condos`, `multiFamily`, `apartments`, `manufactured`, `lots` |
| `daysOnZillow` | string | Listed (or sold) within `1`, `7`, `14`, `30` or `90` days, or `6m`, `12m`, `24m`, `36m` |
| `includeDetails` | boolean | Add the full property record to every home. Off by default |

Filters apply to cities and ZIP codes. A pasted Zillow URL keeps the filters it already contains, which is handy when you have drawn a custom area or set special filters on zillow.com.

#### Example input

Houses and townhomes under $400,000 with at least three bedrooms that sold in Chicago in the last 30 days:

```json
{
  "locations": ["Chicago, IL"],
  "listingType": "sold",
  "maxResults": 500,
  "maxPrice": 400000,
  "minBeds": 3,
  "homeTypes": ["houses", "townhomes"],
  "daysOnZillow": "30"
}
```

### ⬆️ Output

One row per listing. This is a real row from a search for sale:

```json
{
  "zpid": "29575407",
  "listingType": "home",
  "url": "https://www.zillow.com/homedetails/13126-Greybull-Trl-Austin-TX-78729/29575407_zpid/",
  "homeStatus": "FOR_SALE",
  "statusText": "Active",
  "price": 439999,
  "address": "13126 Greybull Trl, Austin, TX 78729",
  "street": "13126 Greybull Trl",
  "city": "Austin",
  "state": "TX",
  "zip": "78729",
  "latitude": 30.448298,
  "longitude": -97.75281,
  "bedrooms": 3,
  "bathrooms": 2,
  "livingArea": 1433,
  "lotSize": 8664,
  "homeType": "SINGLE_FAMILY",
  "daysOnZillow": 30,
  "taxAssessedValue": 406910,
  "brokerName": "Welcome Home Realty",
  "listingTags": ["agent listing"],
  "listingNote": "3D Tour",
  "imageUrl": "https://photos.zillowstatic.com/fp/8455a8024710e5eb6cc1af2d482917ae-p_e.jpg",
  "has3DTour": true,
  "detailsLevel": "search",
  "scrapedAt": "2026-10-02T14:30:58+00:00"
}
```

A sold home carries the sale instead: `"homeStatus": "RECENTLY_SOLD"`, `"price": 385000`, `"soldDate": "2026-09-02"`, `"zestimate": 394400`, `"rentZestimate": 4671`.

With details on, the same row grows by about 40 fields, for example:

```json
{
  "agentName": "Atoosa Ponsford",
  "agentPhone": "(512) 480-0848",
  "mlsId": "2986990",
  "yearBuilt": 1958,
  "priceHistory": [{"date": "2026-09-30", "event": "Listed for sale", "price": 1185000, "pricePerSqft": 499, "source": "Unlock MLS"}],
  "taxHistory": [{"year": 2025, "taxPaid": 19236.43, "assessedValue": 939974}],
  "schools": [{"name": "Highland Park Elementary School", "rating": 10, "grades": "PK-5", "distance": 0.6}],
  "climateRisk": {"flood": {"score": 1, "label": "MINIMAL"}, "wind": {"score": 8, "label": "SEVERE"}},
  "detailsLevel": "full"
}
```

`detailsLevel` is `search` for a row with search data only and `full` once the property record was added.

### 💰 How much does it cost?

You pay per listing saved, plus a tiny start fee per run. Property details are a separate, optional charge per home.

| Apify plan | 1,000 listings | 1,000 listings with details |
|---|---|---|
| Free | $2.00 | $5.00 |
| Starter | $1.90 | $4.75 |
| Scale | $1.80 | $4.50 |
| Business and above | $1.70 | $4.25 |

All 5,073 Austin homes for sale cost about $10.15 on the Free plan without details. Set **Maximum cost per run** in the run options and the Actor stops at that amount. The details fee is charged only for homes whose record could be loaded.

### 💡 Use cases

- 🏘️ **Market inventory:** pull every active listing in a city or ZIP list each week and track prices, days on market and new arrivals.
- 📉 **Sold comps:** export homes sold in the last 30 or 90 days with sale price, size and Zestimate for an appraisal or a pricing model.
- 📞 **Agent and broker leads:** turn on details and collect the listing agent, phone and brokerage for every listing in your territory.
- 🔔 **Deal alerts:** schedule a daily run with `daysOnZillow` set to 1 and send new listings to Slack, a sheet or your CRM.

### ❓ FAQ

**Is there a limit of 500 or 820 results?** No. Zillow shows about 500 homes per map view and 820 per result list. The Actor splits a large area into map tiles and merges the results without duplicates, so the limit you set in `maxResults` is the only one.

**Can I search several places at once?** Yes. Add as many cities, ZIP codes or URLs as you need. `maxResults` is shared evenly between them, and a home that appears in two searches is saved once.

**Can I paste a Zillow search URL?** Yes. Set up any search on zillow.com, including a drawn area, copy the address bar and use it as a location. The URL's own filters are kept and the input filters are ignored for that entry.

**Why is `price` empty for some sold homes?** Some states, Texas among them, do not disclose sale prices, so Zillow has none to show. `soldDate` and `zestimate` are still filled.

**What is a `building` row?** A community or condo building where several homes are for sale under one card. It has a name, a starting price and a unit count, and no ZPID. Details are not available for these rows.

**Does it cover rentals?** Use the [Zillow Rentals Scraper](https://apify.com/benthepythondev/zillow-rentals-scraper), which also returns floor plans, units and leasing phone numbers.

**I already have addresses or ZPIDs. Do I need a search?** No. The [Zillow Detail Scraper](https://apify.com/benthepythondev/zillow-detail-scraper) takes URLs, ZPIDs or street addresses directly.

**What happens if Zillow blocks a request?** The Actor switches to another connection route and continues. If details cannot be loaded for a home, the row keeps its search data and no details fee is charged for it.

**How fresh is the data?** Every run reads Zillow live. Nothing is cached between runs.

**Is it legal to scrape Zillow listings?** The Actor collects listing information Zillow shows publicly to any visitor and does not log in or bypass a paywall. You are responsible for how you use the data. Agent names and phone numbers are business contact details, but privacy and marketing rules such as GDPR, CCPA, CAN-SPAM and the TCPA still apply to outreach, and Zillow's terms of use apply to you as well. If in doubt, ask a lawyer.

**Something is missing or broken?** Open an issue on the Actor's Issues tab with the run ID. Issues are answered within one business day.

### 🧩 Need this as a managed feed?

If you would rather receive a weekly listings file for your markets than run the Actor yourself, request a quote at <https://benthepythondev00.github.io/custom.html>.

### 🔗 You might also like

- [Zillow Detail Scraper](https://apify.com/benthepythondev/zillow-detail-scraper)
- [Zillow Rentals Scraper](https://apify.com/benthepythondev/zillow-rentals-scraper)
- [Apartments.com Rent & Availability Monitor](https://apify.com/benthepythondev/apartments-com-rent-monitor)
- [Zumper Rental Scraper & Price Change Monitor](https://apify.com/benthepythondev/zumper-rental-scraper)
- [Real Estate Agent & Agency Lead Scraper](https://apify.com/benthepythondev/real-estate-agent-lead-scraper)
- [Craigslist Real Estate Scraper](https://apify.com/benthepythondev/craigslist-real-estate-scraper)

**Keywords:** zillow scraper, zillow search scraper, zillow api alternative, zillow homes for sale, zillow sold homes, zillow sold comps, zillow listings export, zillow zip code search, real estate listings data, housing market data, property listings api, real estate agent leads, days on market data, zestimate data, zillow csv export, mls listings data, real estate data api, homes for sale scraper

# Actor input Schema

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

City and state ("Austin, TX"), 5-digit ZIP codes ("78704"), or full Zillow search URLs. The filters below apply to cities and ZIP codes; a pasted URL keeps its own filters.

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

Homes currently for sale, or homes that sold recently. For rentals use the Zillow Rentals Scraper.

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

Maximum number of listings to save across all locations. Each listing is one charged result. Large areas are split into map tiles automatically, so there is no 500-result ceiling.

## `minPrice` (type: `integer`):

Only homes at or above this price.

## `maxPrice` (type: `integer`):

Only homes at or below this price.

## `minBeds` (type: `integer`):

Only homes with at least this many bedrooms.

## `minBaths` (type: `integer`):

Only homes with at least this many bathrooms.

## `homeTypes` (type: `array`):

Leave empty for every home type.

## `daysOnZillow` (type: `string`):

For homes for sale: listed on Zillow within this period. For sold homes: sold within this period.

## `includeDetails` (type: `boolean`):

Add the full property record to every home: listing agent with phone, price and tax history, schools, facts, climate risk and photos. Charged as one extra "Property details" event per home.

## Actor input object example

```json
{
  "locations": [
    "Austin, TX"
  ],
  "listingType": "forSale",
  "maxResults": 10,
  "daysOnZillow": "any",
  "includeDetails": false
}
```

# Actor output Schema

## `results` (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 = {
    "locations": [
        "Austin, TX"
    ],
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("benthepythondev/zillow-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"],
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("benthepythondev/zillow-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"
  ],
  "maxResults": 10
}' |
apify call benthepythondev/zillow-scraper --silent --output-dataset

```

## MCP server setup

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