Zillow Scraper: Sale, Rent and Sold Property Listings
Pricing
from $1.00 / 1,000 results
Zillow Scraper: Sale, Rent and Sold Property Listings
Scrape zillow.com properties for sale, for rent and recently sold across the US: price, beds, baths, area, address, GPS, photos, home value and rent estimates. Optional property page read adds HOA fee, tax rate, MLS id, agent, brokerage and the fact sheet. 25 filters, or paste links.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Features
Share
Zillow Scraper turns zillow.com into structured property data. Search any US place by name or ZIP for homes for sale, homes for rent or recently sold homes, or paste links you already have. Every record carries price, beds, baths, area, full address, GPS, photos and the site's own home value and rent estimates; switch on the property page read and it also carries the description, year built, HOA fee, property tax rate, MLS id, listing agent, brokerage and the full fact sheet. Export to JSON, CSV or Excel, or pull results straight into your app through the API.
Why This Scraper?
- Coverage past the site's own ceiling. One read of a map area returns at most 500 records however many properties exist inside it. This actor splits a busy area into quarters and reads each one, so a city with thousands of homes is genuinely covered instead of truncated at the first few hundred.
- Honest completeness. Every run reports whether it scanned an area end to end. A refused read, an unresolved place or a run cap all mark the scan partial, and expiry tracking refuses to act on a partial scan.
- Three channels, one shape. For sale, for rent and recently sold return the same columns, so a rental feed and a sold-comparables feed line up without post-processing.
- 25 search filters. Channel, price, beds, baths, area, lot size, year built, HOA fee, property type, keyword, time on market, sort order and eight feature toggles.
- Recurring monitoring built in. Run the same search on a schedule and get only what changed, marked NEW, UPDATED, REAPPEARED or EXPIRED, with the exact list of fields that moved.
- Pay for results, not for pages. The search-level record costs one result event. Reading each property's own page is optional and billed separately, so you never pay for detail you did not ask for.
- No fields quietly dropped. Agent name, phone, brokerage and MLS id are returned whenever the property page publishes them, instead of being silently omitted.
Use Cases
- Property investors and flippers: screen a whole metro for price, days on market and lot size, then compare against the home value estimate.
- Rental market research: track asking rent by bedroom count and neighborhood across several cities at once.
- Comparable sales analysis: pull recently sold homes near a subject property to support a valuation or an offer.
- Lead generation for agents and lenders: monitor a farm area on a schedule and get only the new listings and price changes.
- Market dashboards and reports: build a standing dataset of active inventory, price trends and property mix for a region.
Data You Get
Sample shape: values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
id / zpid | "00000001" |
url | "https://www.zillow.com/homedetails/00000001_zpid/" |
listingType | "FOR_SALE" (also "FOR_RENT", "SOLD") |
homeStatus / statusText | "FOR_SALE" / "Active" |
propertyType | "SINGLE_FAMILY" |
price / formattedPrice | 612000 / "$612,000" |
zestimate / rentZestimate | 604800 / 2875 |
taxAssessedValue | 498000 |
priceChange / priceChangeDate | -9000 / "2026-02-01T00:00:00.000Z" |
streetAddress / city / state / zipCode | "142 Sample Ridge Dr" / "Austin" / "TX" / "78701" |
latitude / longitude | 30.30 / -97.70 |
bedrooms / bathrooms | 4 / 3 |
livingArea | 2100 |
lotAreaValue / lotAreaUnit | 8000 / "sqft" |
daysOnZillow | 14 |
priceReduction / marketingTagline / cardHighlight | "$9,000 (Feb 1)" / "Showcase" / short card badge text |
cardType / units / dateSold / listingSoldPrice / availabilityDate / sourceSearchUrl | card type, apartment-building units, sold date and price (sold searches), rental availability, originating search link |
listingSubType / openHouse / openHouseSchedule | {"isFSBA": true, "isOpenHouse": true} (listing-kind flags: for sale by agent or owner, coming soon, pending, auction, foreclosure, bank owned, open house, new home; only the flags the card carries) / "Sat. 11am-2pm" / [{"startDate": "2026-09-05T11:00:00", "endDate": "2026-09-05T14:00:00"}] (open-house windows, property-local wall-clock time with no time-zone suffix) |
heroImage / photos | property photo URL(s) |
description / yearBuilt / monthlyHoaFee / propertyTaxRate / mlsId / mlsName | "..." / 1995 / 60 / 1.9 / "1234567" / "Sample MLS" (property page only) |
listingAgentName / listingAgentPhone / brokerageName | "Jordan Example" / "(555) 010-0100" / "Sample Realty Group" (property page only) |
resoFacts | parking, sub-type and other fact-sheet fields (property page only) |
changeType / changedFields | "UPDATED" / ["price"] (incremental mode only) |
detailFetched / scrapedAt | true / "2026-01-01T00:00:00.000Z" |
Dataset views. The output tab offers three views: Results (the main card fields), Property page details (description, year built, HOA fee, MLS, agent and brokerage, filled when you switch on the property page read) and Changes (changeType and changedFields, filled in incremental mode).
Added card fields. Newer rows also carry cardType, units, priceReduction, marketingTagline, cardHighlight, dateSold, listingSoldPrice, availabilityDate, priceIncludesMonthlyFees, isRentalWithBasePrice, marketingTreatments, sourceSearchUrl, listingSubType and openHouseSchedule. They are additions only; no existing field was renamed or removed. In incremental mode they are ignored by default when deciding UPDATED, so an existing saved baseline does not suddenly bill a wave of changes.
Rental results also include building and community cards, which carry a price range instead of one price and are returned with the fields the site publishes for them.
How to Use
- Pick a mode:
search(build a search from a location and filters) orurl(paste links you already have). - In search mode, add one or more locations and set the channel and any filters. In URL mode, paste search or property links.
- Turn on Read the property page for each result if you need the description, year built, HOA fee, MLS id, agent and brokerage.
- Set Max results to control run size and cost, then click Start. Download the dataset as JSON, CSV or Excel, or read it through the API.
Search one city for homes for sale:
{"mode": "search","locations": ["Austin, TX"],"listingType": "FOR_SALE","maxItems": 200}
Search several places for rentals under a price, with filters:
{"mode": "search","locations": ["Brooklyn, NY", "Jersey City, NJ"],"listingType": "FOR_RENT","maxPrice": 3500,"minBeds": 2,"homeTypes": ["APARTMENT", "CONDO"],"daysOnZillow": "30_DAYS","maxItems": 500}
Recently sold comparables with the property page read switched on:
{"mode": "search","locations": ["78759"],"listingType": "SOLD","daysOnZillow": "12_MONTHS","fetchDetails": true,"maxItems": 100}
Paste links you already have:
{"mode": "url","startUrls": ["https://www.zillow.com/homes/for_sale/Austin,-TX/","https://www.zillow.com/homedetails/00000001_zpid/"],"maxItems": 50}
URL mode defaults: if you switch to URL mode and leave the links field untouched (or omit startUrls from an API call), the run scrapes one example of each supported link shape: a for-sale search, a city page, a page-numbered city page (/austin-tx/2_p/ starts at page 2, it does not restart at page 1), a for-rent search and one property page (returned as a single record). Replace the list, or pass an empty list, to scrape only your own links. Max results still caps the whole run.
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/zillow-scraper").call(run_input={"mode": "search", "locations": ["Austin, TX"], "maxItems": 50})for record in client.dataset(run["defaultDatasetId"]).iterate_items():print(record["address"], record["price"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/zillow-scraper').call({mode: 'search', locations: ['Austin, TX'], maxItems: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
How coverage and Max results interact
One read of a map area returns at most 500 records, however many exist inside it. This actor covers a busy area by splitting it into quarters and reading each one, up to a run-level cap on total reads (Max reads per location). When an area still holds more than one read can return and can no longer be split, the run reports that area as not fully covered rather than reporting a silent partial count.
Resume and recurring updates
- Resume (
resumeFromRunId) continues one interrupted run: paste its run or dataset id and the actor skips every row already collected there, so you don't pay twice. - Incremental mode (
incrementalMode) is for scheduled runs over the same search. Each property is classifiedNEW,UPDATED(withchangedFields),UNCHANGED(suppressed and not billed unlessemitUnchangedis on),REAPPEAREDorEXPIRED(only after a run scanned the whole search end to end, and only withemitExpired).stateKeynames or shares the stored state. With incremental mode off, output is exactly as before. - Ignoring noisy fields (incremental mode). These fields are always ignored when deciding
UPDATED: the scrape time, days on Zillow, favourite count and page view count (they move on their own), and the added card fieldssourceSearchUrl,cardType,units,isValid,hasImage,marketingTagline,cardHighlight,priceReduction,priceIncludesMonthlyFees,isRentalWithBasePrice,marketingTreatments,availabilityDate,dateSold,listingSoldPrice,listingSubTypeandopenHouseSchedule. A change to only one of them does not, on its own, make a rowUPDATED(a changedpriceoropenHouselabel still does), andchangedFieldsleaves them out; they are still returned in every row. Add more withignoreFieldsForChanges; Zillow's ownzestimateandrentZestimateare recomputed regularly, so list them there if you only care about listing changes. The saved baseline is compared again with your current list on every run, so editing the list never turns the whole baseline intoUPDATED. - Resume plus incremental mode. You can combine the two only on a campaign with no saved state yet; with saved state the run stops and asks you to remove the resume id or pick a different
stateKey. On that first combined run the resumed properties are skipped, and they carry no saved values into the campaign. So the next incremental run returns each resumed property that is still listed once asUPDATED(with every field inchangedFields) and bills it. From the run after that, classification is normal. To avoid that one extra batch, start a campaign with a plain incremental run instead of a resume. - Tip: keep Max results high (or 0) on incremental runs. Max results limits how many properties each read checks, not only how many are returned. This is deliberate: a property the run never checked is never counted as seen, so the run is correctly reported as partial and nothing is wrongly marked
EXPIRED. The side effect is that unchanged properties use up the cap even though they are not returned. With a small cap, a new or changed property that sits later in the scan order can go unchecked for that run, and the run can end with fewer rows, or none, and a status saying nothing changed, even though changes exist. Those properties are not lost: any later run whose cap reaches them reports them. Set Max results to0, or comfortably above the area's normal listing count, wheneverincrementalModeis on; keep a tight cap for one-off searches. - Tip:
emitExpiredrows count toward Max results. Once a run has scanned its tracked search end to end, properties that are no longer found are pushed and billed asEXPIREDin that same run, but only while the run is still under Max results (the cap covers the whole run, every location or link together, minus the rows already returned). Properties left over when the cap is reached stay tracked and are reported by a later run; Max results0means no cap, so every one is reported at once. A run that stopped because it reached Max results did not scan the search end to end, so it reports noEXPIREDrows at all. TurnemitExpiredoff if you only want theNEW/UPDATEDdelta.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search builds the search from the location and filters below. url takes zillow.com links you already have. |
locations | array | ["Austin, TX"] | Search mode only. One or more US places, written the way you would type them into the site. The run cap is shared evenly between them. |
listingType | string | FOR_SALE | Search mode only. FOR_SALE, FOR_RENT or SOLD. |
homeTypes | array | [] | Search mode only. Empty means every property type. |
minPrice | integer | none | Search mode only. Lowest price in USD (lowest monthly rent on a for-rent search). |
maxPrice | integer | none | Search mode only. Highest price in USD (highest monthly rent on a for-rent search). |
minBeds | integer | none | Search mode only. Fewest bedrooms. |
maxBeds | integer | none | Search mode only. Most bedrooms. |
minBaths | integer | none | Search mode only. Fewest bathrooms. |
minSqft | integer | none | Search mode only. Smallest interior area in square feet. |
maxSqft | integer | none | Search mode only. Largest interior area in square feet. |
minLotSize | integer | none | Search mode only. Smallest lot in square feet. |
maxLotSize | integer | none | Search mode only. Largest lot in square feet. |
minYearBuilt | integer | none | Search mode only. Earliest year built. |
maxYearBuilt | integer | none | Search mode only. Latest year built. |
maxHoaFee | integer | none | Search mode only. Highest monthly HOA fee in USD. 0 returns only properties with no HOA fee. |
keywords | string | none | Search mode only. Narrows to properties whose listing text mentions this word. |
daysOnZillow | string | ANY | Search mode only. How recently the property was listed, or sold on a recently-sold search. |
sortBy | string | RECOMMENDED | Search mode only. Result ordering; changes the order results arrive in, not which properties match. |
hasPool | boolean | false | Search mode only. Must have a pool. |
hasGarage | boolean | false | Search mode only. Must have a garage. |
hasAirConditioning | boolean | false | Search mode only. Must have air conditioning. |
isWaterfront | boolean | false | Search mode only. Waterfront only. |
singleStoryOnly | boolean | false | Search mode only. Single story only. |
has3dTour | boolean | false | Search mode only. Must have a 3D tour. |
openHouseOnly | boolean | false | Search mode only. Open house only. |
priceReducedOnly | boolean | false | Search mode only. Price reduced only. |
startUrls | array | one example of each link shape | URL mode only. zillow.com search links (walked automatically) or property links ending in _zpid. Search-mode filters are ignored in this mode. |
fetchDetails | boolean | false | Read the property page for each result. Adds description, year built, HOA fee, property tax rate, MLS id and name, listing agent and brokerage, full photo gallery, parking and the fact sheet. Billed per enriched result. |
maxItems | integer | 20 | Maximum number of results across every location or link. 0 means unlimited. |
maxPages | integer | 0 | Optional safety cap on search reads per location or link. 0 means no read limit; the run still stops at Max results. |
resumeFromRunId | string | none | Continue one interrupted run without returning or billing for rows already collected there. For recurring monitoring, use Incremental mode instead. |
incrementalMode | boolean | false | Return only new and changed results on scheduled runs against the same search. |
stateKey | string | none | Name a monitoring campaign to keep its state stable, or share state across differently configured runs. |
emitUnchanged | boolean | false | Also return (and bill) results unchanged since the last run. |
emitExpired | boolean | false | Also return (and bill) results that were present before and are no longer found, once a run has scanned the search end to end. |
ignoreFieldsForChanges | array | none | Incremental mode only. Field names that never, on their own, make a property UPDATED, for example zestimate. Use a dotted name such as resoFacts.hoaFee for a nested field. Ignored fields are still returned in every row. |
proxy | object | Apify Proxy, US | How this run reaches the site. The prefilled option is billed by traffic on top of the run itself. You can also supply your own connection URLs instead. |
mcpConnectors | array | none | Optional: send a summary of each record to apps you authorized under Integrations. |
notionParentPageUrl | string | none | Notion connector only: page under which item pages are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live listing.
{"id": "00000001","zpid": "00000001","url": "https://www.zillow.com/homedetails/00000001_zpid/","listingType": "FOR_SALE","homeStatus": "FOR_SALE","statusText": "Active","propertyType": "SINGLE_FAMILY","price": 612000,"formattedPrice": "$612,000","currency": "USD","zestimate": 604800,"rentZestimate": 2875,"taxAssessedValue": 498000,"priceChange": -9000,"priceChangeDate": "2026-02-01T00:00:00.000Z","streetAddress": "142 Sample Ridge Dr","city": "Austin","state": "TX","zipCode": "78701","country": "USA","address": "142 Sample Ridge Dr, Austin, TX 78701","latitude": 30.30,"longitude": -97.70,"bedrooms": 4,"bathrooms": 3,"livingArea": 2100,"lotAreaValue": 8000,"lotAreaUnit": "sqft","daysOnZillow": 14,"heroImage": "https://photos.zillowstatic.com/fp/00000000-p_e.jpg","photos": ["https://photos.zillowstatic.com/fp/00000000-p_e.jpg"],"description": "Single story home with an open kitchen and a covered patio.","yearBuilt": 1995,"monthlyHoaFee": 60,"propertyTaxRate": 1.9,"pricePerSquareFoot": 291,"mlsId": "1234567","mlsName": "Sample MLS","listingAgentName": "Jordan Example","listingAgentPhone": "(555) 010-0100","brokerageName": "Sample Realty Group","resoFacts": {"parkingCapacity": 2,"propertySubType": ["Single Family Residence"]},"detailFetched": true,"scrapedAt": "2026-01-01T00:00:00.000Z"}
Plan Requirement
Zillow guards its pages with a bot-protection layer that refuses datacenter connections outright. Only residential connections work, so this actor needs a residential connection. The prefilled Proxy & connection setting (Apify Proxy, US) is residential and works out of the box; it is billed by traffic on top of the run itself. A plan without access to residential connections cannot use it: the run logs that the selected connection is unavailable (Apify free plans do not include residential proxies) and then ends as failed with a clear message, so upgrade your plan or supply your own residential connection URLs under Proxy & connection. A datacenter-only setup returns nothing. The actor rotates connections automatically when one is refused. When the residential connection is open on your account but the site keeps refusing its exits, the last attempt of each read goes over a backup connection, and the log says once when the backup served the data. Your own connection URLs never get a backup.
FAQ
How much does it cost?
You pay per result returned, plus a start charge per run. The property page read is a separate charge, applied once per enriched result and only when you switch it on and the record is actually returned. The Pricing tab shows the current rates. Use Max results to cap the cost of any run.
Is it legal to scrape Zillow?
This actor collects only publicly available listing data. You are responsible for how you use it: follow Zillow's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Listing facts (price, beds, baths, address) are generally usable, but photos, descriptions and estimates such as the home value figure may carry additional rights.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated properties, and unchanged ones are not billed. Keep Max results high (or 0) on these runs; a small cap can cause the run to stop scanning before it reaches a genuinely new or changed listing, and can return fewer rows, or none, even though changes exist. See the tips under How to Use for the exact mechanics.
Why did a scheduled run suddenly return a lot of EXPIRED rows?
Once a run scans its tracked search completely, previously tracked properties that are no longer found are returned as EXPIRED in that same run. These rows count toward Max results (the whole run, minus the rows already returned), so with a cap the leftover properties stay tracked and a later run reports them; with Max results 0 the whole batch comes at once, and a large swing in local inventory can make it bigger than you expect. Turn emitExpired off if you only want the new and updated delta.
What does it not return?
Coverage is US only. Price history, tax history and school assignments are not returned, because those tables are not published on the pages this actor reads.
Why did my run fail instead of returning an empty dataset?
If the site refuses every request, the run stops with the message "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later." (or, when the account is refused proxy access, "The proxy connection was refused for this account, so no page could be read ..."), so "no listings matched" is never confused with "nothing could be read". Run it again in a few minutes, and check that Proxy & connection is a residential one. A search that genuinely matches nothing ends with "No results matched. Widen the filters, or in URL mode check the link points at a zillow.com search or property page." Property page reads that keep failing stop early instead of being retried for the whole run. If only some locations or links could be read, you still get what was found, and the run says the scan was partial.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
π More scrapers you might like
Pair this actor with these related scrapers from the same team:
| π Redfin Scraper Scrape redfin.com home listings: price, beds, baths, sqft, lot, year built, coordinates... | π§© Homes.com Scraper Scrape US property records from Homes.com. Pick a city, state or ZIP and a channel (for... |
| π Realtor.com Extract property listings from realtor.com. Get comprehensive data, including prices... | π View.com.au Scraper Scrape View.com.au properties for sale, rent and recently sold across Australia. Search... |
| π Homes.co.nz Scraper Scrape Homes.co.nz listings by location or URL with pagination. Extract property details... | π Crexi Scraper Scrape crexi.com commercial listings: asking price, cap rate, square footage, units, year... |
π Browse all abotapi scrapers
π¬ Support
- π Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- π οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
- β Enjoying it? A quick review on the actor page helps other users find it.