# Zoopla Scraper — UK Property, Price Drops & Agents (`haketa/zoopla-scraper`) Actor

Scrape Zoopla UK property listings with price, price-drop % and date, bedrooms, size, address, coordinates and agent name & phone. Filter to reduced listings for deal hunting. For-sale & to-rent. JSON, CSV, Excel.

- **URL**: https://apify.com/haketa/zoopla-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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 — UK Property, Price Drops & Agents 🏡🇬🇧

![Property](https://img.shields.io/badge/data-UK%20property-2563eb)
![Price drops](https://img.shields.io/badge/track-price%20drops-e11d48)
![Agents](https://img.shields.io/badge/agent-name%20%2B%20phone-16a34a)
![Sale & rent](https://img.shields.io/badge/for--sale%20%26%20to--rent-supported-7c3aed)
![Format](https://img.shields.io/badge/output-JSON%20%7C%20CSV%20%7C%20Excel-f59e0b)
![No login](https://img.shields.io/badge/login-not%20required-0891b2)
![Pay per result](https://img.shields.io/badge/pricing-pay%20per%20result-0d9488)
![Maintained](https://img.shields.io/badge/status-actively%20maintained-22c55e)
![Support](https://img.shields.io/badge/support-responsive-3b82f6)

Turn any **Zoopla** search into clean, structured property data — with two things most Zoopla scrapers skip: **price-drop history** and **agent contact details**. Get price, **price-reduction % and date**, bedrooms, size, address, coordinates and the **agent's name & phone** for every listing.

> Filter on Zoopla the way you normally would (location, price, beds), paste the URL, press **Start**. Export to JSON, CSV, Excel — or pull it into your app via API.

***

### ✨ What makes this different

- 🔻 **Price-drop tracking** — for reduced listings you get the **reduction %** and the **date of the last price change**, plus a `hasPriceDrop` flag. Filter to *only reduced* properties to find motivated sellers and deals.
- 📞 **Agent contacts** — the **agent/branch name and phone number** for every listing — ready for lead generation and outreach.
- 🏠 **Full property detail** — price, price qualifier (Guide price / Offers over), bedrooms, bathrooms, living rooms, size, property type, `underOffer` status and tenure tags (Leasehold/Freehold).
- 📍 **Location & coordinates** — address plus latitude/longitude for mapping.
- 🖼️ **Media** — main image and image/floor-plan counts.

***

### 📦 Output per listing

| Field | Description |
|---|---|
| `title`, `propertyType` | Listing title & type (flat, house…) |
| `price`, `priceLabel`, `priceQualifier` | Numeric price, formatted price, qualifier |
| `hasPriceDrop`, `priceDropPercent`, `priceDropLastDate` | **Price-reduction signal** |
| `bedrooms`, `bathrooms`, `livingRooms`, `sizeSqft` | Property detail |
| `address`, `latitude`, `longitude` | Location |
| `agentName`, `agentPhone`, `agentUrl` | **Agent contact** |
| `underOffer`, `flag`, `tags` | Status & tenure |
| `image`, `numberOfImages`, `numberOfFloorPlans` | Media |
| `url`, `listingId` | Link & ID |

***

### 🚀 Quick start

1. Search on Zoopla and filter to what you want.
2. Copy the page URL.
3. Paste it into **Zoopla search URLs**, set **Maximum listings**, and optionally enable **Only reduced** or a **minimum bedrooms**.
4. Click **Start**.

#### Example input

```json
{
  "startUrls": [{ "url": "https://www.zoopla.co.uk/for-sale/property/london/" }],
  "onlyPriceDrops": true,
  "minBedrooms": 2,
  "maxItems": 500
}
```

***

### 📤 Example output

```json
{
  "listingId": "73971478",
  "url": "https://www.zoopla.co.uk/for-sale/details/73971478/",
  "title": "2 bed flat for sale",
  "propertyType": "flat",
  "price": 450000,
  "priceLabel": "£450,000",
  "priceQualifier": "Guide price",
  "hasPriceDrop": true,
  "priceDropPercent": 10.0,
  "priceDropLastDate": "6th May 2026",
  "bedrooms": 2,
  "sizeSqft": 720,
  "address": "Moor Lane, London EC2Y",
  "latitude": 51.5199, "longitude": -0.0902,
  "agentName": "Savills - Shoreditch",
  "agentPhone": "020 …",
  "underOffer": false,
  "tags": ["Leasehold"]
}
```

***

### 💡 Use cases

- **Deal hunting** — surface price-reduced listings and motivated sellers automatically.
- **Estate-agent lead generation** — build contact lists of agents by area.
- **Market & price analysis** — track asking prices, reductions and stock by location.
- **Property sourcing** — filter by beds, price and type for investment pipelines.
- **Data feeds** — power dashboards, alerts and comparison tools.

***

### 🔌 Run via API

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("YOUR_ACTOR_ID").call(run_input={
    "startUrls": [{"url": "https://www.zoopla.co.uk/for-sale/property/london/"}],
    "onlyPriceDrops": True,
    "maxItems": 500,
})
for p in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(p["address"], p["priceLabel"], p.get("priceDropPercent"), p.get("agentPhone"))
```

***

### ❓ FAQ

**Sale and rent both supported?** Yes — paste a `for-sale` or `to-rent` Zoopla URL.

**How do I get only reduced properties?** Enable **Only reduced** to keep listings with a recent price drop.

**Do I get the agent's phone number?** Yes — `agentName` and `agentPhone` are included for every listing.

**How many listings can I collect?** As many as you want — set `maxItems`; the scraper paginates automatically.

***

### ⚖️ Legal & responsible use

This actor collects **publicly available** property-listing information for legitimate purposes such as market research, lead generation and analytics. It is **not affiliated with, endorsed by, or connected to Zoopla** — all product and company names are trademarks of their respective owners.

You are responsible for how you use the collected data. Use it in compliance with applicable laws (including the GDPR and PECR for any outreach), the target website's Terms of Service, and relevant regulations. Respect rate limits and use the data ethically.

***

#### 💬 Support & feedback

Need an extra field, sold-price history, or another portal? Open an issue or send a message — feature requests are welcome and the actor is **actively maintained**.

# Actor input Schema

## `startUrls` (type: `array`):

Zoopla for-sale or to-rent search URLs. Filter on Zoopla (location, price, beds, property type…) and paste the resulting URL. The scraper paginates automatically.

## `onlyPriceDrops` (type: `boolean`):

Keep only properties whose asking price has recently been reduced — ideal for deal hunting and spotting motivated sellers.

## `minBedrooms` (type: `integer`):

Keep only listings with at least this many bedrooms. Leave empty to ignore.

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

Maximum number of listings to collect across all URLs.

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

Proxy settings. UK residential proxy is required for reliable results.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.zoopla.co.uk/for-sale/property/london/"
    }
  ],
  "onlyPriceDrops": false,
  "maxItems": 200,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# Actor output Schema

## `listingId` (type: `string`):

No description

## `url` (type: `string`):

No description

## `title` (type: `string`):

No description

## `propertyType` (type: `string`):

No description

## `price` (type: `string`):

No description

## `priceDropPercent` (type: `string`):

No description

## `bedrooms` (type: `string`):

No description

## `address` (type: `string`):

No description

## `agentName` (type: `string`):

No description

## `agentPhone` (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 = {
    "startUrls": [
        {
            "url": "https://www.zoopla.co.uk/for-sale/property/london/"
        }
    ],
    "maxItems": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/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 = {
    "startUrls": [{ "url": "https://www.zoopla.co.uk/for-sale/property/london/" }],
    "maxItems": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/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 '{
  "startUrls": [
    {
      "url": "https://www.zoopla.co.uk/for-sale/property/london/"
    }
  ],
  "maxItems": 200
}' |
apify call haketa/zoopla-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/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/QNEapE7lr4lZz8Q7G/builds/HRlFR1wTbAHQ8IEvS/openapi.json
