# Zillow Search Scraper (`harpoon/zillow-search-scraper`) Actor

Scrape Zillow search results: price, beds, baths, area, address, coordinates and more as structured JSON.

- **URL**: https://apify.com/harpoon/zillow-search-scraper.md
- **Developed by:** [Harpoon](https://apify.com/harpoon) (community)
- **Stats:** 1 total users, 1 monthly users, 88.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 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 — turn any Zillow search into a clean, exportable dataset

Point it at a city, ZIP code, neighborhood or address — or pick one or more **whole states** and
sweep them — and get one row per listing: price, beds, baths, size, full address, coordinates,
estimates, broker and photo, ready to export as JSON, CSV, Excel or XML. Paste Zillow search
URLs instead if you prefer, or search many places in a single run.

#### What can Zillow Search Scraper do?

- Search by **city, ZIP code, neighborhood, county or address** — no Zillow account or API key
- **Sweep entire states**: each state is divided into search areas, every area is scraped, and the
  results are de-duplicated, so you collect as much of a state's inventory as the site exposes
- Search **for sale, for rent, or sold** listings
- Return pricing, size, address, coordinates, estimates, taxes, broker and image for every listing
- Search **many locations** (and states) at once and combine the results into one dataset
- Export results to JSON, CSV, Excel, or XML
- Run via the API, schedule runs, and integrate through webhooks or MCP

### What data can I extract?

<table>
<tr><th>What you get</th><th>Features</th></tr>
<tr><td>

- **Listing identity** — `zpid`, `url`, `status`, `status_text`, `home_type`
- **Pricing** — `price`, `price_text`, `currency`, `zestimate`, `rent_zestimate`, `tax_assessed_value`
- **Size & layout** — `beds`, `baths`, `area_sqft`, `lot_area`, `lot_area_unit`
- **Location** — `address`, `street`, `city`, `state`, `zipcode`, `latitude`, `longitude`
- **Listing details** — `days_on_zillow`, `broker_name`, `image_url`, `has_image`

</td><td>

- Search by location or by URL; for sale, for rent or sold
- Multiple locations per run
- Built-in views: **Overview**, **Location**, **Pricing**
- Export to JSON, CSV, Excel, XML
- API access, webhooks, SDKs
- LLM-ready output for MCP, ChatGPT, Claude

</td></tr>
</table>

### How to use Zillow Search Scraper

1. [Create](https://console.apify.com/sign-up) a free Apify account.
2. Open **Zillow Search Scraper** in Apify Console.
3. The form is prefilled with **Search whole states** = `Texas`, **Listing type** = `For sale`,
   and **Max listings per state / search** = `100` - press Start to run it as-is. To search a
   specific place instead, add **Specific locations** (a city, ZIP or address) or paste Zillow
   search URLs.
4. Adjust **Listing type** or the limit if you need to.
5. Click **Save & Start**.
6. Download results in JSON, CSV, Excel, or XML from the **Storage** tab.

> **Sweeping whole states is the expensive mode.** A large state is split into many search areas,
> so it can take tens of minutes and hundreds of MB of proxy traffic. Run one small state first to
> gauge the cost, then scale up.

### Input

There are three ways to start a run (only the first is prefilled):

- **Search whole states** — pick states to sweep for maximum coverage (the expensive mode).

- **Specific locations** — a city, ZIP code, neighborhood, county or address (fast).

- **Paste URLs instead\*** — paste Zillow search results URLs. When this is filled, it takes
  priority over everything else and the other inputs are ignored.

- `states` — whole states to sweep, de-duplicated across the state (prefilled: `TX`).

- `locations` — optional; specific places to search. Leave empty to use `states`.

- `listing_types` — one or more of `for_sale`, `for_rent`, `sold` (prefilled: `for_sale`). Each
  selected type is scraped as a separate search.

- `limit` — max listings per state (or per specific location) **per listing type** (prefilled 100).

- `search_urls` — optional; alternative to the above, takes priority when set.

- `grid_step_deg` — search-area size when sweeping a state; smaller is more thorough but costs
  more requests (default 0.2).

- `max_pages` — safety cap on result pages fetched per search area (default 2).

**Example input**

```json
{
  "states": ["TX"],
  "listing_types": ["for_sale"],
  "limit": 100
}
```

See the **Input** tab above for every parameter.

### Output

Results land in a dataset under the **Storage** tab. View them as a table (use the **Overview**,
**Location** and **Pricing** views), download them, or pull them via the API.

```json
{
  "zpid": "29478686",
  "url": "https://www.zillow.com/homedetails/208-Lessin-Ln-Austin-TX-78704/29478686_zpid/",
  "price": 850000,
  "price_text": "$850,000",
  "currency": "USD",
  "status": "FOR_SALE",
  "status_text": "Active",
  "home_type": "SINGLE_FAMILY",
  "beds": 4,
  "baths": 3,
  "area_sqft": 2340,
  "lot_area": 8454.996,
  "lot_area_unit": "sqft",
  "address": "208 Lessin Ln, Austin, TX 78704",
  "street": "208 Lessin Ln",
  "city": "Austin",
  "state": "TX",
  "zipcode": "78704",
  "latitude": 30.226673,
  "longitude": -97.76352,
  "zestimate": 833500,
  "rent_zestimate": 4375,
  "tax_assessed_value": 763479,
  "days_on_zillow": 60,
  "broker_name": "Keller Williams Realty",
  "image_url": "https://photos.zillowstatic.com/fp/a653e4948407414bbcf907979d9f8ad4-p_e.jpg",
  "has_image": true,
  "page": 1,
  "search_term": "Austin, TX"
}
```

Field names are lowercase snake\_case, and the input keys match them. Fields that a listing does
not have are omitted from that row.

### What can you do with the data?

Each recipe names the exact input and fields to use.

#### 1. Build a price-comparison sheet for a market

1. Set `locations` to a city or ZIP and `listing_type` to `for_sale`.
2. Set `limit` high enough to cover the area.
3. Export the **Overview** view to CSV or Excel and sort by `price` and `area_sqft`.

#### 2. Map active inventory

1. Run a search for your area(s).
2. Export `latitude`, `longitude`, `address` and `price`.
3. Load the coordinates into your mapping tool of choice.

#### 3. Track a market over time

1. Schedule the Actor to run daily for the same `locations`.
2. Compare `price`, `days_on_zillow` and `tax_assessed_value` between runs.

### How much does Zillow Search Scraper cost?

Pricing is pay-per-event, so you only pay for what a run actually produces:

- **`listing`** — charged once for every listing saved to the dataset (price, beds, baths, area,
  address, coordinates, estimates, broker and photo). **$1 per 1,000 listings** ($0.001 each).

A run that returns 10,000 listings costs about $10. You pay only for listings written to the
dataset, so a smaller `limit` costs less, and new Apify accounts get free monthly usage. See the
**Pricing** tab for current rates and plan discounts. Note that **sweeping whole states is the
costliest way to use the Actor** — each state is split into many search areas, so pick a small
state first to gauge both the cost and the time.

### FAQ

**Do I need an account, cookies, or an API key for Zillow?**
No. You only need a free Apify account. Just pick a location and press Start.

**Which mode wins, locations or pasted URLs?**
If **Paste URLs instead**\* is filled, it is used and **Search locations** is ignored. Otherwise
the locations are searched. The two are never combined.

**How many results can I get?**
Up to the number of public listings in each location, bounded by **Max listings per search** and
**Max pages per search**. Very large markets are capped by the site's own result limits.

**Can I scrape private or restricted content?**
No. The Actor returns publicly visible search listings only.

**Is it legal to scrape Zillow?**
The Actor collects publicly available data. Review Apify's guidance on legal and ethical scraping
and make sure your use case complies with Zillow's terms.

**Can I use it with the API / SDKs / MCP?**
Yes — see the **API** tab above, or connect through the Apify MCP server.

**Something isn't working.**
Open the **Issues** tab, or a discussion on the Actor page. Include your input and the run URL so
it can be reproduced.

### Notes and limitations

- Results reflect the public listings available at the moment the run executes; they can change
  between runs.
- A location name is matched to the closest region. Very ambiguous or misspelled names may fail
  to resolve — paste a Zillow search URL in that case.
- Some fields are not available for every listing (for example an estimate, taxes, or days on
  market). Missing fields are omitted from that row rather than shown as empty.
- **Max pages per area** exists to keep very large markets from running away; raise it if you
  need deeper coverage, up to the site's own cap.
- **State sweeps cover the whole state but are not guaranteed to be 100% exhaustive in the
  densest areas.** Each search area returns a bounded number of results; in a very dense city a
  single area can return more than that. Lower **grid\_step\_deg** (e.g. to `0.1`) for finer areas
  and rerun that state if you need more depth.
- The Actor is built to be rate-friendly. Extremely large runs may slow down when the site
  throttles requests, and will resume automatically.

### Support

Found a bug or have feedback? Open an issue in the **Issues** tab.

# Actor input Schema

## `states` (type: `array`):

Sweep entire states for as many listings as possible. Each selected state is divided into search areas and every area is scraped, then de-duplicated.<br><b>This is the expensive mode:</b> a big state can mean hundreds of MB of proxy data. Add one or two small states first to check timing and cost.

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

Optional. One or more places to search - a city, ZIP code, neighborhood, county or address, one per line (e.g. <code>Austin, TX</code>, <code>73301</code>). Leave empty to use only the states above.

## `listing_types` (type: `array`):

Which listing types to return. Pick one or more - each selected type is scraped as a separate search, so selecting more increases time and cost.

## `limit` (type: `integer`):

Cap on listings returned for each state (or each specific location). Higher values take longer and increase cost.

## `search_urls` (type: `array`):

Optional. Alternative to searching: paste one or more Zillow search results URLs, one per line, e.g. <code>https://www.zillow.com/homes/for\_sale/90005\_rid/</code>. When provided, these take priority over <b>Search whole states</b> and <b>Specific locations</b>.

## `grid_step_deg` (type: `number`):

How large each search area is when sweeping a state, in degrees (about 69 miles per degree). Smaller = more thorough but far more requests (and proxy traffic). Default 0.2 is a good balance; lower it to 0.1 for dense cities, raise it to save cost.

## `max_pages` (type: `integer`):

Safety cap on result pages fetched per search area. The first page already returns the bulk of nearby listings.

## Actor input object example

```json
{
  "states": [
    "TX"
  ],
  "listing_types": [
    "for_sale"
  ],
  "limit": 100,
  "grid_step_deg": 0.2,
  "max_pages": 2
}
```

# Actor output Schema

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

One row per scraped listing. Export as JSON, CSV, Excel, or XML.

# 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 = {
    "states": [
        "TX"
    ],
    "listing_types": [
        "for_sale"
    ],
    "limit": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("harpoon/zillow-search-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 = {
    "states": ["TX"],
    "listing_types": ["for_sale"],
    "limit": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("harpoon/zillow-search-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 '{
  "states": [
    "TX"
  ],
  "listing_types": [
    "for_sale"
  ],
  "limit": 100
}' |
apify call harpoon/zillow-search-scraper --silent --output-dataset

```

## MCP server setup

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