# Zoopla Scraper \[$0.50/1K💰] | UK Property | Leads (`ahmed_jasarevic/zoopla-scraper`) Actor

Scrape Zoopla.co.uk for UK property listings: sale and rental prices, sold-price history, EPC ratings, agent contacts, floor area, tenure and council tax bands. Track price drops, monitor new listings and build agent lead lists across London, Manchester and all UK postcodes.

- **URL**: https://apify.com/ahmed\_jasarevic/zoopla-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Categories:** Real estate, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Zoopla Scraper 💰 $0.50/1K — UK Property Data, Sold Prices & Agent Leads

Scrape **Zoopla.co.uk** for UK property listings — sale and rental prices, **sold-price history**, **EPC ratings**, agent contacts, floor area, tenure and council tax bands. Track price drops, monitor new listings and build agent lead lists across London, Manchester and all UK postcodes.

### Main Use Cases

- **UK property price monitoring** — track asking prices and detect price drops across target postcodes
- **Investment analysis** — pull sold-price history, EPC ratings and price-per-sqft for yield models
- **Estate agency competitor research** — monitor which branches list what, where and at what price
- **Agent lead generation** — extract agent name, brand and phone per listing for outreach
- **Property database building** — build structured UK property datasets with UPRN for Land Registry joins
- **New listing detection** — schedule runs to catch fresh inventory as it appears

### What Data You Get

| Field | Type | Description |
|---|---|---|
| `listingId` | string | Unique Zoopla listing identifier |
| `url` | string | Listing URL |
| `listingStatus` | string | `for_sale` or `for_rent` |
| `title` | string | Listing title |
| `displayAddress` | string | Full address |
| `postcode` | string | UK postcode |
| `price` | string | Display price (formatted) |
| `priceValue` | integer | Numeric price value |
| `priceQualifier` | string | e.g. "Offers in region of" |
| `bedrooms` | integer | Number of bedrooms |
| `bathrooms` | integer | Number of bathrooms |
| `receptions` | integer | Number of reception rooms |
| `floorAreaSqft` | integer | Floor area in square feet |
| `propertyType` | string | terraced, detached, semi-detached, flat, etc. |
| `tenure` | string | freehold, leasehold, etc. |
| `councilTaxBand` | string | Council tax band (A-H) |
| `epcRating` | string | Energy Performance Certificate rating |
| `uprn` | string | Unique Property Reference Number |
| `agentName` | string | Estate agent branch name |
| `agentPhone` | string | Agent phone number |
| `latitude` / `longitude` | number | GPS coordinates |
| `soldPriceHistory` | array | Previous sale prices with dates and growth |
| `listingHistory` | array | Price changes and listing timeline |

### Example Output

```json
{
  "type": "zoopla_listing",
  "listingId": "71644137",
  "url": "https://www.zoopla.co.uk/for-sale/details/71644137/",
  "listingStatus": "for_sale",
  "title": "3 bed terraced house for sale",
  "displayAddress": "Heathlands Way, Hounslow TW4",
  "postcode": "TW4 5BU",
  "price": "\u00a3460,000",
  "priceValue": 460000,
  "priceQualifier": "Offers in region of",
  "bedrooms": 3,
  "bathrooms": 1,
  "receptions": 2,
  "floorAreaSqft": 754,
  "propertyType": "terraced",
  "tenure": "freehold",
  "councilTaxBand": "D",
  "epcRating": null,
  "uprn": "100021550601",
  "agentName": "Ambiance Property",
  "agentPhone": "020 7768 7515",
  "latitude": 51.460948,
  "longitude": -0.383781,
  "soldPriceHistory": [
    { "event": "Sold", "date": "October 2006", "price": "\u00a3185,000", "changeLabel": "\u00a335,000 (23.3%)" },
    { "event": "Sold", "date": "May 2002", "price": "\u00a3150,000", "changeLabel": null }
  ],
  "listingHistory": [
    { "event": "Listed", "date": "September 2025", "price": "\u00a3450,000", "changeLabel": null },
    { "event": "Price changed", "date": "September 2025", "price": "\u00a3460,000", "changeLabel": "\u00a310,000 (2.2%)" }
  ],
  "scrapedAt": "2026-08-24T09:00:00.000Z"
}
```

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `searchUrls` | array | **required** | Zoopla search URLs or direct listing URLs |
| `maxItems` | integer | `20` | Max listings per run (max 1000) |
| `maxPagesPerSearch` | integer | `5` | Result pages per search (each ~28 listings) |
| `scrapeDetails` | boolean | `true` | Fetch detail pages for EPC, UPRN, agent phone, sold history |
| `maxRequestsPerCrawl` | integer | `1100` | Hard safety cap on total HTTP requests |
| `proxyConfiguration` | object | UNBLOCKER, GB | Cloudflare-protected — UNBLOCKER or RESIDENTIAL required |

### How It Works

1. You provide Zoopla search URLs (for-sale or to-rent)
2. The actor loads search result pages through UK residential proxies
3. It extracts listing cards with Cheerio — price, beds, address, agent
4. With `scrapeDetails` enabled, it visits each listing's detail page for EPC, UPRN, sold-price history and agent phone
5. Results are saved to an Apify dataset (JSON, CSV, Excel)

### Price Monitoring & Scheduled Tracking

Schedule **daily or weekly runs** on your target postcodes and diff on `listingId` + `priceValue` to catch:

- **New listings** — properties that didn't appear in previous runs
- **Price drops** — listings where `priceValue` decreased
- **Sold properties** — listings that disappeared from search results

### Related Actors

- **Realtor.com Agent Scraper** (own) — US real estate agent data
- **Daft.ie Scraper** (own) — Irish property listings and BER ratings
- **Bayut Scraper** (own) — Gulf property data across 5 markets

