Short answer: you cannot use a current public Zoopla listings API to scrape property pages. Zoopla’s official developer information says, “The Zoopla listings API is no longer publicly available.” Its Terms of Use also prohibit text or data mining and web scraping. If you need Zoopla data, request an authorised commercial feed, obtain the terms in writing, and build against the endpoint and limits Zoopla supplies.
The code below is a contract-first client template, not a way to bypass Zoopla’s controls. It becomes usable only after Zoopla gives you an approved base URL, credentials, fields, pagination rules and permission to store or redistribute the response.
Is there a public Zoopla listings API?
Not according to Zoopla’s current developer position as of 30 September 2026. The official developer portal states that “The Zoopla listings API is no longer publicly available.” Commercial users are directed to contact Zoopla to discuss data availability and possible listings API access.
That statement supersedes old blog posts, GitHub wrappers and tutorials that show API keys, listing-search endpoints or free quotas. Those materials describe a historical service; they do not establish that an endpoint, credential, quota or permission still exists.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Why a public-site scraper is not a compliant substitute
Zoopla’s Terms of Use say: “You shall not conduct, facilitate, authorise or permit any text or data mining or web scraping in relation to our Site.” The same section gives examples including a robot, bot, spider, scraper, automated device, program, tool, algorithm, code, process or methodology. The terms also state that site content may not be used for commercial purposes without a licence from Zoopla.
Rotating proxies, browser automation, CAPTCHA-solving services and generic scraping libraries change how requests are sent; they do not create permission to copy the site. Using them against public listing pages can breach the terms even when a page loads successfully. Do not present them as an API-access strategy.
What Zoopla documents today
The currently documented catalogue is aimed at members and business workflows rather than an open listing-search feed. Zoopla Member Support lists:
- Authentication
- Leads API
- Push Delivery Service
- Premium Listings
- Featured Properties (weekly)
For example, the premium-listings documentation describes member operations such as a POST request to activate a premium listing for a supplied listing ID, followed by authenticated status or update operations. That is a product integration for authorised members, not an invitation to harvest every public property page.
How to request authorised Zoopla data
- Define the use case. State whether you need internal analytics, lead routing, valuation research or a customer-facing product. Identify whether you need sale listings, rentals, sold-price information, agent fields or another dataset.
- Describe the data envelope. Give Zoopla your geography, fields, expected record volume, refresh interval, historical depth and retention period. Say whether data will be shown to customers, supplied to another business or used only internally.
- Use Zoopla’s official business or developer route. Ask whether a listings feed is available for your use case and request the current technical documentation and commercial terms.
- Get the permission in writing. Confirm the permitted use, geography, fields, refresh frequency, retention, redistribution, authentication method, endpoint host, pagination, rate limits, pricing, support process and termination or deletion requirements.
- Test a small authorised integration. Start with a low-volume account or sandbox if Zoopla provides one. Record the contract version, credentials owner, request identifiers and response errors.
- Operationalise the feed. Keep secrets on the server, enforce the published limits, validate every response, preserve the source timestamp and implement the agreed deletion and retention rules.
Questions to settle before writing production code
| Area | Ask Zoopla to confirm |
|---|---|
| Permission | Which applications and users may access the data, and is redistribution allowed? |
| Coverage | Sale, rental, sold-price and agent fields; geographic boundaries; listing types and exclusions. |
| Freshness | Update latency, change notifications, delisted-property handling and historical availability. |
| Transport | Base URL, HTTP methods, authentication scheme, TLS requirements and request-id conventions. |
| Limits | Page size, pagination cursor, rate limits, burst behaviour, maximum response size and retry guidance. |
| Storage | Retention period, backup rules, deletion requests and whether derived analytics may be kept. |
| Commercial terms | Price, billing metric, support hours, liability, suspension rules and termination procedure. |
Build a client only after the contract supplies an endpoint
Because no public listing endpoint is available, a truthful example must leave the host and field names supplied by your agreement. The following Python client is runnable after you set those contract-specific values. It deliberately does not fetch Zoopla’s public pages.
Python template
import os
import time
import requests
BASE_URL = os.environ["ZOOPLA_AUTHORIZED_BASE_URL"]
TOKEN = os.environ["ZOOPLA_AUTHORIZED_TOKEN"]
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {TOKEN}",
"Accept": "application/json",
})
params = {
# Replace these with names and values in your written agreement.
"location": os.environ.get("ZOOPLA_LOCATION", ""),
"page_size": int(os.environ.get("ZOOPLA_PAGE_SIZE", "100")),
}
records = []
next_cursor = None
while True:
request_params = dict(params)
if next_cursor:
request_params["cursor"] = next_cursor
response = session.get(BASE_URL, params=request_params, timeout=30)
request_id = response.headers.get("X-Request-Id")
if response.status_code == 429:
delay = int(response.headers.get("Retry-After", "10"))
time.sleep(delay)
continue
response.raise_for_status()
payload = response.json()
records.extend(payload.get("items", []))
next_cursor = payload.get("next_cursor")
print({"request_id": request_id, "received": len(payload.get("items", []))})
if not next_cursor:
break
print(f"Received {len(records)} authorised records")
Do not assume that items, cursor or page_size are Zoopla field names. Replace them with the names in the documentation attached to your agreement. Keep the access token in a secret manager or environment variable, never in source control or browser JavaScript.
Equivalent cURL request
curl --fail-with-body
-H "Authorization: Bearer $ZOOPLA_AUTHORIZED_TOKEN"
-H "Accept: application/json"
--get "$ZOOPLA_AUTHORIZED_BASE_URL"
--data-urlencode "location=$ZOOPLA_LOCATION"
--data-urlencode "page_size=100"
Use the exact authentication header, query names and endpoint Zoopla gives you. A successful HTTP response from another URL is not evidence that it is an authorised Zoopla feed.
Equivalent Node.js request
const baseUrl = process.env.ZOOPLA_AUTHORIZED_BASE_URL;
const token = process.env.ZOOPLA_AUTHORIZED_TOKEN;
const url = new URL(baseUrl);
url.searchParams.set('location', process.env.ZOOPLA_LOCATION || '');
url.searchParams.set('page_size', '100');
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
});
if (response.status === 429) {
throw new Error('Rate limited; apply the Retry-After value specified by the contract.');
}
if (!response.ok) {
throw new Error(`Zoopla request failed: ${response.status} ${await response.text()}`);
}
const payload = await response.json();
console.log(payload);
Data-quality and reliability controls
- Identity: retain the authorised listing identifier and source timestamp. Do not use an address alone as a permanent key.
- Duplicates: detect repeated identifiers across pages and runs before loading records into your warehouse.
- Staleness: track the last-seen time and the provider’s status or update timestamp. Treat missing updates as an operational alert, not proof that a property is still available.
- Schema changes: reject or quarantine responses with missing required fields; log unknown fields so an upstream change is visible.
- Retries: retry only transient failures and honour the documented back-off and
Retry-Afterbehaviour. Do not retry authentication or permission failures indefinitely. - Observability: store request IDs, status codes, latency, page counts and validation failures without logging access tokens or unnecessary personal data.
- Retention: run deletion jobs that match the contract. Backups and derived tables need the same review as the primary dataset.
Common errors and what they mean
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 or 403 | Missing, expired or unauthorised credentials; wrong product entitlement. | Check the account and authentication instructions with Zoopla. Do not try a public-page scraper as a workaround. |
| 404 | Legacy endpoint, wrong host or a path that is not part of your agreement. | Use the current endpoint supplied by Zoopla and verify the documentation version. |
| 429 | Rate or concurrency limit exceeded. | Stop, honour Retry-After, reduce concurrency and ask for the contractual limit if your workload needs more capacity. |
| Empty pages | Invalid filter, exhausted cursor, geographic restriction or no matching records. | Log the complete request parameters, validate them against the contract and distinguish an empty result from an expired cursor. |
| Fields disappear | Schema or entitlement change. | Quarantine the response, alert an owner and obtain the current schema before resuming. |
| Old tutorial returns data | Cached example, a different product or a legacy service. | Treat it as historical until Zoopla confirms current permission, endpoint, quota and credentials in writing. |
What to do with old wrappers and tutorials
Historical Python wrappers can help you recognise terminology or understand why older articles mention instant keys and listing queries. They cannot prove that those requests still work or that their use is permitted. The official developer position controls the current answer. Remove legacy credentials from copied examples, and do not publish a scraper based on an old request shape.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsIf Zoopla cannot provide the required feed
Evaluate another licensed UK property-data provider whose contract explicitly covers your intended fields, geography, refresh rate, storage and redistribution. Compare providers on permission and liability first, then coverage, freshness, pagination, rate limits, authentication, support and price. A page that can be fetched is not equivalent to a licensed data source.
Or skip the browser setup
If your actual requirement is a visual record of a page you are authorised to view—not a structured feed of Zoopla listings—ScreenshotNeo can take the screenshot through one API call. It is not a Zoopla listings API and does not grant permission to copy or republish site data. Use it only for pages and purposes your agreement allows.
ScreenshotNeo removes cookie-consent banners, newsletter popups and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
Here is the supplied one-call example; replace the target with a page you are authorised to capture:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://zoopla.co.uk -o shot.webp
See the ScreenshotNeo API documentation for request options. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account when a compliant screenshot workflow is what you need.
FAQ
Frequently Asked Questions
Can an old Zoopla API key still be used?
Do not rely on it. Ask Zoopla to confirm in writing that the credential, endpoint, quota and intended use remain active.
Can I store data returned through an authorised feed?
Only if the written agreement permits that retention. Confirm backup, deletion, derived-data and redistribution rules before storing responses.
Is a screenshot the same as a listings data feed?
No. A screenshot is an image of an authorised page; it does not provide structured listing fields or permission to extract and republish them.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

