Zillow Scraper: Listings, Prices & Zestimates

A working Zillow scraper: pull listings, prices, and beds from Zillow's JSON-LD for free, plus robots rules, ToS limits, and the Zestimate gap.

MMotherlode Lab9 min read
Magpie title card: Zillow Scraper: Listings, Prices & Zestimates

Zillow hides the listing prices from your scraper and then hands them to you in structured data on the same page. I pulled 41 San Francisco listings with prices, beds, square footage, and coordinates in one robots-respecting request. Minutes later, a second render of a detail page came back empty. That is Zillow in two sentences: generous once, touchy twice.

A zillow scraper that minds robots.txt can still pull listings, prices, and coordinates off the city pages and turn them into a CSV with one command. Fair warning up front: Zestimates do not come back in a static scrape, and Zillow walls off heavy use. Both limits get their own sections, because both will bite you.

What a Zillow scraper can pull (tested 2026-10-16)

Everything below comes from a live run on October 16, 2026, from a home connection, using Magpie in default static mode. No login is involved at any point; Zillow accounts matter only for saved searches. Sites change; re-test before you build on this.

The city search page returned a 17,433-character markdown record plus 38 JSON-LD blocks (JSON-LD is the machine-readable metadata sites embed for search engines). One of those blocks is an ItemList with 41 listing entries, and every single one carries the full payload: address, price in USD, bedrooms, square footage, latitude, longitude, and the canonical homedetails URL. The visible page text has zero prices. The data is all in the structured block, which is good news: you parse one JSON object instead of fighting CSS.

Property detail pages work too. Scraping the /homedetails/ page for one of those 41 listings returned the MLS number, the agent and brokerage, the listing description, price history, and a second RealEstateListing JSON-LD block with the same fields as the search entry.

What you will not find in either: the Zestimate. More on that below, because it changes which tool you should pick.

robots.txt, ToS, and the API Zillow closed

Read this section before you run anything. Zillow is not a scrape-friendly site that forgot to lock the door. It is a locked site with a few doors marked open.

robots.txt is an allowlist. Zillow’s robots.txt starts with 40-odd Allow: lines for specific search paths, then follows with Disallow: /homes/, Disallow: /api/, and hundreds of narrower rules. Under the longest-match rule, /homes/for_sale/ is allowed despite the broader disallow, and so are its *_p/ pagination pages. City pages like /san-francisco-ca/ match nothing on the disallow list, so they are clean. Standard /homedetails/<address>/<zpid>/ pages are clean too; only specific variants (view=owner, rental-manager resources) are off-limits.

The file also lists sitemap indexes for sale, sold, and rental listings, a legitimate source of URLs if you need coverage instead of a sample.

The Terms of Use say no. Zillow’s terms state that you may not “use any robot, spider, scraper or other automated means to access the Services” without express written permission. Scraping Zillow therefore breaches the site contract even when the specific page is robots-allowed. Public facts are not copyrightable in the US, and courts have limited how far automated-access claims reach, but I am not your lawyer and this is not legal advice. If you are weighing a commercial project, get a real opinion.

They enforce it. When I fetched Zillow’s own Terms page with curl for this article, it came back as a PerimeterX challenge: “Press & Hold to confirm you are a human.” The bot wall guards even the legal text. The 2026-10-16 test above worked from a home connection at polite volume; the same session’s follow-up browser render got refused. Zillow blocks heavy use. There is no configuration that makes bulk scraping safe, only slower ways to get blocked.

There is no official API to fall back on. Zillow retired its public Web Services API (the old ZWSID keys) on September 30, 2021. Bridge Interactive, the Zillow Group program that replaced it, serves MLS-affiliated brokerages and partners, not the general public, and does not expose the Zestimate. ZTRAX, the transaction and assessment database, was discontinued in 2023. Zillow’s mortgage-rates API still exists but carries no listing data.

Scrape Zillow with Magpie, step by step

