Zillow Property Scraper — Agent Details & Price History avatar

Zillow Property Scraper — Agent Details & Price History

Pricing

from $2.40 / 1,000 results

Go to Apify Store
Zillow Property Scraper — Agent Details & Price History

Zillow Property Scraper — Agent Details & Price History

Look up any Zillow home by property ID or link. Take the whole record, including the listing agent's name, email and phone number, the Zestimate, the taxes, the description and every photo. Or take its history instead: every price cut and sale, the tax bill by year, schools and comparable homes.

Pricing

from $2.40 / 1,000 results

Rating

0.0

(0)

Developer

The Netaji

The Netaji

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

16 days ago

Last modified

Share

Zillow Property Scraper

Everything Zillow holds on a home, from its property ID or a link to it. There are two jobs here, and scraperType picks which one a run does.

Who is selling this house, and what is it? The property record carries the listing agent's name, email address and telephone number, the brokerage and the MLS, the price and the Zestimate, the tax bill, the structure and location, the listing description, every photograph at full width, the complete RESO fact set, and the page view, save and tour counts Zillow publishes nowhere a visitor can see. The contact details and the demand counts are the part no Zillow page renders.

What has this house done over time? The history record carries every price event Zillow records for the home, the assessed value and tax bill year by year, the schools attached to it, and the comparable homes nearby.

Both jobs take the same list of homes and cost one request per home, which is why they are one Actor rather than two.

Accepted input

zpid is the list of homes to read. Zillow property links and bare property identifiers are both accepted and may be mixed in the same list; the same home given twice under two spellings is read once. Every row produced by Zillow Search Scraper and Zillow Sitemap Scraper carries a zpid field holding exactly the value this field accepts, so a discovery run feeds into this Actor unchanged.

scraperType is propertyDetails by default, and propertyHistory for the second mode.

{
"scraperType": "propertyDetails",
"zpid": [
"2146999031",
"https://www.zillow.com/homedetails/2146999031_zpid/"
]
}

The Actor takes an identifier rather than an address on purpose. The address half of a Zillow property link is decorative: /homedetails/2146999031_zpid/ and /homedetails/any-slug-at-all/2146999031_zpid/ both resolve to the same home. A link assembled from an address is therefore not validated by anything, and it fails silently by returning a different house rather than by returning nothing.

Response fields: the property record

{
"zpid": "2146999031",
"price": 480000,
"zestimate": 468600,
"rent_zestimate": 1936,
"last_sold_price": 43000,
"bedrooms": 3,
"bathrooms": 2,
"living_area": 1600,
"year_built": 1911,
"county": "Cook County",
"agent_name": "Luis Ortiz",
"agent_phone": "708-990-4079",
"broker_name": "RE/MAX Partners",
"mls_name": "MRED as distributed by MLS GRID",
"page_view_count": 197,
"favorite_count": 20,
"days_on_zillow": 23,
"photo_count": 61
}

Who is selling the home arrives as agent_name, agent_email, agent_phone, broker_name, broker_phone, mls_id, mls_name, listing_agreement and true_status. None of these is rendered on the Zillow page itself. agent_email is null more often than not; a telephone number is stated far more consistently than an email address. mls_id is only unique inside the feed that issued it, so it should be read together with mls_name. true_status is the MLS's own status word before Zillow mapped it onto its own smaller set, which is not always the same value as home_status.

How much attention the listing is getting arrives as page_view_count, favorite_count and tour_view_count. A save is a logged-in action by somebody who intends to return, so its ratio to the view count behaves as a conversion rate for the individual home. All three are worth reading against days_on_zillow; 197 views over 23 days describes a different listing from 197 views in one.

The money fields are price, currency, zestimate, rent_zestimate, last_sold_price, date_sold, price_change and price_change_date_display, with tax_annual_amount, property_tax_rate and monthly_hoa_fee beside them. A null monthly_hoa_fee means the home has no association, which is a different statement from a fee of zero. The Zestimate is a model output rather than a listed figure and is stated even for homes that are not for sale, so the gap between it and price is Zillow's opinion rather than a fact about the market.

The structure arrives as bedrooms, bathrooms, living_area, lot_size, lot_area_value, lot_area_units, year_built, home_type, property_type, listing_type and contingent_listing_type. lot_size and lot_area_value describe the same lot in different units; lot_area_units names the second one.

The location arrives as street_address, city, state, zipcode, country, county, neighborhood, community, subdivision, latitude, longitude and time_zone. county is stated here and nowhere else in the response, and it is the join key for public tax and deed records. neighborhood is frequently null, which means Zillow names none rather than that the home has none.

