Zillow Listings Scraper & Price Intelligence avatar

Zillow Listings Scraper & Price Intelligence

Pricing

$2.00 / 1,000 listings

Go to Apify Store
Zillow Listings Scraper & Price Intelligence

Zillow Listings Scraper & Price Intelligence

Scrape current Zillow for-sale listings and compare price per sqft, Zestimate delta, and days on market against transparent active-listing comparables.

Pricing

$2.00 / 1,000 listings

Rating

0.0

(0)

Developer

Zapticx

Zapticx

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Scrape current Zillow for-sale listings and turn them into a practical read on pricing, not just a row dump. Every listing comes back with a price-per-sqft percentile against comparable nearby homes, a Zestimate delta, a days-on-market signal, and a confidence score — so you can tell a priced-right listing from an overpriced one at a glance.

This Actor keeps observed source data separate from Actor-derived intelligence, so you get usable benchmarks without opaque claims about occupancy, appreciation, or investment returns.

What "comparable" means here: the comparable set is the collected population of active Zillow for-sale listings matching the same ZIP/home type/bedroom segment — not a broker CMA, an appraisal, or an analysis of verified closed sales. Treat the intelligence output as a market-rate read against current asking prices, not a substitute for professional valuation.

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Zillow Group, Inc. "Zillow" and "Zestimate" are trademarks of Zillow, Inc.

Quick start

  1. Type a market into LocationMiami Beach, FL, 33139, or Austin, TX.
  2. Optionally set Number of listings (default 100, max 820).
  3. Click Start.

That is the whole basic path. A 100-listing run finishes in about 10 seconds and costs $0.20. Everything else on the form is optional.

{ "location": "Miami Beach, FL", "maxResults": 100 }

What this Actor does

Zillow search → normalized listings → comparable-set selection → price/Zestimate/DOM intelligence → market summary

Provide a location (or a Zillow search-results URL) and optional price/bed/bath/home-type filters. The Actor collects up to 820 unique listings — Zillow's own per-search cap — selects a comparable set for each one (same ZIP + home type + bedroom count, falling back to looser tiers when that's too small), and scores it against that set. A market_summary record with aggregate pricing, coverage, and distribution stats for the whole run is written to the key-value store (not the dataset — see Output below).

Why use it?

Most Zillow scrapers stop at rows of listing data. This Actor also answers practical questions:

  • Is this listing priced below, near, or above comparable homes nearby?
  • How far off is the list price from Zillow's own Zestimate?
  • Is it moving faster or slower than similar listings?
  • How large and specific was the comparable sample, and how much should you trust it?

The methodology is deterministic and documented below. Missing evidence stays null with a reason code instead of being guessed or silently dropped.

Key features

  • Location or direct Zillow search-URL input, with server-side price/bed/bath/home-type filters
  • Normalized address, pricing, size, and listing-status fields
  • Price-per-sqft percentile and delta-from-median against a selected comparable set
  • Plain-language price position: budget, below market, market, above market, or premium
  • Zestimate delta (independent of comparable-set size — shown whenever a Zestimate exists)
  • Days-on-market delta versus the comparable set's median
  • Comparable-set tiers based on ZIP + home type + bedrooms, with transparent fallback
  • Per-listing and market-wide confidence scoring with reason codes
  • No per-property detail-page fetches needed — the full intelligence layer comes from one search request per ~41 listings, keeping cost low
  • Explicit limitations and transparent null handling
  • Apify datasets ready for JSON, CSV, Excel, APIs, and automation workflows

Who is it for?

Real-estate investors and flippers doing comps, agents and brokers pricing a listing, short-term and long-term rental analysts, buyers sanity-checking a price, and researchers or agencies building market snapshots.

Common uses: "is this listing overpriced" checks, comp-set research for an offer, market pricing snapshots by ZIP or neighborhood, and feeding a normalized dataset into a BI tool or spreadsheet.