Magpie is a local Go binary: fetch, clean, extract, no API key, and it respects robots.txt by design. It suits this job because Zillow’s data is already structured: Magpie’s scrape returns the JSON-LD sidecar alongside the cleaned text, and that sidecar is where all the prices live.

Free zillow scraper: build it from source

Magpie is free to use locally (AGPL-3.0-or-later, dual-licensed with a commercial option). Building takes two commands:

git clone https://github.com/motherlodelab/magpie.git
cd magpie && go build -o magpie ./cmd/magpie

You need Go installed; no other dependencies, no database setup, no account.

Pull the search page

magpie scrape "https://www.zillow.com/san-francisco-ca/" \
  --page-format markdown --format json --out zillow-sf.json

The record comes back as JSON (abridged):

{
  "url": "https://www.zillow.com/san-francisco-ca/",
  "title": "San Francisco CA Real Estate - San Francisco CA Homes For Sale | Zillow",
  "markdown": "…17,433 chars of cleaned page text, no prices…",
  "structured_data": [ "…38 JSON-LD blocks, incl. one ItemList with 41 listings…" ]
}

If the JSON record came back with an empty or stub title, Zillow served you a wall page instead of the search results. Do not retry in a loop; that is how one blocked request becomes a blocked IP. Wait a day, or move to the third-party options below.

Build the zillow data scraper: JSON-LD in, CSV out

The search record is one Python file away from a spreadsheet. This flattens every ItemList entry into rows (stdlib only):

#!/usr/bin/env python3
"""Flatten Magpie's Zillow JSON-LD to CSV. Usage: zillow_to_csv.py <record.json>"""
import csv, json, sys

rec = json.load(open(sys.argv[1]))
items = []
for block in rec.get("structured_data", []):
    if block.get("@type") != "ItemList":
        continue
    for el in block.get("itemListElement", []):
        it = el.get("item", {})
        off = it.get("offers", {})
        res = off.get("itemOffered", {})
        addr = res.get("address", {})
        geo = res.get("geo", {})
        items.append({
            "address": it.get("name", ""),
            "price": off.get("price", ""),
            "currency": off.get("priceCurrency", ""),
            "beds": res.get("numberOfBedrooms", ""),
            "sqft": res.get("floorSize", {}).get("value", ""),
            "city": addr.get("addressLocality", ""),
            "state": addr.get("addressRegion", ""),
            "zip": addr.get("postalCode", ""),
            "lat": geo.get("latitude", ""),
            "lon": geo.get("longitude", ""),
            "url": it.get("url", ""),
        })

if not items:
    sys.exit("no ItemList found (did Zillow serve a wall page?)")

w = csv.DictWriter(sys.stdout, fieldnames=list(items[0].keys()))
w.writeheader()
w.writerows(items)

Run it against the scrape output:

python3 zillow_to_csv.py zillow-sf.json > listings.csv

First rows (abridged, 41 rows in my run):

address,price,currency,beds,sqft,city,state,zip,lat,lon,url
"2070 46th Ave, San Francisco, CA 94116",1495000,USD,3,1564,San Francisco,CA,94116,37.747936,-122.50472,https://www.zillow.com/homedetails/...

Every cell lands typed and empty-free because it comes from Zillow’s own feed, not from CSS selectors that rot on the next redesign. If you want a deeper treatment of the export side (headers, encoding, spreadsheets that mangle ZIP codes), the scrape-to-CSV guide covers it.

Detail pages: the listing behind the card

magpie scrape "https://www.zillow.com/homedetails/2070-46th-Ave-San-Francisco-CA-94116/15116574_zpid/" \
  --page-format markdown --format json --out listing.json

My run returned 824 words of cleaned content: the listing description, MLS number, agent attribution, and price figures in the text, plus 5 structured-data blocks including a RealEstateListing record. One detail page per session is a sane budget. A full market study is thousands of pages, and that is exactly the volume Zillow’s wall exists to stop.

