~ / guides / How to Scrape Zillow Without Getting Blocked (Proxies & CAPTCHAs)

How to Scrape Zillow Without Getting Blocked (Proxies & CAPTCHAs)

DC
Dana Cole
Zillow data engineer · about the author
the short version
  • A plain requests call to a Zillow /homedetails/ page returned HTTP 403 from CloudFront with a 5,928-byte HTML block page where the property data should have been. A full Chrome User-Agent changed nothing in my test.
  • Zillow runs HUMAN Security (PerimeterX), so it blocks on IP reputation, TLS fingerprint, and behavior. That is the source of the Press & Hold CAPTCHA and the datacenter-IP 403.
  • The setups that return data: residential proxies plus a stealth headless browser, the official Zillow data (free ZHVI/ZORI CSVs and the licensed API), or a scraper API that handles proxies and CAPTCHAs for you.
  • For more than a few hundred property records, rotating proxies and solving Press & Hold yourself costs more engineering time than it saves.

I tried to scrape Zillow the quick way first: one requests.get against a live /homedetails/ page from a server. It came back 403 before I parsed a single price, bed count, or address. That failure is the whole subject of this guide on how to scrape Zillow data, because it is what nearly everyone hits, and the standard fix everyone repeats (set a browser User-Agent) did nothing in my test.

Below is exactly what I ran, what Zillow returned, why its anti-bot stack reacts that way, and the three setups that actually get property data back.

Why does Zillow block scrapers?

Zillow blocks scrapers on IP reputation, TLS fingerprint, and behavioral signals. The User-Agent string has little to do with it. When I sent a request from a datacenter IP to a live Zillow property page in June 2026, Zillow answered with an HTTP 403 and a 5,928-byte HTML block page served through CloudFront, no matter which User-Agent I set.

I tested the same /homedetails/ URL two ways:

RequestUser-AgentResultBody
GET /homedetails/...none4035,928 B HTML, server: CloudFront
GET /homedetails/...full Chrome desktop string4035,928 B HTML, server: CloudFront

The response was identical both times: content-type: text/html, server: CloudFront, an HTML body where the property JSON should be. That is the edge refusing the connection at the door. A rate-limit throttle would return 429 with a retry-after header. A 403 with an HTML body means the request never reached the listing data at all.

The reason is the anti-bot layer. Zillow uses HUMAN Security, formerly PerimeterX, which combines browser fingerprinting, behavioral analysis, and network-level signals to decide whether a request is a real person. It reads Canvas, WebGL, AudioContext, and Navigator properties, watches mouse movement and scroll cadence, and flags datacenter IP ranges from AWS and Google Cloud almost on the first hit. When the score looks automated it returns a 403 block page or injects the Press and Hold CAPTCHA, and that block decision happens before content, so the fix has to change where the request comes from and how human it looks.

What is the Press and Hold CAPTCHA on Zillow?

The Press and Hold CAPTCHA on Zillow is the HUMAN Security (PerimeterX) human-challenge screen, shown when the anti-bot system scores a request as automated. It asks you to press and hold a button to confirm you are human, and it frequently appears the moment a plain headless browser loads the page, before the listing renders.

Holding the button is not the actual test. The page runs a collector script that emits a signed telemetry payload before and during the press: pointer pressure, timing, micro-movements, and the device fingerprint it already gathered. A script that fakes a mousedown then mouseup without that telemetry stream still fails the challenge, which is why manual click automation in Selenium or Puppeteer rarely clears it on its own. The reliable paths around Press and Hold are the same paths that avoid the 403 in the first place: a real browser fingerprint over a residential IP, or a service that solves the challenge upstream.

This matters for tooling choice. Scraping tools that only swap headers cannot pass a behavioral CAPTCHA, so the question becomes which scraping solution for Zillow actually changes the IP and the fingerprint together.

What scraping solutions for Zillow actually work?

Three scraping solutions for Zillow return data reliably: residential proxies paired with a stealth browser, the official Zillow data products, and a managed scraper API. Each trades cost, scale, and engineering time differently.

SolutionWhat it returnsHandles CAPTCHA / blocksBest for
Residential proxies + stealth browserRaw HTML you parse yourselfYou maintain it (fingerprint + rotation)Mid-volume, full control
Official Zillow data (CSV + API)Aggregate ZHVI / ZORI metricsNo blocks, it is sanctionedMarket trends, research
Scraper API (e.g. ChocoData)Parsed listing JSONHandled server-sideLive listings at scale

The split is about what data you need. Individual live listings with price, beds, baths, sqft, and address come from the listing pages, which means you fight the anti-bot stack. Aggregate neighborhood and metro trends come from Zillow’s own free research files, which means no scraping at all. The next three sections take each route in turn, starting with the proxy build because it is the one most guides hand-wave.

How do proxies help collect data from Zillow?

Proxies help collect data from Zillow by routing each request through a residential or mobile IP, so the request presents as an ordinary home connection instead of a flagged datacenter range. Datacenter IPs from AWS and Google Cloud are pre-scored as suspicious by HUMAN Security, so rotating residential proxies is the single change that moves the 403 result the most in my experience.

A proxy alone is not enough, because the fingerprint and behavior still get scored. The working combination is a residential proxy plus a stealth headless browser that presents a consistent Canvas, WebGL, and Navigator fingerprint, plus human-like pacing. Here is the shape of a Playwright request through a rotating residential proxy:

from playwright.sync_api import sync_playwright

# Residential proxy endpoint from your provider (rotates the exit IP per session)
PROXY = {
    "server": "http://gate.your-residential-proxy.com:7000",
    "username": "user",
    "password": "pass",
}

url = "https://www.zillow.com/homedetails/1600-Pennsylvania-Ave-NW-Washington-DC-20500/"

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True, proxy=PROXY)
    ctx = browser.new_context(
        user_agent=(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/124.0 Safari/537.36"
        ),
        locale="en-US",
        viewport={"width": 1366, "height": 768},
    )
    page = ctx.new_page()
    page.goto(url, wait_until="domcontentloaded", timeout=30000)
    page.wait_for_timeout(2500)   # let scripts run; do not hammer
    html = page.content()
    print(len(html), "bytes")     # a real listing is far larger than the 5,928 B block page
    browser.close()

This is more reliable than raw requests because it runs a real browser engine, so the JavaScript that Zillow expects actually executes. It is still maintenance: you buy a residential pool, rotate it, keep the browser fingerprint current, slow the request rate to one every few seconds per IP, and add retry logic for the sessions that still draw a Press and Hold. For Zillow neighborhood data scraping with proxies at any real volume, that maintenance is the cost you are signing up for. If you only need market-level trends, the official data route below skips it entirely.

When should you use Zillow’s official data instead?

Use Zillow’s official data when you need aggregate market metrics at the neighborhood or metro level, because Zillow publishes those numbers for free and scraping them is pointless. Zillow Research releases the Zillow Home Value Index (ZHVI) and the Zillow Observed Rent Index (ZORI) as downloadable CSVs, and the data is free for public use by consumers, media, analysts, academics, and policymakers with attribution to Zillow.

The coverage is broad. ZHVI and ZORI are generated at seven geographic levels: neighborhood, ZIP code, city, county, metropolitan area, state, and the nation, with history reaching back to the late 1990s for many series. ZHVI is a weighted average of the middle third of home values in a region, and ZORI is a repeat-rent index weighted to the rental housing stock. For programmatic access, the Zillow Real Estate Metrics API serves the same figures, and Zillow recommends the Econ Data API over scraping CSV paths because it changes those download URLs periodically.

What the official data does not give you is the live listing detail: a specific home’s current asking price, beds, baths, sqft, photos, agent, and address. For property-level extraction at scale, Zillow’s own Terms of Use prohibit automated collection, and Zillow does not offer a general public API for it, with API access limited to approved partners through Bridge Interactive under separate agreements. That gap, sanctioned aggregates on one side and no sanctioned listing feed on the other, is exactly where a scraper API fits.

How do you scrape Zillow at scale without managing proxies?