Data source

Zillow's public "GetSearchResults" API (and its siblings GetZestimate/GetComps) was permanently shut down on September 30, 2021 — no waiting list, no new keys issued. The only official successor is Bridge Interactive, an enterprise RESO Web API restricted to MLS-affiliated brokerages and approved proptech partners, with a weeks-to-months approval process; it is not available to an individual developer building a Store actor. This Actor instead reads the same structured __NEXT_DATA__ JSON payload Zillow's own search page embeds and renders client-side — verified against the live site, not assumed — using the already-published, publicly-served page data rather than any authenticated or gated endpoint.

Input

FieldRequiredDescription
locationOne search inputCity, state, ZIP, county, or neighborhood — e.g. Miami Beach, FL, 33139, Wynwood, Miami, FL. Use exactly one of location, searchUrl, or targetUrl.
maxResultsNoUnique listing cap, 1–820; default 100. Zillow caps a single search around 820 total.
listingTypeNoFor-sale listings only in this version; for_sale is the only value.
searchUrlOne search inputA full zillow.com search-results URL used instead of location, for filters this Actor does not expose.
targetUrlOne search inputA single zillow.com/homedetails/... listing URL. Fetches just that one property — no search, no comparable-set intelligence, no market_summary — as one target_listing record. Adds three fields search results never carry: yearBuilt, monthlyHoaFee, and propertyTaxRate (all real observed data, only present when Zillow publishes them).

Filters (optional)

FieldRequiredDescription
homeTypesNoRestrict to specific home types. Leave empty for all.
priceMin / priceMaxNoList-price range in USD.
bedsMin / bathsMinNoMinimum bedrooms / bathrooms.

Filters are applied by Zillow before results come back, so they also define the comparable population every percentile is measured against — see Sample-selection bias.

Advanced

FieldRequiredDescription
proxyConfigurationNoApify Proxy; used only as a retry fallback after a direct attempt.

Example inputs

Quick market scan (defaults only)

{
"location": "Miami Beach, FL"
}

Condo comps in a price band

{
"location": "Miami Beach, FL",
"homeTypes": ["CONDO"],
"priceMin": 300000,
"priceMax": 1500000,
"maxResults": 100
}

Family homes, 3+ beds, larger sample

{
"location": "Austin, TX",
"homeTypes": ["SINGLE_FAMILY"],
"bedsMin": 3,
"maxResults": 300
}

Output

  • Default dataset — one row per normalized listing, each with its intelligence block. The dataset holds only listings, deliberately: Apify's dataset views project fields but don't filter rows by record type, so mixing record types into one dataset means every view shows blank rows for whichever type it wasn't built for (verified directly against a live run's ?view= output, not assumed). Splitting the output this way keeps the "Listing intelligence" and "All fields" dataset views fully clean.
  • market_summary — one aggregate record per run (pricing, coverage, distributions, comparison quality, limitations), written to the run's key-value store under the key MARKET_SUMMARY instead of the dataset. Fetch it via the Actor run's output link, the Console's key-value store viewer, or GET /v2/key-value-stores/{storeId}/records/MARKET_SUMMARY.

Abbreviated, real examples (pulled from a live run, not fabricated) are included with the repository in examples/outputs.

{
"recordType": "listing",
"zpid": "43885671",
"address": "5005 Collins Ave APT 424, Miami Beach, FL 33140",
"homeType": "CONDO",
"price": 399000.0,
"pricePerSqft": 295.56,
"livingAreaSqft": 1350.0,
"bedrooms": 2.0,
"bathrooms": 2.0,
"zestimate": 378900.0,
"daysOnZillow": 17,
"intelligence": {
"pricePerSqftPercentile": 23.33,
"pricePerSqftDeltaFromMedianPercent": -33.05,
"pricePosition": "below_market",
"zestimateDeltaPercent": 5.3,
"daysOnMarketDeltaFromMedian": 0.0,
"comparableSampleSize": 15,
"comparableTier": "market",
"confidence": "medium"
}
}

Field availability

Zillow publishes different data on search results than on a property's own detail page. Nothing here is inferred or filled in — a field Zillow does not publish stays null.

FieldSearch runs (location / searchUrl)Single-property runs (targetUrl)
Address, geo, price, beds, baths, sqft, home type, status, days on Zillow, broker, imageAlwaysAlways
pricePerSqft (derived)Whenever price and living area are both publishedSame
taxAssessedValueNearly alwaysAlways
lotAreaValue / lotAreaUnitAbout half of listingsWhen published
zestimate, rentZestimateAbout a third of listingsWhen published
priceChange, datePriceChanged, priceReductionAbout a quarter to a third of listingsWhen published
yearBuilt, monthlyHoaFee, propertyTaxRateNever — Zillow's search payload does not carry themWhen published
intelligence blockAlwaysNot applicable (sample of one)

Coverage percentages are what a real Miami Beach run returns; they vary by market. Every run's market_summary reports its own exact coverage, and each listing's unavailableReasons names the specific cause of any missing metric.

Understanding the intelligence

  • Price-per-sqft percentile ranks the listing's midpoint within its comparable sample, 0–100. Lower means cheaper per square foot relative to comparables.
  • Price-per-sqft delta from median shows the dollar and percentage difference from that sample's median $/sqft.
  • Price position maps percentile bands to a readable label from budget to premium.
  • Zestimate delta is the list price versus Zillow's own automated estimate — positive means listed above Zestimate. This is computed directly from the listing's own data, so unlike the other intelligence fields it does not depend on comparable-sample size or confidence.
  • Days-on-market delta compares the listing's daysOnZillow to its comparable set's median.
  • Comparable tier says exactly how the sample was selected (see below).
  • Confidence summarizes sample size and coverage. Reason codes explain every label and every suppressed/unavailable metric — nothing is silently guessed.

Methodology in brief

Price-per-sqft percentile uses a tie-aware midpoint rank: 100 × (comparables below + 0.5 × comparables equal) / sample size. Price-position bands are 0–20 budget, 20–40 below market, 40–60 market, 60–80 above market, and 80–100 premium. Price-relative metrics require at least 8 eligible comparables; below that, they're null with an unavailableReasons entry rather than a low-confidence guess.

How comparable listings are selected

The Actor tries the most specific viable segment first:

ZIP + home type + bedrooms → ZIP + home type → ZIP → the full collected market

Each tier needs at least 8 eligible listings (valid price and living area). The subject listing is excluded from its own sample. Confidence bands: insufficient (<8 comparables), low (8–14), medium (15–29), high (30+ with ≥70% price coverage and a segmented tier).

Sample-selection bias

The comparable population is your collected run, not the whole Zillow market. Your own priceMin/priceMax/bedsMin/bathsMin/homeTypes filters, maxResults, and Zillow's relevance-based result ordering all shape which listings end up in the comparable pool. A run filtered to $300k–$500k will not produce a percentile meaningful for a $1.2M property, and a market-tier fallback (broad, unsegmented) is a materially weaker signal than a zip_type_beds-tier match — that's exactly what comparableTier and confidence are for. Wider filters and larger maxResults generally produce a more representative comparable pool.

Market summary

The market_summary record (in the key-value store — see Output) is one aggregate view of the whole run:

GroupContents
marketThe location or search URL requested, plus every filter that shaped the sample — homeTypesFilter, priceMinFilter, priceMaxFilter, bedsMinFilter, bathsMinFilter, maxResultsRequested.
pricinglistingCount; asking-price min/max/average/median; price-per-sqft min/max/average/median/P25/P75; median days on Zillow.
distributionsPrice-per-sqft quartile counts, home-type counts, bedroom counts, each with its own coverage percentage.
coverageListings collected vs. analyzed, Zestimate coverage, duplicates removed, whether the sample was truncated, and a breakdown of why any listing was excluded from pricing.
comparisonQualityOverall confidence, comparable sample size, coverage rates, reason codes, and how many listings matched each comparable tier.
limitationsExplicit coded caveats for the run — truncation, low coverage, small sample, unknown home types, missing living area.

