To scrape Zillow data, give a ready-made Actor a city, a Zillow search URL, a home URL or a street address, and export one row per listing: price, beds, baths, living area, year built, Zestimate, photos and MLS details. On Scrape.ly that takes a few clicks, or one API call.
This guide shows which fields you get, the no-code steps, and the same job in curl, Python, JavaScript and through an AI agent. Then it walks through a real run from 22 October 2026, five homes for sale in Greenville, South Carolina, with the log and the exact cost.
What data you can get from Zillow
The Zillow Detail Scraper returns one row per listing. Fields that Zillow doesn't show for a home come back as null.
| Field | What it holds |
|---|---|
zpid, propertyUrl | Zillow's property ID and the listing URL |
address, listingAddress | The full address and its parts (street, city, state, ZIP) |
coordinates | Latitude and longitude |
price, listingPrice | List price as a number, and as an object with currency and formatted text |
bedrooms, bathrooms, bathroomsDetail | Bed and bath counts, with full and half baths |
livingArea, lotArea, pricePerSquareFoot | Living area in square feet, lot size and price per square foot |
yearBuilt, homeType | Year built and type, such as SINGLE_FAMILY |
listingStatus, listingType | Status (forSale) and flags such as pending, new home, foreclosure or for sale by owner |
zestimate, rentZestimate | Zillow's estimated value and rent, when shown |
monthlyHoaFee, propertyTaxRate | Running costs, when shown |
description, photoCount, mainImage, listingPhotos | Listing text and photos |
mls, agent, broker, attributionInfo | MLS name and ID; listing agent and broker when the page shows them |
resoFacts, parking | Structured facts such as garage spaces and parking features |
isValid, scrapedAt | Row status and timestamp |
What you won't get: price history, tax history, nearby schools and nearby homes come back empty, and parcel IDs, tax amounts and school districts aren't included. Listings behind a Zillow login aren't available either.
How to scrape Zillow without code
- Open the Zillow Detail Scraper in the Scrape.ly Store.
- Pick the Homes for sale in Greenville, SC, 5 results preset. It fills in this input:
{
"startUrls": [],
"searchQueries": [
"Greenville, SC"
],
"maxItems": 5,
"propertyStatus": "FOR_SALE",
"addresses": [],
"extractBuildingUnits": "disabled"
}- Click Start. Our run finished in under 6 seconds.
- Open the dataset and export it as JSON, CSV or Excel.
The input fields that matter most:
searchQueries: cities or neighborhoods, typed the way you'd type them into Zillow's search box.startUrls: Zillow home URLs (/homedetails/), search URLs or building pages. A home URL returns one listing; a search URL returns homes up to the maximum.addresses: US street addresses, if you already know which homes you want.maxItems: the most listings to return. Default 10; 0 means no limit.propertyStatus:FOR_SALE,RECENTLY_SOLDorFOR_RENT, applied to location searches. A home URL is read as Zillow published it.searchResultsDatasetId: a dataset whose rows containpropertyUrl,detailUrloraddress, so you can feed in URLs from an earlier run.
How to scrape Zillow with the API
Create a token under Settings → API & Integrations in the dashboard and store it as SCRAPELY_TOKEN. This preset runs in a few seconds, so the synchronous endpoint can start it and return the listings in one call:
curl -X POST "https://api.scrape.ly/v2/actors/roamandroof~zillow-detail-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"startUrls": [], "searchQueries": ["Greenville, SC"], "maxItems": 5, "propertyStatus": "FOR_SALE", "addresses": [], "extractBuildingUnits": "disabled"}'The call waits up to 45 seconds and returns a JSON array. Add ?format=csv for CSV. A job with many searches or URLs can take longer. Then the call answers 408 while the run keeps going, and calling again would start a second run. For those, start the run with POST /v2/actors/roamandroof~zillow-detail-scraper/runs, poll /v2/actor-runs/RUN_ID?waitForFinish=60 until the status is SUCCEEDED, and read /v2/actor-runs/RUN_ID/dataset/items. The API docs show the full flow.
In Python, install the client with pip install scrapely-client-python. call() waits for the run however long it takes:
import os
from scrapely_client import ScrapelyClient
client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")
run = client.actor("roamandroof/zillow-detail-scraper").call(
run_input={
"searchQueries": ["Greenville, SC"],
"maxItems": 5,
"propertyStatus": "FOR_SALE",
}
)
print(run.status) # SUCCEEDED, FAILED, ABORTED or TIMED-OUT
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item["price"], item["bedrooms"], item["bathrooms"], item.get("zestimate"))In JavaScript or Node.js, install it with npm install scrapely-client:
import { ScrapelyClient } from 'scrapely-client';
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });
const run = await client.actor('roamandroof/zillow-detail-scraper').call({
searchQueries: ['Greenville, SC'],
maxItems: 5,
propertyStatus: 'FOR_SALE',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);The Python client, JavaScript client and dataset API docs cover paging through large datasets.
With an AI agent (MCP)
Scrape.ly runs a hosted MCP server at https://api.scrape.ly/mcp. In Cursor, add it to ~/.cursor/mcp.json:
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}In Claude Code, run claude mcp add --transport http scrapely https://api.scrape.ly/mcp, then /mcp to sign in with OAuth. The agent uses search-actors, fetch-actor-details, call-actor and get-actor-output. Try a prompt like: "Use scrapely to run roamandroof/zillow-detail-scraper for homes for sale in Greenville, SC, 5 results, and give me a table of price, beds, baths, living area and Zestimate." The MCP docs list the other clients.
A real run: Homes for sale in Greenville, SC
We ran the preset on 22 October 2026. It saved 5 listings, the run took 5.7 seconds, and it was charged $0.0062 in total. We removed the street addresses of these private homes and any agent names from the sample below.
| address | price | bedrooms | bathrooms | livingArea | zestimate |
|---|---|---|---|---|---|
| [street withheld], Greenville, SC 29605 | 369,000 | 3 | 2 | 1,542 | — |
| [street withheld], Greenville, SC 29617 | 170,000 | 2 | 1 | 1,123 | 158,700 |
| [street withheld], Greenville, SC 29607 | 1,087,750 | 5 | 5 | 4,351 | 1,034,500 |
| [street withheld], Greenville, SC 29605 | 1,700,000 | 3 | 5 | 4,607 | 1,779,400 |
| [street withheld], Greenville, SC 29605 | 375,000 | 3 | 2 | 1,325 | 366,000 |
2026-10-22T15:23:09.198Z [Scrapely] Container started (setup 0.8 s)
2026-10-22T15:23:10.291Z [scrapely.actor] INFO [Scrapely] Initializing API storage for run aec640d809a248a09
2026-10-22T15:23:10.420Z [scrapely.proxy_configuration] INFO Platform proxy access check succeeded.
2026-10-22T15:23:10.420Z [scrapely.actor] INFO Fetching with proxy pool DATACENTER
2026-10-22T15:23:13.685Z [scrapely.actor] INFO Saved 5 listings. Requests 6. Transferred 4829117 bytes.
2026-10-22T15:23:13.685Z [scrapely.actor] INFO [Status message]: Saved 5 listings from 1 inputs. Reached the maxItems limit of 5.
2026-10-22T15:23:14.092Z [Scrapely] Container state: status=exited exitCode=0 oomKilled=falseAll five were single-family homes for sale, priced from $170,000 to $1,700,000. Four had a Zestimate: three sat below the list price and one above it ($1,779,400 against $1,700,000). The first listing had none. Its full record shows a 2021 build on 0.48 acres at $239 per square foot, 48 photos and the Greater Greenville AOR as its MLS. As the limits below say, listingPriceHistory and nearbySchools came back empty, and daysOnZillow was null. The run made 6 requests and moved 4,829,117 bytes (about 4.8 MB) for five listings.
What it costs
The Actor has one charge event: result-item, at $0.001 for each listing saved. URLs or addresses that can't be read aren't charged.
This run: 5 listings × $0.001 = $0.005 in event fees. The run was charged $0.0062 in total, because platform usage added $0.000754 of compute, $0.000399 of datacenter proxy traffic and $0.000005 of dataset writes.
At 1,000 listings: 1,000 × $0.001 = $1.00 in event fees, plus platform usage for compute and proxy traffic.
Limits and common problems
- One results page per search. A location search returns the first results page Zillow shows for it (about 40 homes). For bigger jobs, add more searches (for example, by neighborhood) or paste home URLs.
- Missing blocks. Price history, tax history, nearby schools and nearby homes are loaded by a separate request this Actor doesn't make, so they come back empty. If you need them, this is the wrong tool.
- Empty fields. Zillow doesn't show every field on every listing, so values such as agent contact details, days on Zillow or the Zestimate can be
null, as in the first row above. - Bad input. A wrong URL or an address Zillow can't find saves no row and isn't charged. The run still succeeds and lists it under
failedInputsin theOUTPUTrecord. - Sync timeouts. This run took 5.7 seconds, but the synchronous endpoint stops waiting at 45 seconds. Use the asynchronous flow for large jobs.
Is it legal to scrape Zillow?
The Actor reads publicly visible listing pages and never logs in. Zillow's Terms of Use (updated October 28, 2025) are clear, though. They forbid "automated queries (including screen and database scraping, spiders, robots, crawlers, bypassing 'captcha' or similar precautions...)". They allow copying information only "without the aid of any automated processes" and only as needed for personal or "Pro" use. Listings also carry more personal data than product pages: a street address points to someone's home, and agent names and phone numbers identify people. Once you collect personal data, privacy laws such as the GDPR and the CCPA apply, which is why we masked our sample. This is not legal advice. Before you use Zillow data commercially, get advice from a lawyer for your case.
Alternatives
- Zillow's Bridge APIs. Zillow Group's MLS Listings API (Bridge Listing Output) serves MLS listing data over REST, normalized to the RESO data dictionary. Access is invite-only and at the discretion of each MLS. The Public Records API covers parcel, assessment and transaction data, roughly 15 years of it, and is also invite-only. If you're a broker or a business with a data agreement, these are the better route.
- Zestimates API and Zillow Research data. The Zestimates API returns current property, rental and foreclosure Zestimates for about 100 million US properties, aimed at commercial use. For research, Zillow points to its Research data, which has looser terms. If you need market trends rather than single listings, start there.
- Your own Python scraper. Scrapfly's guide reads the JSON Zillow embeds in each page (
__NEXT_DATA__). Scrapingdog's guide uses generated CSS class names, and its text and code already cite two different versions of the same class. Expect to maintain selectors and handle blocks yourself. - A headless browser. Playwright or Selenium gives full control over the page. It's the better choice when you need data a ready-made tool doesn't collect, at the cost of running browsers and proxies yourself.
FAQ
Does Zillow have an API?
Yes. Zillow Group lists close to 20 APIs, but the listing data needs approval: the MLS Listings and Public Records APIs are invite-only, and the Zestimates API is aimed at businesses. Researchers can download aggregate market data from Zillow Research instead.
Can you scrape Zestimates from Zillow?
Yes. Each row carries zestimate and rentZestimate when Zillow shows them. In our run, four of the five listings had a Zestimate and one had none.
Can you scrape sold or rental listings?
Yes. Set propertyStatus to RECENTLY_SOLD or FOR_RENT for a location search. The Recently sold in Greenville, SC preset shows the sold case. A home URL you paste is read as Zillow published it, whatever status you pick.
Can you scrape Zillow by address?
Yes. Put US street addresses in addresses, one per entry, and the Actor finds each home and returns its details. An address Zillow can't find saves no row and isn't charged.
How many listings can one Zillow search return?
One search returns the first results page Zillow shows, about 40 homes. For more, split the area into several searches or collect home URLs and pass them in startUrls or through searchResultsDatasetId.