### FAQ

#### Why do I need UNBLOCKER or RESIDENTIAL proxies?

Zoopla is protected by Cloudflare Turnstile which blocks plain datacenter IPs. The UNBLOCKER group solves the challenge automatically.

#### Can I scrape sold-price history?

Yes. With `scrapeDetails: true`, the actor extracts Land Registry sold-price data shown by Zoopla, including previous sale prices, dates and growth percentages.

#### What is UPRN and why does it matter?

UPRN (Unique Property Reference Number) is a consistent identifier that joins with Land Registry, council and Ordnance Survey datasets — great for data enrichment.

#### How do I detect price drops?

Schedule daily runs and compare `priceValue` across runs for the same `listingId`. A decrease indicates a price drop.

#### Is scraping Zoopla legal?

Scraping publicly available listing data is generally acceptable. You are responsible for compliance with Zoopla's Terms of Service and UK GDPR if processing personal data such as agent phone numbers.

### For AI Agents & LLM Apps

**Purpose:** Extract UK property listings from Zoopla — prices, sold history, EPC, agent contacts, UPRN and coordinates for investment analysis and market research.

**Minimal working input:**

```json
{
  "searchUrls": [{ "url": "https://www.zoopla.co.uk/for-sale/property/london/" }],
  "maxItems": 20
}
```

**Variant — rental listings with detail pages:**

```json
{
  "searchUrls": [{ "url": "https://www.zoopla.co.uk/to-rent/property/manchester/" }],
  "maxItems": 50,
  "scrapeDetails": true,
  "maxPagesPerSearch": 3
}
```

**Output fields:** `type`, `listingId`, `url`, `listingStatus`, `title`, `displayAddress`, `postcode`, `price`, `priceValue`, `priceQualifier`, `bedrooms`, `bathrooms`, `receptions`, `floorAreaSqft`, `propertyType`, `tenure`, `councilTaxBand`, `epcRating`, `uprn`, `agentName`, `agentPhone`, `latitude`, `longitude`, `soldPriceHistory`, `listingHistory`, `scrapedAt`.

**Behaviors an agent should know:**

- `searchUrls` is **required** — accepts search pages or direct listing URLs.
- `scrapeDetails: true` adds EPC, UPRN, agent phone, sold-price history but increases requests.
- UNBLOCKER or RESIDENTIAL proxy is required — datacenter IPs are blocked by Cloudflare.
- `maxItems` caps results; `maxPagesPerSearch` caps crawl depth — whichever limit is hit first stops the run.
- `soldPriceHistory` and `listingHistory` are arrays — may be empty if no data available.

**Billing:** ~$0.50 per 1,000 search-only listings; detail-enriched listings cost more.

### Legal & Compliance Disclaimer

This actor is an independent tool and is **not affiliated with, endorsed by, or sponsored by Zoopla**. It accesses only publicly available listing pages. Agent phone numbers may be personal data under UK GDPR — handle with care. You are responsible for compliance with Zoopla's Terms of Service and applicable law.

### SEO Keywords

zoopla scraper, uk property data, zoopla sold prices, uk property price monitoring, zoopla api alternative, uk estate agent leads, zoopla rental data scraper, epc rating data uk, property price drop tracker, london property data, uk property investment data, zoopla listing scraper, sold price history uk, uprn property data, council tax band data, manchester property data, uk property database, zoopla price tracker, estate agent contact scraper, uk real estate data extraction

# Actor input Schema

## `searchUrls` (type: `array`):

Zoopla search URLs (e.g. https://www.zoopla.co.uk/for-sale/property/london/ or https://www.zoopla.co.uk/to-rent/property/manchester/) or direct listing URLs (https://www.zoopla.co.uk/for-sale/details/71644137/). Search URLs are paginated and their listings are scraped; direct listing URLs are scraped individually.

## `maxItems` (type: `integer`):

Maximum number of property listings to save per run.

## `maxPagesPerSearch` (type: `integer`):

Maximum number of result pages to follow per search URL (Zoopla paginates with ?pn=N). Each Zoopla page holds ~28 listings. Note: Max Listings still applies first — extra pages are only fetched while the listing target isn't met.

## `scrapeDetails` (type: `boolean`):

Fetch each listing's detail page for EPC rating, UPRN, agent phone, sold-price history, tenure, council tax band and description. Disable for faster, cheaper runs (search-card data only). Note: detail-enriched listings are billed at the 'listing-detail' event price; search-only listings at the lower 'listing' event price.

## `maxRequestsPerCrawl` (type: `integer`):

Hard safety cap on total HTTP requests for the whole run (search pages + detail pages). Rule of thumb: Max Listings x (details ? 1 : 0.04) + a few search pages.

## `proxyConfiguration` (type: `object`):

Apify UNBLOCKER proxy is required — Zoopla is fronted by Cloudflare Turnstile which blocks plain HTTP clients. The UNBLOCKER group solves the challenge automatically.

## Actor input object example

```json
{
  "searchUrls": [
    {
      "url": "https://www.zoopla.co.uk/for-sale/property/london/"
    }
  ],
  "maxItems": 20,
  "maxPagesPerSearch": 5,
  "scrapeDetails": true,
  "maxRequestsPerCrawl": 1100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchUrls": [
        {
            "url": "https://www.zoopla.co.uk/for-sale/property/london/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/zoopla-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "searchUrls": [{ "url": "https://www.zoopla.co.uk/for-sale/property/london/" }] }

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/zoopla-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchUrls": [
    {
      "url": "https://www.zoopla.co.uk/for-sale/property/london/"
    }
  ]
}' |
apify call ahmed_jasarevic/zoopla-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/zoopla-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0pkfjDFet1W22Z5hp/builds/0jZzFcUxeHCihdhao/openapi.json