A scraper API removes the blocking work by accepting a Zillow URL and returning parsed JSON, with proxy rotation, fingerprinting, and CAPTCHA handling done server-side. You send one request and get structured listing data back, with no 403 and no Press and Hold to solve yourself. ChocoData is the Zillow listings and property API I reach for when I need volume.

The request is a single call. You pass the listing URL and your key, and the service returns the property fields:

curl "https://chocodata.com/api/v1/zillow/property?url=https://www.zillow.com/homedetails/2092-zpid/&api_key=$CHOCO_API_KEY"

The Python version is the same call, which makes it easy to loop a search scraper over a list of Houston TX listings or any other search result set:

import os
import requests

API_KEY = os.environ["CHOCO_API_KEY"]
listing = "https://www.zillow.com/homedetails/2092-zpid/"

resp = requests.get(
    "https://chocodata.com/api/v1/zillow/property",
    params={"url": listing, "api_key": API_KEY},
    timeout=60,
)
data = resp.json()
# Expected fields for a property response: price, beds, baths, sqft, address
print(data.get("price"), data.get("beds"), data.get("baths"), data.get("sqft"))

The data this returns is the same listing detail (price, beds, baths, sqft, address) you would have parsed from the HTML, without buying a residential pool, rotating IPs, maintaining a browser fingerprint, or debugging a Press and Hold screen. You can extract a single property or feed it a search results page; related endpoints cover rental listings and rent prices and home price and sales history. For a one-off pull of a few hundred records the proxy build is workable, but for continuous collection across many ZIP codes, offloading the blocking and CAPTCHA work is the cheaper path once you price your own engineering time. You can get a key on the ChocoData sign-up page.

How do you avoid getting blocked when scraping Zillow?

You avoid getting blocked on Zillow by changing IP reputation, browser fingerprint, and request rate together, since HUMAN Security scores all three. These are the levers that actually moved the result in my testing, in rough order of impact:

The honest tradeoff: doing all of this yourself means buying and rotating a residential pool, keeping a stealth fingerprint current, handling Press and Hold, and retrying failures. That is a standing maintenance project once you pass a few thousand records, which is the reason most teams hand the blocking problem to a scraper API. Before you collect anything at scale, it is worth knowing where the legal line sits, which I cover in is scraping Zillow legal. If you want the full Python build end to end, see my Zillow scraping with Python walkthrough, and for the broader method overview there is the complete Zillow scraping guide.

FAQ

Why does Zillow show a Press and Hold screen instead of the listing?

The Press and Hold screen is the HUMAN Security (PerimeterX) challenge. Zillow serves it when the request's IP, TLS fingerprint, or behavior looks automated. Holding the button submits a signed telemetry payload from the page's collector script, so a script that fakes the click without that telemetry still fails.

Does a real Chrome User-Agent stop the Zillow 403?

No. In my June 2026 test a full Chrome desktop User-Agent returned the same HTTP 403 and the same 5,928-byte CloudFront block page as sending no User-Agent at all. Zillow blocks on the datacenter IP and TLS fingerprint, so the header alone does not change the result.

Is there a free official source for Zillow data?

Yes. Zillow Research publishes ZHVI and ZORI as free CSV downloads at neighborhood, ZIP, city, county, metro, state, and national levels, and the Real Estate Metrics API serves the same numbers. These cover aggregate market data. Individual live listings with beds, baths, and sqft come from the listing pages instead.

How many Zillow pages can I scrape before getting blocked?

There is no published request quota. Zillow's robots.txt disallows /homes/, /s/, and /api/, and the block triggers on request signals, so a single datacenter request can return 403 while a slow residential session lasts longer. Volume past a few hundred records is where a proxy pool or a scraper API becomes the practical route.

Is scraping Zillow legal?

Scraping publicly visible pages is generally treated as legal in the US after hiQ v. LinkedIn, where the Ninth Circuit held that scraping public data is unlikely to violate the CFAA. Zillow's Terms of Use still prohibit automated access without written permission, so contract and copyright exposure remain. I cover the detail in my guide on whether scraping Zillow is legal.

DC
Dana Cole
I've built Zillow data pipelines for years. On zillowscraperapi.com I run Zillow scraping methods against live pages and publish what actually holds up.