How to get Zillow listings in Python
By the end of this guide you have a CSV of Austin homes for sale under $450,000 with three or more bedrooms, from one script you can run again tomorrow. Everything below was run on 15 October 2026; the output table is what it returned.
Why scraping Zillow yourself breaks
- Zillow closed its public API years ago. Official data now runs through Bridge Interactive, which wants an MLS membership or a signed data agreement, and approval takes weeks.
- The search pages carry their results as JSON inside the HTML, so parsing is not the hard part. Getting the page is: Zillow sits behind PerimeterX, and requests from cloud servers are refused before any page loads.
- One map view returns at most about 500 homes. A whole city needs the map split into smaller tiles and the results de-duplicated.
- The internal queries the site uses change when Zillow ships a new release, so a scraper that worked last month can return nothing today.
None of that is impossible, but each point is code you then maintain. The rest of this guide uses Listingrail, which does the reading and hands back clean JSON. The Zillow API page has the official options with sources.
1. Get a key
One request with your email returns a key with 100 free listings. It is shown once, so keep it in an environment variable.
curl -X POST https://listingrail.com/v1/signup \
-H "content-type: application/json" \
-d '{"email": "you@example.com"}'
export LISTINGRAIL_KEY=re_...2. Search and save to CSV
Install requests (pip install requests), then run:
import csv
import os
import requests
r = requests.post(
"https://listingrail.com/v1/listings/search",
headers={"Authorization": f"Bearer {os.environ['LISTINGRAIL_KEY']}"},
json={"source":"zillow","location":"Austin, TX","maxPrice":450000,"minBeds":3,"limit":50},
timeout=300,
)
r.raise_for_status()
listings = r.json()["listings"]
fields = ["price", "currency", "beds", "baths", "area", "address", "url"]
with open("zillow-austin-tx.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(fields)
for home in listings:
writer.writerow([home[k] for k in fields])
print(len(listings), "listings saved to zillow-austin-tx.csv")The request body, on its own:
{
"source": "zillow",
"location": "Austin, TX",
"maxPrice": 450000,
"minBeds": 3,
"limit": 50
}Each listing returned costs one credit. A search that finds nothing, or fails at Zillow, costs nothing. A request can take up to a minute or two, because Zillow is read at that moment.
3. What comes back
The first three rows of the run on 15 October 2026:
Every listing has the same keys on all 17 portals, so the code for Zillow reads the others too. Fields Zillow does not show come back as null, and the portal's own record sits in raw. With pandas:
import pandas as pd
df = pd.DataFrame(listings)
df["agent"] = df["agent"].str.get("company")
print(df[["price", "beds", "baths", "area", "address", "agent"]].head())4. Get new listings and price cuts every day
Running the script on a schedule works, but then you compare the files yourself. A monitor stores the search, checks it once a day, and sends only what changed: new listings and price cuts. The free key holds one monitor.
requests.post(
"https://listingrail.com/v1/monitors",
headers={"Authorization": f"Bearer {os.environ['LISTINGRAIL_KEY']}"},
json={
"source": "zillow",
"location": "Austin, TX",
"filters": {"maxPrice":450000, "minBeds":3},
"webhook_url": "https://example.com/new-listings",
},
timeout=30,
)Changes can also be read with GET /v1/monitors/{id}/changes or downloaded as CSV. Plans and limits are on the monitors page.
Zillow quirks worth knowing
- "zillow" is homes for sale. For rentals use "zillow-rentals" with the same location.
- Price filters and minimum bedrooms are sent to Zillow itself (minPrice, maxPrice, minBeds), so you are charged only for homes that match.
- area is living area in square feet (area_unit says so). agent.company is the listing brokerage.
- listed_at is empty in search rows: Zillow does not show it on the result card.
Questions
Is there a free Zillow API?
Not from Zillow for listing search. Listingrail's free key returns 100 listings, enough to build and test the script on this page.
Can I scrape Zillow with requests and BeautifulSoup?
Not reliably from a server. Zillow refuses most cloud addresses, and the page structure changes with each release. It can work from a home connection for a few pages.
How many Zillow listings can I get per request?
Up to 500 per request. Each listing returned costs one credit; a search that finds nothing costs nothing.