Every statistic states the sample it was computed from. The three sample sizes are published alongside the numbers, because they differ on purpose:

  • pricePerSqftSampleSize — listings with both a price and a positive living area.
  • priceSampleSize — every listing with a price. A lot with no square footage still has a real asking price, so excluding it from a price median would bias that median toward listings that happen to publish square footage.
  • daysOnZillowSampleSize — listings that reported a days-on-market figure.

Duplicates are removed before any of this is computed, and listings with a missing or non-positive price-per-sqft are excluded from the *PricePerSqft family with the reason recorded in coverage.pricingExclusionReasons rather than being silently counted as zero.

Note that averagePricePerSqft is sensitive to outliers in luxury markets — a single ultra-premium listing can pull it well above medianPricePerSqft. Both are published so you can see the skew rather than having one of them chosen for you.

Data quality and limitations

  • Results are a collected Zillow search sample, not complete market coverage.
  • For-sale listings only in this version; rentals are a planned fast-follow using the same comparable-set architecture.
  • Zillow caps a single search at roughly 820 reachable results — for larger markets, run multiple narrower searches (split by ZIP or price band) rather than one broad one.
  • Price-per-sqft and Zestimate coverage vary by listing; sparse or ultra-luxury listings often lack a Zestimate, and the Actor reports that explicitly rather than guessing.
  • Single-property (targetUrl) runs return the property's full observed detail data, but no comparable-set intelligence and no market_summary — there is nothing to rank a sample of one against. To benchmark a specific home, run a search over its ZIP and find it in the results.
  • Zillow's public page structure is theirs to change; provenance fields and null-handling reduce the impact but don't remove it.

Use it from your own code