photos holds every photograph of the home at the widest size available, deduplicated; 61 were returned for the sampled property. photo_count counts what actually arrived rather than repeating a figure the page printed.

reso_facts is republished whole, under Zillow's own key names such as bathroomsThreeQuarter and garageParkingCapacity, and is the one field in the response that does not follow this Actor's naming. RESO is the real-estate industry's own interchange standard and its field names are the format, so renaming them would destroy the portability that makes the object worth carrying. The object is also flat, wide and variable, at roughly a hundred facts of which any listing carries a different subset, so a fixed shape would either invent columns or drop real ones.

Response fields: the history record

{
"zpid": "2146999031",
"street_address": "2114 S Trumbull Ave",
"city": "Chicago",
"price_history": [
{ "date": "2025-08-01", "price": 480000, "event": "Price change", "price_change_rate": -0.03 }
],
"tax_history": [
{ "time": 2024, "tax_paid": 3210, "value": 162000, "tax_increase_rate": 0.041 }
],
"schools": [
{ "name": "Marshall Elementary", "rating": 3, "level": "Elementary", "grades": "PK-8", "distance": 0.4 }
],
"nearby_homes": [
{ "zpid": "2077663766", "price": 415000, "home_status": "SOLD", "bedrooms": 3, "bathrooms": 2 }
]
}

price_history holds every listing, price cut and sale Zillow records for the home, newest first, each with its date, price, event, price_change_rate stated as a rate rather than a percentage, and source. tax_history holds the assessed value and tax bill by year with tax_increase_rate and value_increase_rate; the assessed value is what the county taxes the home on, and it is neither the market value nor the Zestimate. schools holds name, rating out of ten, level, grades, distance in miles, assigned and link. nearby_homes holds comparable homes, each with its own zpid, so a comparables set is a starting point rather than a dead end.

The four lists are returned on one row rather than split into four datasets, because they belong to the same home and are read in one request. Splitting them would produce a spreadsheet in which the price events and the tax years no longer line up with the house they describe.

An empty list is a real and complete answer meaning Zillow holds no such records; one San Francisco property I measured returns zero price events beside 25 tax rows, while a Chicago property returns 22 price events and 26 tax rows. A null on one of these fields is the rarer case in which the response did not carry the list at all. The two are kept distinct rather than flattened together, because otherwise "this home has never changed price" and "this did not arrive" become the same cell.

Questions

Why can the record and the history not arrive on one row? Because they come from two different documents. The page a property record is read from does not contain the price history, the tax history, the schools or the comparables; they are genuinely absent from it rather than withheld. Collecting them is therefore a second read, and I made it a mode rather than a checkbox so that a run reading agent contact details cannot quietly pay for a tax history nobody asked for. Running the same list twice and joining on zpid returns both.

One identifier produced no row, and the run did not fail. Why? Zillow served no home for it; either the identifier never existed, or the listing has been withdrawn. That home is skipped with a line in the run log and the remainder of the list continues. Twenty identifiers read from a listing last week will not all still resolve, and losing the other nineteen rows to one dead identifier is the wrong trade.

Why does assigned say null for a school that is obviously the local one? Zillow states that field only where the district publishes attendance boundaries it trusts. Null means Zillow does not say, rather than that the home is unassigned to the school.

Why is there no error column on the history record? Because it would be non-empty on almost every row while meaning nothing. Zillow answers this request with partial errors beside complete data as a matter of course; every response I have measured carried Failed to fetch visualizations while also returning 22 price events and 26 tax rows. A column reading "error" next to a full price history is a column somebody filters on, and filtering on it would discard the good rows. So it is not published, and the four lists are judged on their own contents. A request that genuinely failed does not produce a row at all: the identifier is skipped with a line in the run log.

Can prices be compared directly across nearby_homes? Not without reading home_status on each row first. The set mixes for-sale, sold and off-market homes, so a price there is an asking price on some rows and a sale price on others.

Why are some fields empty on a sold home? Not every record states every field, and a sold or off-market home states fewer than a live listing; description in particular is normally absent once a listing closes. Fields the record does not state are returned as null rather than omitted, so a column never silently changes width and "Zillow states nothing here" stays distinguishable from "the Actor did not look".

Is a Zillow account, cookie or API key required? No. No account, session cookie or key of any kind is supplied to the Actor or needed by it.

Zillow Search Scraper starts from a city, state or ZIP code rather than from a list of identifiers, and can merge the property record onto each listing row in the same run.

Zillow Sitemap Scraper supplies property identifiers in bulk from Zillow's published index, which is the cheapest way to assemble the list this Actor consumes.