One thing I tried that did not work: re-rendering that same detail page with a headless browser a few minutes later. Magpie came back with quality blocked (empty) and exit code 8: Zillow served nothing worth parsing, and Magpie refuses to hand over a blank page dressed up as data. I took the hint and stopped there, and you should too.

Zestimates: the number Zillow keeps client-side

Here is the part most Zillow scraper tutorials skip, usually because they never ran theirs. I searched the entire static output of the detail page for the word “Zestimate”: zero hits. The rent estimate, the price history graph, the valuation range — all rendered client-side after the page loads, and my browser-render attempt got walled (see above). A static zillow data scraper cannot pull what the server never sends.

Your realistic options, in order of how much I trust them:

  1. Compute your own. The detail-page scrape carries the asking price and the other price figures Zillow shows, and county assessor records are public. ATTOM Data licenses cleaned public-records data if you want a vendor for it. Slower, but nothing to get cut off from.
  2. Third-party Zillow API wrappers. Zillapi, for one, exposes a Zestimate endpoint per property and gives 100 free credits at signup. You are paying for convenience and inheriting their ToS position, which is the same problem wearing a different shirt.
  3. Bridge Interactive. Official, free, and gated to MLS-affiliated brokerages and partners. If you qualify, it is the only legitimate bulk source, but it generally does not include the Zestimate either.

Nobody legitimate resells Zestimate data in bulk, and the number itself is an estimate with published error ranges. If your project survives losing it, the listing data above may be all you need.

Picking a zillow web scraper: local binary or rented API

The SERP for this topic is wall-to-wall managed scraping vendors. Honest comparison, with the two facts that matter:

  • Local (Magpie). Free, no account, data never leaves your machine, respects robots.txt, and the whole extraction is a JSON parse that keeps working when Zillow redesigns. Limits: polite volume only, no Zestimate, and you own the judgment call on ToS. The same approach works on Airbnb and Craigslist, which publish comparable structured data with fewer tripwires.
  • Rented (Apify, Bright Data, Oxylabs, ScrapingBee). They maintain proxy pools and solving infrastructure, so they deliver volume Zillow would block from your IP, and some resell Zestimate-shaped data. You pay per listing or compute unit, every record transits their servers, and their uptime is a function of an adversarial arms race: when Zillow changes its wall, their actors break too, on their schedule, not yours.

If you need ten thousand listings a day, rent, and budget for breakage. If you need today’s market snapshot for one metro as a CSV, build the two-command setup above and stay under the tripwire. For the wider picture across property sites, the real-estate scraping guide covers the data model that transfers between them.

FAQ

Is it legal to scrape Zillow? Scraping breaches Zillow’s Terms of Use, which prohibit automated access without written permission. US courts have narrowed how automated-access claims play out, and listing facts themselves are generally not copyrightable, but the contract risk is real. Commercial use warrants a lawyer’s opinion, not a blog answer.

Does Zillow have a public API? No. Zillow retired its Web Services API in September 2021 and ZTRAX in 2023. Bridge Interactive is the official path for MLS-affiliated brokerages and approved partners. Everyone else is on unofficial wrappers or scraping.

Can you get the Zestimate through an API? Not from Zillow. Bridge’s partner feed generally excludes it, and third-party wrappers like Zillapi sell it per property credit. Since it is a model estimate with published error margins, public records plus your own arithmetic is the defensible route.

Why does my Zillow scraper get blocked after a few requests? PerimeterX bot protection with aggressive rate heuristics. My test worked at polite volume, then a second browser render minutes later returned an empty page. Slow down, cache what you fetch, reuse URLs from the sitemaps, and never loop retries against a wall.


If you only need one metro’s snapshot, clone Magpie, run the two commands, and be done in an hour. If you find yourself needing volume Zillow refuses to give, that is the market telling you to buy the data from a county recorder or a licensed vendor instead of fighting a wall built by a hundred-person trust-and-safety team.

Stop renting credits.

One flat price, your machine, your keys.

Download free for Windows, macOS and Linux

Windows · macOS · Linux $49/mo flat, cancel anytime