Results are ordinary Apify datasets and key-value stores, so anything that speaks HTTP can read them. No proprietary dashboard, no export step.

Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("zapticx/zillow-market-intelligence").call(
run_input={"location": "Miami Beach, FL", "maxResults": 100}
)
for listing in client.dataset(run["defaultDatasetId"]).iterate_items():
print(listing["address"], listing["price"], listing["intelligence"]["pricePosition"])
summary = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("MARKET_SUMMARY")
print(summary["value"]["pricing"]["medianPricePerSqft"])

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('zapticx/zillow-market-intelligence').call({
location: 'Miami Beach, FL',
maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const summary = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('MARKET_SUMMARY');
console.log(items.length, summary.value.pricing.medianPricePerSqft);

cURL

$curl -X POST "https://api.apify.com/v2/acts/zapticx~zillow-market-intelligence/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" -H "Content-Type: application/json" -d '{"location":"Miami Beach, FL","maxResults":100}'

The market_summary for any finished run is a single GET:

$curl "https://api.apify.com/v2/actor-runs/<RUN_ID>/key-value-store/records/MARKET_SUMMARY?token=<YOUR_APIFY_TOKEN>"

No-code

Use the Apify integrations for Make, n8n, Zapier, Google Sheets, Airtable, Slack, or a plain webhook. Common patterns: a scheduled weekly market snapshot appended to a sheet, a webhook that alerts you when a listing appears below its comparable median, or a nightly pull into a BI tool.

Performance

Measured directly on the Apify platform, not estimated:

  • 100-listing default run: ~9.5–10.2 seconds, ~52–60MB peak memory, zero retries, no proxy traffic needed (direct HTTP succeeds first in the large majority of runs).
  • Full maxResults: 820 run: 21.3 seconds, ~69MB peak memory. An earlier version of this run took 82 seconds — batching the dataset writes (instead of one network round-trip per listing) cut that by ~4×; see the Changelog.
  • Zero-result searches (e.g. an impossibly narrow price band) complete cleanly with a market_summary record and no crash.
  • Verified working: location input, direct searchUrl input, ZIP-code locations, and multiple homeTypes filters (CONDO, SINGLE_FAMILY).

Pricing

Pay-per-event: $2.00 per 1,000 listings ($0.002 per unique listing successfully written). That is the only charge — there is no Actor-start fee, no per-run minimum, and no charge for a run that returns nothing. market_summary lives in the key-value store, not the dataset, so it was never a chargeable dataset item in the first place — no separate charge, no ambiguity. Duplicates are removed before billing, so you are never charged twice for the same zpid.

  • 100 listings: ~$0.20 total
  • 300 listings: ~$0.60 total
  • 820 listings (max): ~$1.64 total

This matches the pricing model of this account's airbnb-market-intelligence Actor and undercuts or matches raw-extraction-only competitors on the Zillow side of the Store ($0.0009–$0.0036 per listing), while being the only option in that comparison set that also computes price intelligence.

Troubleshooting

Run fails immediately with a validation error. Check that you provided exactly one of location, searchUrl, or targetUrl, and that priceMax ≥ priceMin if both are set. The error message names the exact field.

Run succeeds but returns 0 listings. The location may be too narrow (a specific address instead of a city/ZIP/neighborhood) or your filters may be too restrictive for that area — try widening priceMin/priceMax or clearing homeTypes/bedsMin/bathsMin.

comparableTier is always market and confidence stays low/insufficient. Your comparable pool isn't reaching the 8-listing floor for a tighter ZIP/type/bedroom segment — raise maxResults, widen filters, or expect a broad-market read for very narrow searches.

Run fails or returns unusually little data. Zillow occasionally changes its page structure or serves a block page. The Actor retries automatically and treats direct HTTP as primary with Apify Proxy as a fallback; if it still fails, check the run log for the specific error — a ParseError means the page shape changed and needs a code update, while a BlockedResponseError means proxy traffic is warranted for that run.

Zestimate or price-per-sqft is null for most listings. This is usually real: Zillow doesn't publish a Zestimate for every listing (ultra-luxury and some off-market-style listings often lack one), and price-per-sqft needs a living-area figure the listing may not expose. Check unavailableReasons on the listing for the specific cause rather than assuming a bug.

FAQ

Do I need to provide filters?

No. location alone is enough — every other field has a sensible default and the Actor will return a broad market scan.

What does a price-per-sqft percentile of 20 mean?

It's a rank, not a percentage difference. A listing at the 20th percentile is cheaper per square foot than roughly 20% of its comparable set. Use pricePerSqftDeltaFromMedianPercent for the actual percentage difference from the median.

Why is zestimateDeltaPercent null for some listings?

Zillow doesn't publish a Zestimate for every listing — ultra-luxury and off-market-style listings often lack one. The Actor reports this explicitly via unavailableReasons rather than guessing.

Why is my comparable sample size small?

Small or very specific searches (a rare home type, a tight price band, a small ZIP) may not reach the 8-comparable floor for price-relative metrics. Widen homeTypes/priceMin/priceMax or drop bedsMin/bathsMin, or increase maxResults.

Does this predict future value or investment returns?

No. It reports observed public listing data and deterministic comparative metrics only — no appreciation, rental-yield, or return projections.

Can I search for rentals?

Not in this version. listingType currently only supports for_sale; rentals are a planned addition using the same architecture.

Support

Found a bug, hit a market that behaves oddly, or need a field this Actor does not yet extract? Open an issue on the Actor's Issues tab in Apify Console — that is the fastest route and it is monitored. Include the run ID; it carries the exact input, log, and output needed to diagnose the problem.

Feature requests are welcome, particularly around rentals, sold comparables, and additional detail-page fields.