Zillow API in JavaScript
Fetch listing price, status, Zestimate, rent Zestimate, photos and price history from a Zillow link or an address, from Node.js or your own API route. Then batch a whole list.
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
Node 18+ has fetch built in. Keep the key on the server. Never ship it to the browser.
export PROPERTIESAPI_KEY="your_key_here"2. Look up one Zillow link
Send any zillow.com/homedetails link as ?url=, or a plain address as ?address=. A live lookup takes typically 8 seconds, up to about 20, so set a timeout. The body is { data, meta }.
const BASE = "https://api.propertiesapi.com/v1";
const headers = { "x-api-key": process.env.PROPERTIESAPI_KEY };
const url = new URL(`${BASE}/zillow/property`);
url.searchParams.set("url", "https://www.zillow.com/homedetails/130-Water-St-APT-12D-New-York-NY-10005/2064142765_zpid/");
// or: url.searchParams.set("address", "1600 Main St, Austin, TX 78701");
const res = await fetch(url, { headers, signal: AbortSignal.timeout(120_000) });
if (!res.ok) throw new Error((await res.json()).error.message);
const { data: home, meta } = await res.json();
console.log(home.address, home.homeStatus, res.headers.get("x-cache"), `${meta.credits} credit(s)`);
console.log(`Price $${home.price?.toLocaleString()} · Zestimate $${home.zestimate?.toLocaleString()} · rent $${home.rentZestimate}/mo`);
console.log(`${home.beds} beds · ${home.baths} baths · ${home.livingArea} sqft · ${home.daysOnZillow} days on Zillow`);3. Type the response
Any field Zillow doesn't show for a property comes back as null. Don't treat null as zero. The main fields (the docs list all of them):
type ZillowProperty = {
zpid: string | null;
detailUrl: string | null;
address: string | null;
city: string | null; state: string | null; zipcode: string | null;
latitude: number | null; longitude: number | null;
homeStatus: string | null; // "FOR_SALE", "FOR_RENT", "RECENTLY_SOLD", "OFF_MARKET", ...
price: number | null;
zestimate: number | null;
rentZestimate: number | null;
beds: number | null; baths: number | null; livingArea: number | null;
lotSize: number | null; yearBuilt: number | null; homeType: string | null;
daysOnZillow: number | null;
imgSrc: string | null;
photos: string[];
priceHistory: { date: string | null; event: string | null; price: number | null }[];
taxHistory: { year: number | null; taxPaid: number | null; value: number | null }[];
brokerName: string | null; agentName: string | null;
// ...and more: see /docs/endpoints/property
};
type PropertyResponse = {
data: ZillowProperty;
meta: { credits: number; cached: boolean; cache_key: string; fetched_at: string; took_ms: number };
};4. Handle errors and retries
A 404 means we couldn't find a Zillow property, and failed lookups aren't billed. Retry timeouts and 5xx with a backoff (a 503 carries retry-after).
async function lookup(params: { url: string } | { address: string }): Promise<ZillowProperty | null> {
const u = new URL(`${BASE}/zillow/property`);
for (const [k, v] of Object.entries(params)) u.searchParams.set(k, v);
for (let attempt = 0; attempt < 4; attempt++) {
let r: Response;
try {
r = await fetch(u, { headers, signal: AbortSignal.timeout(120_000) });
} catch {
continue; // timed out: the live lookup took too long, try again
}
if (r.status === 404) return null; // no matching Zillow property
if (r.status >= 500) {
const wait = Number(r.headers.get("retry-after")) || 2 ** attempt;
await new Promise((ok) => setTimeout(ok, wait * 1000));
continue;
}
if (!r.ok) throw new Error((await r.json()).error.code); // 401 missing/invalid_api_key, 400 bad_param
return ((await r.json()) as PropertyResponse).data;
}
throw new Error("lookup failed after retries");
}5. Call it from your own API route
Proxy through your server so the key stays secret. A Next.js route handler, for example:
export async function GET(req: Request) {
const link = new URL(req.url).searchParams.get("url") ?? "";
const u = new URL("https://api.propertiesapi.com/v1/zillow/property");
u.searchParams.set("url", link);
const r = await fetch(u, {
headers: { "x-api-key": process.env.PROPERTIESAPI_KEY! },
signal: AbortSignal.timeout(120_000),
});
const body = await r.json();
return Response.json(r.ok ? body.data : body.error, { status: r.status });
}6. Batch 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 give a full batch a long timeout. Billed per successful live lookup; cache hits are free.
import { readFile, writeFile } from "node:fs/promises";
const inputs = (await readFile("zillow-links.txt", "utf8")).split("\n").map((l) => l.trim()).filter(Boolean);
const found = [], failed = [];
for (let i = 0; i < inputs.length; i += 50) {
const r = await fetch(`${BASE}/zillow/batch`, {
method: "POST",
headers: { ...headers, "content-type": "application/json" },
body: JSON.stringify({ items: inputs.slice(i, i + 50) }), // links or addresses
signal: AbortSignal.timeout(320_000),
});
if (!r.ok) throw new Error((await r.json()).error.message);
for (const item of (await r.json()).data) (item.ok ? found : failed).push(item);
}
await writeFile("homes.json", JSON.stringify(found.map((x) => x.data), null, 2));
console.log(`${found.length} found, ${failed.length} failed (not billed)`);Zillow API JavaScript questions
Is there an official Zillow API for Node.js?+
No. npm packages such as node-zillow wrapped the legacy ZWSID API, which was retired in 2021. 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.
Can I call the API from the browser?+
Don't: it would expose your key. Call it from your server or a serverless function and pass the result to the browser.
Is there a JavaScript SDK?+
A TypeScript SDK is planned. Today the API is plain HTTPS and JSON, so fetch is all you need.
How many lookups do I get for free?+
50 free lookups, once, with no card. Paid plans (lookups a month): Starter $29/mo (2,500); Pro $79/mo (7,500); Business $199/mo (20,000); Scale $499/mo (65,000). Overage is your plan's own per-lookup rate ($11.60 per 1,000 on Starter, down to $7.68 on Scale). Repeat lookups of the same home within 24 hours are free. Failed lookups aren't billed.
Your first call in JavaScript
50 free lookups, no card. Join the list; keys go out as we open accounts.
Zillow is a trademark of Zillow, Inc. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow.