# Zillow Price Tracker & Scraper - Price Drops, API & MCP (`akhil_rajesh/zillow-price-tracker`) Actor

Scrape and monitor Zillow new listings, price drops, rentals, FSBO and sold homes by city, ZIP code, link or street address: cuts with dates, Zestimate, price per sq ft and rent yield. Only changes returns what moved since the last run, with Slack, Discord or Teams alerts and an MCP server.

- **URL**: https://apify.com/akhil_rajesh/zillow-price-tracker.md
- **Developed by:** [Akhil rajesh](https://apify.com/akhil_rajesh) (community)
- **Categories:** Real estate, Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 homes

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 Price Tracker & Scraper

Scrape Zillow homes **for sale, recently sold and for rent** by city, ZIP code, county, neighborhood, Zillow search link or **street address**, with each home's **latest price cut and the day it happened**, days on Zillow, beds, baths, living area, Zestimate, brokerage, photos and location, plus **price per sq ft, price against the Zestimate and rent yield**.

It is also a **Zillow monitor**. Schedule it with **Only changes** and each run returns only what moved since the last one: **new listings, price drops, price increases, homes back on the market, sold, pending or removed**, each with **every price the tracker has seen for the home**, posted to **Slack, Discord or Microsoft Teams** if you like. It runs as a **live API and MCP server** for AI agents too.

### Why this scraper

- **It tracks changes, not just listings.** Most Zillow scrapers return the same homes every run, and you work out what changed. This one keeps a history per search and returns only new listings, price cuts and rises, homes back on the market, and homes that sold or left, each one once.
- **Every home Zillow lists, not just the first 820.** Zillow shows at most 820 homes per search. A city with more is read by its ZIP codes (homes whose address is in the city), so a tracker watches the whole market. Austin, TX lists about 5,600 homes for sale.
- **Price cuts with their dates, on every row.** Zillow's own latest price change (amount, day, the price before it and the percentage) comes with each home, so even a single run answers "which homes were cut this week?".
- **A price history of your own.** Zillow's price history isn't on its search pages, and its robots.txt disallows the requests that load it. With Only changes, each change row carries `trackedPrices`: every price your tracker saw for the home, with the day it first saw it.
- **Homes by address, link or zpid.** Type `2433 Calle Moreno, Brownsville, TX 78521` and get that home from its own page. An address is matched to exactly one Zillow home (house number, street, unit and ZIP code or city must agree), never to Zillow's first suggestion.
- **No runaway bills.** Every run stops at Max results (1,000 unless you set it) or at your maximum cost per run. Locations Zillow doesn't know are free, and so are sold homes in states that don't disclose sale prices (Texas and others).
- **Clear about what it didn't read.** Anything Zillow didn't answer is named in the status message, and a run that read nothing fails without charging.

| | Typical Zillow scrapers | This Actor |
|---|---|---|
| New listings, price cuts, sold, pending, removed since the last run | You compare runs yourself | Built in (Only changes) |
| Alerts to Slack, Discord, Teams | No | Yes |
| Price history | Zillow's, from a detail scraper | Your tracker's own, on every change row |
| Whole city past Zillow's 820 per search | Some | Yes, by ZIP code |
| Lookup by street address | Detail scrapers | Yes, up to 20 a run |
| MCP server for AI agents | Through Apify's generic tools | Its own (4 tools) |
| Price per 1,000 homes | About $0.90 to $3.60 | $1.00, less on paid plans |

### Use cases

- **Zillow price-drop alerts**: a daily schedule for your target ZIP codes that posts every cut to Slack.
- **Only new listings since the last run**: an investor's or agent's morning list, with days on Zillow to spot motivated sellers.
- **Zillow FSBO and foreclosures**: for sale by owner (FSBO) homes, foreclosures and auctions, by Zillow's own listing kinds (by owner, foreclosure, bank owned, auction, new construction, coming soon).
- **Investor screening**: price per sq ft, price against the Zestimate, gross rent yield and the latest cut, in the Investor view.
- **Zillow comps**: recently sold homes with their sale dates and prices, newest first.
- **Rentals**: rents by building and unit size, special offers, and rent drops over time.
- **Market research**: inventory, median price and the share of homes with a cut per city or ZIP code (in the run summary).
- **Property lookup**: a list of addresses in, each home's status, price, Zestimate, description, year built, HOA and agent out.
- **AI agents**: ask an assistant "which 3-bed homes under $500k in 78744 were cut this week?" through the MCP server.

### How to use it in 4 steps

1. Add **Locations**: `Austin, TX`, `78744`, `Travis County, TX`, `Mueller, Austin, TX`, or a link such as `https://www.zillow.com/austin-tx/`. Or add **Homes**: addresses, Zillow links or zpids.
2. Pick **Listing types** (for sale, recently sold, for rent) and any **filters**.
3. Set **Max results** and run it.
4. To track changes, switch on **Only changes since the last run**, add an **Alert webhook URL** if you want chat alerts, and schedule it (daily is typical).

### What you get

One row per home (`type: "home"`). Example (a real row from ZIP code 78744, shortened):

```json
{
    "type": "home",
    "id": "29467752",
    "zpid": "29467752",
    "location": "78744",
    "region": "Austin TX 78744",
    "listingType": "forSale",
    "listingKind": "agent",
    "price": 245000,
    "priceChange": -15000,
    "priceChangeDate": "2026-10-16",
    "priceBeforeLastChange": 260000,
    "lastChangePercent": -5.77,
    "daysOnZillow": 27,
    "bedrooms": 3,
    "bathrooms": 2,
    "livingAreaSqft": 1308,
    "pricePerSqft": 187,
    "zestimate": 243500,
    "priceVsZestimatePercent": 0.6,
    "rentZestimate": 2154,
    "grossRentYieldPercent": 10.55,
    "homeType": "SINGLE_FAMILY",
    "address": "4801 Cabob St, Austin, TX 78744",
    "brokerName": "Dash Realty",
    "summary": "3 bd, 2 ba, 1,308 sq ft house at 4801 Cabob St, Austin, TX 78744, for sale at $245,000 (cut $15,000 on 2026-10-16), 27 days on Zillow.",
    "url": "https://www.zillow.com/homedetails/4801-Cabob-St-Austin-TX-78744/29467752_zpid/"
}
```

Zillow shows a Zestimate and a rent Zestimate on about a quarter of search results, so `priceVsZestimatePercent` and `grossRentYieldPercent` are empty on the rest. With Home pages to read, a home's own page usually has them.

With **Only changes**, each row also has `change`; price changes have `previousPrice`, `changeAmount` and `changePercent`; and every change row has `trackedPrices` (the prices the tracker saw, `[{"date", "price"}]`, the latest 6) and `firstSeenDate`:

| change | meaning |
|---|---|
| `priceCut` / `priceIncrease` | the price moved since the last run |
| `newListing` | a home the tracker hadn't seen (check `daysOnZillow`: most are listed since the last run) |
| `backOnMarket` | listed again after it was reported sold, pending or removed |
| `sold` | found on Zillow's sold list (with `soldDate`, and `soldPrice` where the state discloses it) |
| `pending` | its own page says pending or under contract (with Home pages to read) |
| `removed` | gone from the search two runs in a row, or its page says off the market |
| `newSale` | a new home on the Recently sold list |
| `firstRun` | the first run's baseline: the homes listed now |

**Rentals**: apartment buildings come as one row each (`isBuilding`, `buildingName`, `rent` and `maxRent`, `units` with beds and price, `availableUnits`, `specialOffer`); single homes for rent as normal rows with `rent` and `rentPerSqft`.

**Home pages** (Home pages to read, or the Homes input) add the description, year built, HOA fee, tax rate, Zillow's price per sq ft, parking, listing agent and brokerage, MLS id, views and saves, all photos, and the price history where the page shows it.

The dataset has views for **Homes**, **Changes**, **Investor view**, **Sold homes**, **Rentals** and **Home pages** (a view picks columns: every view lists every row, so filter on `type` or `change` if you need to).

### How to use it

#### Locations

A city and state (`Austin, TX`, `Austin TX`, `Austin, Texas`), a ZIP code, a county (`Travis County, TX`), a neighborhood (`Mueller, Austin, TX`) or a Zillow search link. Zillow needs the state: `Springfield` alone is refused with a note. A link's own filters (price, beds) aren't read, because Zillow's robots.txt doesn't allow its filtered links: use this Actor's filters. A street address among the locations is read as a home.

#### Homes

Street addresses (`2433 Calle Moreno, Brownsville, TX 78521`, `789 N Clarkson St Apt 1006, Denver, CO 80218`), Zillow home links (`https://www.zillow.com/homedetails/.../83825908_zpid/`) or zpids, read from their own pages: up to 20 a run (Zillow refuses a visitor's home pages after about 26). An address needs its city and state or its ZIP code. It is looked up in Zillow's own address search and matched to exactly one home: the house number, street, unit (or no unit) and ZIP code or city must agree, and a street's direction (N, SE) may be left out when only one home fits. An address Zillow doesn't know, or one that fits several homes (a building without the unit), gets a free `notFound` row with Zillow's suggestions. The matched row has `matchedAddress`, Zillow's own form of the address.

#### Filters

Minimum and maximum price (monthly rent for rentals), minimum bedrooms and bathrooms, home types, **listing kinds** (for sale by owner or FSBO, new construction, coming soon, auction, foreclosure, pre-foreclosure, bank owned, listed by an agent), minimum living area, listed within N days, only homes with a price cut, price cut within N days, and sold within N days (Recently sold). Zillow's search pages show every home, so the filters are applied as the pages are read: a rare kind (auctions) can take many pages for a few homes.

#### Large cities

Zillow shows at most 820 homes per search. With **Split large cities by ZIP code** on (the default), a city with more is read by its ZIP codes, keeping homes whose address is in the city. Counties and neighborhoods aren't split: add their ZIP codes or cities as locations. A big city takes a few minutes: about 3 seconds per 41 homes (all of Austin, TX: 5,667 homes read through 46 ZIP codes in 9 minutes, against Zillow's count of 5,614).

### Tracking changes on a schedule (Zillow monitor)

1. Switch on **Only changes since the last run**. Optionally pick the **Changes to return**.
2. Run it once: the first run returns the homes listed now as `firstRun` (up to Max results) and saves them as the baseline.
3. Schedule it (Apify Console, Schedules). Each later run returns only the changes.

How it decides:

- Each location is read whole (cities by ZIP code), up to **Max homes read per location** (5,000 by default), and every home is compared with the last run.
- A home that disappears is looked up on Zillow's sold list first. If it isn't there, it is reported `removed` only when it is missing two runs in a row; with **Home pages to read**, its own page says at once whether it is sold, pending or off the market.
- Each home's prices are kept as the tracker sees them (the latest 6), so a home cut three times shows all three prices.
- Histories are kept per location, listing type and filters (two trackers with different filters don't mix), in the key-value store `zillow-price-tracker-history`, or one you name in **History name**.
- Only what a run returns moves the history: if Max results or your spending limit stops a run, the changes it didn't return come with the next run. The most important changes come first (sold, price cuts, new listings, back on the market, removed, price increases).

### Alerts in Slack, Discord or Microsoft Teams

Paste an incoming-webhook URL in **Alert webhook URL** (Slack, Discord, Microsoft Teams, or any HTTPS endpoint that takes JSON, such as Zapier, Make or n8n). It switches on Only changes. The first run posts one short "alerts are set up" message; each later run posts its changes (price cuts, new listings, back on the market and sold by default, or those you pick in **Alert on**), up to 50 per run, most important first, each with the home's photo, price move, beds, baths, area and link. The URL is treated as a secret and masked in logs. If posting fails, the run still succeeds and its status says why.

### Run summary for pipelines

Each run saves a `RUN_SUMMARY` record in its key-value store: per location, Zillow's total, homes read, whether it was read whole, ZIP codes read, homes outside the city, median price and homes with a price cut; plus the changes, what didn't load and why, the sold homes without a disclosed price, and the filters used. Every home row also has a one-sentence `summary`, ready for a report, an alert or an AI agent.

### Zillow API: use it from code or from an AI assistant

Start a run and get the rows in one call (replace `<YOUR_TOKEN>`; a call that waits gives up after 5 minutes, so start bigger runs without waiting and read the dataset afterwards):

```bash
curl -X POST "https://api.apify.com/v2/acts/akhil_rajesh~zillow-price-tracker/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"locations": ["78744"], "maxResults": 200, "onlyPriceCuts": true}'
```

Or from Python with `apify-client`:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("akhil_rajesh/zillow-price-tracker").call(run_input={
    "locations": ["Austin, TX"], "maxResults": 500, "maxPrice": 500000, "minBedrooms": 3,
    "priceCutWithinDays": 7, "listingKinds": ["owner", "foreclosure"],
})
for row in client.dataset(run.default_dataset_id).iterate_items():
    print(row["summary"])
```

#### For AI agents: MCP server and live API

The Actor also runs as a **live endpoint** (Apify Standby): an **MCP server** that agents call directly, and plain HTTP endpoints. Once a Standby run is up, a request is answered in seconds; the first request starts one. Authenticate with your Apify API token in the `Authorization: Bearer <token>` header.

**MCP server** (Streamable HTTP): `https://akhil-rajesh--zillow-price-tracker.apify.actor/mcp`

```json
{"mcpServers": {"zillow": {"type": "http", "url": "https://akhil-rajesh--zillow-price-tracker.apify.actor/mcp",
  "headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
```

In Claude Code:

```bash
claude mcp add --transport http zillow https://akhil-rajesh--zillow-price-tracker.apify.actor/mcp --header "Authorization: Bearer <YOUR_APIFY_TOKEN>"
```

A client that can't send headers can use `https://akhil-rajesh--zillow-price-tracker.apify.actor/mcp?token=<YOUR_APIFY_TOKEN>`; keep that URL private, as it carries your token. Through **Apify's MCP server** (`https://mcp.apify.com`, for Claude, ChatGPT, Cursor and other clients), add the tools with `https://mcp.apify.com?tools=akhil_rajesh/zillow-price-tracker` (they appear as `akhil_rajesh--zillow-price-tracker--search_homes` and so on), then ask in plain words, for example *"which 3-bedroom homes under $500,000 in 78744 had a price cut this week?"*. Add them that way rather than through Apify's generic `call-actor` tool, which returns the rows only as text. Apify's MCP server doesn't offer Actors with a live endpoint to agents that pay per call with x402 or Skyfire: connect with an Apify account or API token.

| Tool | What it returns |
|---|---|
| `search_homes` | Homes for sale, sold or for rent in up to 3 locations, with price, latest cut and its date, days on Zillow, beds, baths, area, price per sq ft, price against the Zestimate and a one-line summary; filters on price, beds, baths, type, listing kind, area, days listed |
| `find_price_cuts` | Homes whose latest price change was a cut, within N days (7 by default), with the cut's amount, date and percentage |
| `get_homes` | Homes read from their own pages by street address, link or zpid: status, description, year built, HOA, agent, all photos |
| `run_actor` | The Actor's whole input in one call |

**HTTP endpoints**, such as `GET https://akhil-rajesh--zillow-price-tracker.apify.actor/homes?locations=Austin, TX|78744&max=100&maxPrice=500000` (separate several locations or homes with `|`, since a city's name has a comma; defaults in brackets). The Actor's **Endpoints** tab in Apify Console lists them too, and lets you try them.

| Endpoint | Parameters |
|---|---|
| `GET /homes` | `locations`, `type` (forSale, sold, forRent), `max` (100), `minPrice`, `maxPrice`, `minBeds`, `minBaths`, `homeTypes`, `kinds`, `minSqft`, `maxDays`, `priceCuts`, `cutWithinDays`, `soldWithinDays`, `homePages` (0) |
| `GET /price-cuts` | `locations`, `type` (forSale, forRent), `withinDays` (7), `max` (100), `minPrice`, `maxPrice`, `minBeds`, `homeTypes`, `kinds` |
| `GET /home` | `homes` (street addresses, links or zpids) |
| `POST /run` | The Actor's whole input as the JSON body |

**Answers** carry the `rows`, `rowsByType`, `notFound` (locations, homes or addresses Zillow doesn't know: free), `notLoaded` (what Zillow didn't answer), `notRead` (what a limit left out: not charged) and `notes`. A request that reads nothing gets an `error` and nothing is charged: HTTP 400 for an argument it can't read (a tool error over MCP), 503 when Zillow didn't answer or the run was busy (send it again), 402 when your spending limit for the run is reached (it lifts when the run ends, after 2 minutes without requests). A 503 can also carry rows, when the platform stopped the run while a request was being read: those were stored and charged, and `notRead` names the rest.

**Limits per request**: an MCP tool call reads up to 3 locations and 200 homes, about 350 kB of rows, within 50 seconds, and asks for 50 homes unless told otherwise (MCP clients stop waiting at 60 seconds, and Apify's MCP server drops answers over about 1 MB); an HTTP request reads up to 10 locations, 2,000 homes and about 6 MB within 170 seconds. Zillow serves about 41 homes every 3 seconds. Home pages are limited: the endpoint reads about 20 at a time. What a limit leaves out is named in `notRead` and isn't charged. **A request that has started runs to its end even if you stop waiting**: Apify's Standby proxy keeps it open, so its rows are read and charged. Ask for what you need. Tracking (Only changes) and alerts belong to scheduled runs: the live endpoint answers each request on its own, so it ignores those fields.

### How much does it cost?

You pay **$1.00 per 1,000 homes**, less on paid Apify plans, plus a start fee of $0.00005 per run. **Platform usage is included** in runs of the Actor: there is no compute charge on top. Home pages and address lookups are included in the home's price. Not-found rows are free, and so are sold homes whose state doesn't disclose the sale price (`priceDisclosed: false`). With Only changes you pay only for the changes returned. The live endpoint (MCP server and HTTP API) charges homes at the same prices, plus the Standby run's platform usage while it serves you and until it has been idle for 2 minutes (a short session costs a fraction of a cent).

| Apify plan | Per 1,000 homes |
|---|---|
| Free | $1.00 |
| Starter | $0.90 |
| Scale | $0.80 |
| Business and above | $0.70 |

| Run | Homes | Cost (Free plan) |
|---|---|---|
| One ZIP code's homes for sale (about 300) | 300 | about $0.30 |
| Every home for sale in Austin, TX (about 5,600) | 5,600 | about $5.60 |
| A daily tracker of 3 ZIP codes, about 25 changes a day | 25 | about $0.025 a day |
| A city's 1,000 most recently sold homes (a disclosure state) | 1,000 | about $1.00 |
| 20 homes looked up by address | 20 | about $0.02 |

Apify's free plan ($5 of monthly credit) covers about 5,000 homes. To cap spending, lower Max results or set a maximum cost per run in the run options; the Actor stops cleanly at the limit (and with Only changes, the rest comes with the next run).

### Good to know

- **Sold prices**: Zillow doesn't show sale prices in non-disclosure states (Texas, Utah and others). Those sold homes come with their sale date, `priceDisclosed: false`, and no charge.
- **Speed**: about 3 seconds per search page of 41 homes. Tracking a big city reads it whole each run: Austin (about 5,600 homes, 46 ZIP codes) took 9 minutes, Denver (about 3,900 homes) about 7.
- **Home pages**: up to 20 a run, addresses included; Zillow refuses a visitor's home pages after about 26, and the Actor stops at the first refusal and says so.
- **Zillow's own limits**: a run that meets Zillow's bot check asks again a few times, then fails without charging; run it again later.
- **What isn't read**: Zillow's filtered links, its search API and its price-history requests are disallowed by its robots.txt, so this Actor doesn't use them. Price history comes from your tracker's own runs (`trackedPrices`) and from home pages that show it.
- **Agents' contact details**: home pages give the listing agent's name and the brokerage's phone; agents' personal phone numbers and emails aren't collected.

### FAQ

**Can it monitor a whole city on Zillow?** Yes: switch on Only changes and schedule it. A city over 820 homes is read by its ZIP codes; the run summary says how many homes it read of Zillow's total.

**Can I get only new listings since the last run?** Yes: Only changes with Changes to return set to New listings. Each new home comes once.

**How do I get only this week's price drops?** Set Price cut within (days) to 7, without Only changes; or use Only changes on a schedule to get each cut once, as it happens.

**Does it give a home's price history?** Each change row has `trackedPrices`, every price your tracker saw for the home. Zillow's own history is in its price-history requests, which its robots.txt disallows, so it comes only where a home's page shows it.

**Can it post price drops to Slack?** Yes: paste a Slack incoming webhook in Alert webhook URL and schedule the run. Discord, Microsoft Teams and any JSON webhook work the same way.

**Can I scrape Zillow FSBO (for sale by owner) homes or foreclosures?** Yes: pick them in Listing kinds. Zillow's own marks are used (for sale by owner, foreclosure, pre-foreclosure, bank owned, auction, new construction, coming soon).

**Can I look up a home by its address?** Yes: put the address in Homes, with its city and state or ZIP code. It is matched to exactly one Zillow home, or answered as not found (free) with Zillow's suggestions.

**Does it work for rentals?** Yes: pick For rent. Buildings come with their rent range and units, single homes with their rent, and Only changes reports rent drops and new rentals.

**Do I need a proxy?** No: Zillow answers Apify's servers directly. You can use your own proxies; Apify's residential proxies aren't available in this Actor, as they're billed per GB on top of the result price.

**Is it legal?** The Actor reads public listing pages that Zillow's robots.txt allows, at a modest pace, without logging in. Use the data in line with Zillow's terms and the laws that apply to you.

### Other Actors by this developer

- [Amazon.ca Product & Trending Tracker](https://apify.com/akhil_rajesh/amazon-ca-product-trending-tracker): Amazon Best Sellers, prices, search positions and reviews on 23 marketplaces, with change tracking
- [AliExpress Price Tracker & Scraper](https://apify.com/akhil_rajesh/aliexpress-price-tracker): AliExpress search results with store prices, units sold and price history
- [Google Hotels Scraper](https://apify.com/akhil_rajesh/google-hotels-scraper): hotel prices by date with booking sites, and price tracking
- [Yahoo Finance Scraper, API & MCP](https://apify.com/akhil_rajesh/yahoo-finance-scraper): quotes, history, options, financials and more

### Disclaimer

This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by Zillow. It reads publicly available listing pages at a modest pace. Use the data in line with Zillow's terms and the laws that apply to you.

# Actor input Schema

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

Where to read homes: a city and state (Austin, TX), a ZIP code (78744), a county (Travis County, TX), a neighborhood (Mueller, Austin, TX), or a Zillow search page link (zillow.com/austin-tx/). A link's own filters aren't read: use the filters below.

## `homes` (type: `array`):

Specific homes to read from their own pages: Zillow home links (zillow.com/homedetails/.../12345678_zpid/), zpids, or street addresses with the city and state or ZIP code ('2433 Calle Moreno, Brownsville, TX 78521'). An address is matched to exactly one Zillow home, or answered as not found (free) with Zillow's suggestions. Up to 20 a run (Zillow refuses a visitor's home pages after about 26): price, status, Zestimate, description, year built, HOA fee, agent, MLS id, views and all photos.

## `listingTypes` (type: `array`):

For sale, recently sold, or for rent. Each location is searched for each type picked.

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

Most homes (rows) a run returns, shared between locations. With Only changes: most changes a run returns (the most important first; the rest come with the next run).

## `onlyChanges` (type: `boolean`):

Track your locations: each run returns only what changed since the last run with the same locations and filters (new listings, price cuts and increases, homes back on the market, sold, pending or removed). The first run saves the homes listed now as the baseline and returns them as firstRun. Each location is read whole (cities over Zillow's 820 by ZIP code) so no change is missed.

## `changeTypes` (type: `array`):

Which changes Only changes returns. Leave empty for all.

## `alertWebhookUrl` (type: `string`):

Post each run's changes to Slack, Discord or Microsoft Teams (their incoming-webhook URL), or to any HTTPS endpoint that takes JSON (Zapier, Make, n8n). Switches on Only changes. The first run posts a short 'alerts are set up' message.

## `alertChangeTypes` (type: `array`):

Which changes are posted. Leave empty for price cuts, new listings, homes back on the market and sold homes.

## `historyName` (type: `string`):

Keep a separate history for this tracker (a-z, 0-9 and hyphens). Leave empty to share the default one: histories are kept per location, listing type and filters anyway.

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

Leave empty or 0 for no minimum. For rentals: monthly rent.

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

Leave empty or 0 for no maximum. For rentals: monthly rent.

## `minBedrooms` (type: `integer`):

Leave empty or 0 for any.

## `minBathrooms` (type: `integer`):

Leave empty or 0 for any.

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

Leave empty for every type.

## `listingKinds` (type: `array`):

Only these kinds of homes for sale, as Zillow marks them. Leave empty for every kind. The whole place is read and the kinds picked out, so a rare kind (auction, foreclosure) can take many pages for a few homes.

## `minLivingAreaSqft` (type: `integer`):

Leave empty or 0 for any size.

## `maxDaysOnZillow` (type: `integer`):

Only homes listed on Zillow at most this many days ago. Leave empty or 0 for any.

## `onlyPriceCuts` (type: `boolean`):

Only homes whose latest price change on Zillow was a cut (with its amount and date).

## `priceCutWithinDays` (type: `integer`):

Only homes whose latest price cut on Zillow was at most this many days ago (7: cut in the last week). Leave empty or 0 for any.

## `soldWithinDays` (type: `integer`):

For the Recently sold listing type: only homes sold at most this many days ago. Leave empty for all Zillow lists.

## `maxHomeDetails` (type: `integer`):

Read each home's own page for this many homes per run (at most 20: Zillow refuses a visitor's home pages after about 26): description, year built, HOA fee, tax rate, price per sq ft, agent and brokerage, MLS id, views and saves, and all photos. With Only changes, homes that left a search are checked first (sold, pending or off the market).

## `splitLargeAreas` (type: `boolean`):

Zillow shows at most 820 homes per search. A city with more is read by its ZIP codes (homes whose address is in the city), so every home can be read and tracked. Off: a city's first 820 only.

## `maxHomesPerLocation` (type: `integer`):

With Only changes, each location is read whole up to this many homes. A larger city takes about 3 seconds per 41 homes.

## `proxy` (type: `object`):

Not needed: Zillow answers Apify's servers directly. You can use your own proxies; residential proxies aren't available in this Actor.

## Actor input object example

```json
{
  "locations": [
    "Austin, TX"
  ],
  "listingTypes": [
    "forSale"
  ],
  "maxResults": 100,
  "maxHomeDetails": 0,
  "splitLargeAreas": true,
  "maxHomesPerLocation": 5000
}
```

# Actor output Schema

## `homes` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `investor` (type: `string`):

No description

## `sold` (type: `string`):

No description

## `rentals` (type: `string`):

No description

## `details` (type: `string`):

No description

## `notFound` (type: `string`):

No description

## `allData` (type: `string`):

No description

## `runSummary` (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": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("akhil_rajesh/zillow-price-tracker").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": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("akhil_rajesh/zillow-price-tracker").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": 100
}' |
apify call akhil_rajesh/zillow-price-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,akhil_rajesh/zillow-price-tracker"
        }
    }
}
```

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/VH57n9Ce9kSNImmXC/builds/5Rl90VsThxjUs4U5H/openapi.json
