Zillow API in Python
Get listing price, status, Zestimate, rent Zestimate, photos and price history from a Zillow link or an address in a few lines of Python. Then batch a whole spreadsheet.
Base URL https://api.propertiesapi.com/v1 · auth header x-api-key. Zillow's own API needs Bridge approval. This tutorial uses PropertiesAPI, an independent service that returns Zillow property and listing data as JSON, provided as-is.
1. Set your key
Keep the key out of your code. Everything below uses requests. No SDK needed.
pip install requests pandas
export PROPERTIESAPI_KEY="your_key_here"2. Look up one Zillow link
Send any zillow.com/homedetails link as ?url=. A live lookup takes typically 6 seconds, up to about 20, so set a generous timeout. The body is { data, meta }.
import os, requests
BASE = "https://api.propertiesapi.com/v1"
session = requests.Session()
session.headers["x-api-key"] = os.environ["PROPERTIESAPI_KEY"]
r = session.get(
f"{BASE}/zillow/property",
params={"url": "https://www.zillow.com/homedetails/2640-Steiner-St-San-Francisco-CA-94115/15073305_zpid/"},
timeout=120,
)
r.raise_for_status()
home = r.json()["data"]
print(home["address"], home["homeStatus"])
print(f"Price ${home['price']:,}")
print(f"Zestimate {home['zestimate']} rent {home['rentZestimate']}/mo") # either can be None
print(home["beds"], "beds,", home["baths"], "baths,", home["livingArea"], "sqft, built", home["yearBuilt"])
print(home["daysOnZillow"], "days on Zillow,", len(home["photos"]), "photos")3. Or look up by address
No Zillow link? Send ?address= and we find the matching Zillow property first. The response is the same. An address lookup costs 1 credit, the same as a link.
r = session.get(
f"{BASE}/zillow/property",
params={"address": "2640 Steiner St, San Francisco, CA 94115"},
timeout=120,
)
body = r.json()
home = body["data"]
print(home["zpid"], home["detailUrl"], "cached" if body["meta"]["cached"] else "live")4. What comes back
{ data, meta }: data is the property, meta says whether it came from the 24-hour cache (free) and how many credits it used. Fields Zillow doesn't show for that property come back as null. Example values below are illustrative.
{
"data": {
"zpid": "2064142765",
"detailUrl": "https://www.zillow.com/homedetails/130-Water-St-APT-12D-New-York-NY-10005/2064142765_zpid/",
"address": "130 Water St APT 12D, New York, NY 10005",
"price": 995000,
"homeStatus": "FOR_SALE",
"homeType": "CONDO",
"beds": 2,
"baths": 2,
"livingArea": 1280,
"zestimate": null,
"rentZestimate": 4470,
"daysOnZillow": 38,
"imgSrc": null,
"photos": [],
"brokerName": "SERHANT.",
"priceHistory": [],
"taxHistory": []
},
"meta": {
"cached": false
}
}5. Handle errors and missing fields
Don't treat null as zero: a home that isn't for sale has no price, and some homes have no Zestimate. A 404 means we couldn't find a Zillow property. Failed lookups aren't billed.
import time
def lookup(**params):
"""params: url=... or address=..."""
for attempt in range(4):
try:
r = session.get(f"{BASE}/zillow/property", params=params, timeout=120)
except requests.Timeout:
continue # live lookup took too long: try again
if r.status_code == 404:
return None # no matching Zillow property (not billed)
if r.status_code >= 500: # 502/504 upstream, 503 busy (has retry-after)
time.sleep(int(r.headers.get("retry-after", 2 ** attempt)))
continue
if not r.ok: # 401 missing/invalid key, 400 bad input
raise RuntimeError(r.json()["error"]["message"])
return r.json()["data"]
raise RuntimeError(f"lookup failed after retries: {params}")
home = lookup(address="2640 Steiner St, San Francisco, CA 94115")
if home and home["zestimate"] is None:
print("Zillow shows no Zestimate for this home")6. Price and tax history
History comes back as lists, as shown on the Zillow page.
for e in home["priceHistory"]:
print(e["date"], e["event"], e["price"])
for t in home["taxHistory"]:
print(t["year"], "tax", t["taxPaid"], "assessed", t["value"])7. Batch a CSV of links or addresses
POST /v1/zillow/batch takes up to 50 Zillow URLs or addresses per request. Results come back in data, in order, each with ok. Lookups run live, so a full batch can take a few minutes: use a long timeout. Billed per successful live lookup; cache hits are free.
import pandas as pd
inputs = pd.read_csv("homes.csv")["zillow_url"].dropna().tolist() # or an "address" column
rows, failed = [], []
for i in range(0, len(inputs), 50):
chunk = inputs[i:i + 50]
r = session.post(f"{BASE}/zillow/batch", json={"items": chunk}, timeout=320)
r.raise_for_status()
for item in r.json()["data"]:
(rows if item["ok"] else failed).append(item)
df = pd.json_normalize([item["data"] for item in rows])
df[["address", "homeStatus", "price", "zestimate", "rentZestimate", "beds", "baths", "livingArea"]].to_csv("homes_out.csv", index=False)
print(len(rows), "found,", len(failed), "failed (not billed)")Zillow API Python questions
Is there an official Zillow API Python library?+
No. Old packages such as python-zillow wrapped the legacy ZWSID API, which was retired in 2021, so they no longer work. Zillow's current APIs go through Bridge Interactive by application.
Is this Zillow's official API?+
No. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow. It returns what the public Zillow page shows, provided as-is, with no guarantee of accuracy or completeness.
Is there a PropertiesAPI Python SDK?+
Yes: the official client installs with pip from this site (see the SDKs page; it isn't on PyPI). The API is also plain HTTPS and JSON, so requests (or httpx) works without it.
Why does a lookup take so long?+
A live lookup fetches the property from Zillow at request time, so it takes typically 6 seconds, up to about 20. Set a timeout of about 120 seconds for single lookups and about 320 for batches. Repeat lookups of the same home within 24 hours come from cache, for free.
How many lookups do I get for free?+
50 free lookups, once, with no card and no approval. Paid plans (lookups a month): Starter $29/mo (4,000); Pro $79/mo (11,500); Business $199/mo (30,000); Scale $499/mo (80,000). Overage is your plan's rate per 1,000 lookups, shown on each plan. Or pay as you go: $10 per 1,000 lookups, prepaid, in packs from $20 for 2,000 lookups up to $250 for 25,000 lookups. No subscription; credits last 12 months, and on a plan they are used after its included lookups. Buying a pack ends the free trial: from then on lookups use your prepaid credits. Repeat lookups of the same home within 24 hours are free. Failed lookups aren't billed.
Related guides
- Build a Property Research Dashboard with Python
Build a local dashboard for a property shortlist using an API snapshot. Compare returned addresses, listing prices, estimates, errors, and collection times.
- Zillow API errors: decide what to fix, review, or retry
Handle Zillow API validation, authentication, ambiguous addresses, quotas, and transient failures with a bounded retry policy.
- Enrich a Property Address List with Python and Export to CSV
Turn an address spreadsheet into property data with a downloadable Python script. Keep prices, Zillow estimates, collection times, and every failed row.
Your first call in Python
50 free lookups, no card, no approval.
Zillow is a trademark of Zillow, Inc. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow.