Zillow Price Tax History Scraper
Pricing
from $15.00 / 1,000 results
Zillow Price Tax History Scraper
Property price and tax history scraper that outputs one flat row per event. Every sale, price change, and tax year becomes its own dataset record, ready to load into a spreadsheet or database without any post-processing.
Pricing
from $15.00 / 1,000 results
Rating
0.0
(0)
Developer
Kawsar
Actor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Zillow Price & Tax History Scraper, Flat Row-Per-Event Property Data Extraction
Most property data tools give you one blob of JSON per address. This actor works differently. Every price change, every sale, every tax year becomes its own row in the dataset. Load the results straight into a spreadsheet or database and you can sort by date, filter by event type, and calculate year-over-year trends without touching the data first.
Who this is for
Real estate investors who want to screen deals fast. Researchers building housing market datasets. Data teams who need property transaction history in a format that works with SQL, Excel, or any BI tool without a transformation step in the middle.
What you get
Two types of rows, both in the same dataset:
Price event rows cover every transaction and listing event on record for a property — sales, listings, price reductions, pending sales. Each row has the date, dollar amount, price per square foot, percentage change from the prior event, event label, MLS source, and agent names when available.
Tax record rows cover annual property tax history. Each row has the tax year, annual tax paid, year-over-year tax change as a percentage, assessed value, and assessed value change as a percentage.
All rate fields from the source are converted to plain percentages. There are no decimal fractions to convert on your end.
Input
Three ways to look up a property. Mix and match in any combination.
| Parameter | Type | Default | Description |
|---|---|---|---|
zpidIds | array of strings | — | Property IDs, one per line |
listingUrls | array of strings | — | Listing page URLs, one per line |
addressQueries | array of strings | — | Full street addresses, one per line |
timeoutSecs | integer | 300 | Total run time limit in seconds. Increase for larger batches. |
At least one of the first three is required. You can mix all three in a single run.
Setting timeout for larger batches
The default 300 seconds works for small runs. For bigger lists you need to increase timeoutSecs — and set the same value in your Apify actor run settings under Timeout:
| Properties | Recommended timeoutSecs |
|---|---|
| up to 10 | 300 |
| up to 30 | 1000 |
| up to 50 | 1800 |
| up to 100 | 3600 |
| 100+ | 3000 per 100 properties |
If the run hits the limit mid-batch, the actor stops cleanly and saves everything collected so far. It logs a warning so you can see exactly where it stopped and re-run with the remaining inputs.
How URL lookup works
Both of these URL formats are accepted without any change on your end:
https://www.zillow.com/homedetails/4315-Lago-Viento-Austin-TX-78734/58187131_zpid/https://www.zillow.com/homedetails/4315-Lago-Viento-Austin-TX-78734
The first has the property ID in the path. The actor pulls it out directly. The second does not — the actor reads the address slug from the URL and resolves the property ID automatically before fetching history. Same output either way.
Example input
{"zpidIds": ["58187131", "20482366"],"listingUrls": ["https://www.zillow.com/homedetails/4315-Lago-Viento-Austin-TX-78734/58187131_zpid/"],"addressQueries": ["4315 Lago Viento, Austin, TX 78734"]}
Output
One record per property, not one record per event. All price events and tax records are spread across flat numbered columns on a single row. A batch of 50 properties produces 50 rows, each up to 90 columns wide.
Sample output record
This is what a real record looks like. Each property produces exactly one row like this, with price events in price1* through price10* columns and tax records in tax1* through tax10* columns. Columns for entries that do not exist are simply absent.
{"inputQuery": "4315 Lago Viento, Austin, TX 78734","propertyId": "58187131","price1Date": "2026-02-11","price1Amount": 1299000,"price1PerSqft": 281,"price1Change": -1.96,"price1Event": "Listed for sale","price1Source": "Unlock MLS","price1Buyer": null,"price1Seller": null,"price2Date": "2023-09-20","price2Amount": 685000,"price2PerSqft": 249,"price2Change": -7.65,"price2Event": "Sold","price2Source": "ACTRIS","price2Buyer": "Shelly Martinez","price2Seller": "Shelly Martinez","price3Date": "2023-08-17","price3Amount": 741500,"price3PerSqft": 269,"price3Change": 0,"price3Event": "Listed for sale","price3Source": "ACTRIS","price3Buyer": null,"price3Seller": null,"price4Date": "2022-04-08","price4Amount": 741500,"price4PerSqft": 269,"price4Change": 8.25,"price4Event": "Sold","price4Source": "ACTRIS","price4Buyer": null,"price4Seller": "Jordan Whitfield","tax1Year": 2025,"tax1Amount": 14820,"tax1TaxChange": 3.62,"tax1AssessedValue": 612000,"tax1ValueChange": 2.15,"tax2Year": 2024,"tax2Amount": 14302,"tax2TaxChange": -1.34,"tax2AssessedValue": 598800,"tax2ValueChange": 8.71,"tax3Year": 2023,"tax3Amount": 14496,"tax3TaxChange": 4.88,"tax3AssessedValue": 550800,"tax3ValueChange": -3.22,"tax4Year": 2022,"tax4Amount": 13821,"tax4TaxChange": 6.14,"tax4AssessedValue": 569200,"tax4ValueChange": 21.43,"fetchedAt": "2026-04-17T10:32:00Z"}
Field naming pattern
| Pattern | Description |
|---|---|
inputQuery | The exact value you passed in — ID, URL, or address |
propertyId | Resolved property ID |
price{n}Date | Date of price event n |
price{n}Amount | Price in USD |
price{n}PerSqft | Price per square foot |
price{n}Change | Percentage change vs. the prior event. Negative = price dropped. |
price{n}Event | Event label: Sold, Listed for sale, Price change, Pending sale, etc. |
price{n}Source | MLS or data source name |
price{n}Buyer | Buyer agent name when disclosed |
price{n}Seller | Seller agent name when disclosed |
tax{n}Year | Tax year |
tax{n}Amount | Annual property tax paid in USD |
tax{n}TaxChange | Year-over-year change in tax paid as a percentage |
tax{n}AssessedValue | Assessed value in USD |
tax{n}ValueChange | Year-over-year change in assessed value as a percentage |
fetchedAt | ISO 8601 timestamp of when the record was retrieved |
error | Only present when the fetch failed after all retry attempts |
How the actor processes each input
- Property ID — goes straight to history lookup, no extra step.
- URL with ID in path — ID is extracted from the URL, no extra request.
- URL without ID — address slug is pulled from the path and used to resolve the property ID first, then history is fetched.
- Street address — property ID is resolved from the address first, then history is fetched.
Once the property ID is confirmed, the actor fetches up to 10 price events and 10 tax records. Everything goes into one flat record per property — price events as price1* through price10* columns, tax records as tax1* through tax10* columns. Rate fields are converted to plain percentages. Agent objects are flattened to name strings.
When something goes wrong
Every request retries up to 5 times. Wait time between retries: 1 second, 2, 4, 8. If all five fail, the actor writes a single error row for that property — with error and inputQuery filled in — and keeps going with the rest of the list. You can identify failed lookups by filtering for rows where the error field is not empty.