# UK Property Tracker: Rightmove, Zoopla, OnTheMarket (`apizilla/uk-property-tracker`) Actor

Scrape UK homes for sale or rent from Rightmove, OnTheMarket and Zoopla in one run. Merges the same home across portals and tracks new listings, price drops, price rises and removed homes.

- **URL**: https://apify.com/apizilla/uk-property-tracker.md
- **Developed by:** [APIzilla](https://apify.com/apizilla) (community)
- **Categories:** Real estate, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 listing scrapeds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does UK Property Tracker do?

**UK Property Tracker** scrapes homes for sale and to rent from **[Rightmove](https://www.rightmove.co.uk)**, **[OnTheMarket](https://www.onthemarket.com)** and **[Zoopla](https://www.zoopla.co.uk)** (beta) in one run.

It finds the **same home on several portals** and gives you one record with links to all of them.

Turn on **monitor mode** and it tells you what changed since the last run: **new** homes, **price drops**, **price rises**, **removed** homes and homes that came **back** on the market.

Use it as a simple Rightmove API, OnTheMarket API or Zoopla API alternative.

### Why use UK Property Tracker?

Most scrapers read one portal. Then you must join the data yourself. This Actor does it for you.

- **One run, many portals.** Search Rightmove, OnTheMarket and Zoopla together.
- **No duplicates.** The same home on two portals becomes one record. You see the cheapest price and the other links.
- **Change feed.** Schedule it daily and get only what you need: new listings and price changes.
- **UK fields.** Tenure (freehold or leasehold), lease years left, council tax band, EPC rating, price wording like "Guide price" or "Offers over", service charge and ground rent.
- **Square metres and square feet.** Sizes in sq ft are converted to m2, so you can compare price per m2.
- **Same output as our Spain and Germany trackers.** One format for all three countries.

Good for buyers, renters, investors, estate agents, data teams and anyone who watches a local market.

You also get everything Apify gives you: schedules, API access, webhooks, integrations (Google Sheets, Slack, Make, Zapier) and proxy rotation.

### What data can UK Property Tracker extract?

| Field | Example | What it is |
|---|---|---|
| `price` | 725000 | Price in GBP. Rent is per month. |
| `priceQualifier` | Guide price | Price wording from the agent |
| `title` | 2 bedroom flat for sale | Listing title |
| `address`, `postcode`, `city` | Oakden Street, London, SE11 | Where the home is |
| `lat`, `lng` | 51.4928, -0.1099 | Map position |
| `bedrooms`, `bathrooms` | 2, 2 | Room counts |
| `sizeM2`, `sizeSqFt` | 85, 912 | Floor area |
| `pricePerM2` | 8529 | Price per square metre |
| `tenure` | leasehold | freehold, leasehold, share_of_freehold |
| `leaseYearsRemaining` | 95 | Years left on the lease |
| `councilTaxBand` | B | Council tax band |
| `epcRating` | C | Energy rating |
| `agencyName` | Example Estates | Estate agent |
| `alsoListedOn` | onthemarket, 725000 | Same home on other portals |
| `changeType` | price_drop | Change since the last run |
| `priceHistory` | \[750000, 725000] | Prices we have seen |
| `daysOnMarket` | 34 | Days since first seen |

Council tax, lease length, service charge and full description need **Include details** turned on.

### How to scrape Rightmove, Zoopla and OnTheMarket

1. Open the Actor and go to the **Input** tab.
2. In **Searches**, add a place, for example `{ "location": "Manchester", "operation": "sale", "maxPrice": 300000 }`. Or paste a search URL from Rightmove, OnTheMarket or Zoopla.
3. Pick the **Portals** you want.
4. Set **Max listings per portal**.
5. Turn on **Monitor changes** if you want a change feed.
6. Click **Start**.
7. Download your data as JSON, CSV, Excel or HTML, or read it with the API.

To track a market, save the input as a task and add a **schedule**, for example every morning.

### How much will it cost to scrape UK property portals?

This Actor uses pay per event pricing. You only pay for results. Failed pages cost nothing.

| Event | When you pay | Price per 1,000 |
| --- | --- | --- |
| `listing-scraped` | Once per unique home in the results | $2.00 |
| `browser-listing` | Once per saved home that comes from Zoopla (on top of `listing-scraped`) | $4.00 |
| `listing-details` | Once per home, only when Include details is on | $1.00 |
| `change-event` | Once per change (new, price drop, price rise, removed, back), only in monitor mode | $0.50 |
| `apify-actor-start` | When a run starts, set by Apify. One event per GB of memory | $1.25 (about $0.005 per run at the default 4 GB) |

Why is Zoopla more expensive? Zoopla blocks simple scrapers. We need a real browser and a home proxy for it. That costs us more, so a home from Zoopla has an extra `browser-listing` charge. A home that is also on Zoopla but comes from a cheaper portal does not pay it.

A removed home only costs a `change-event`. Unchanged homes do not cost a `change-event`.

You can set a maximum cost per run. The Actor checks the total price of all events for a home before it saves it. If they do not all fit, it stops. You never pay for a home that was not saved.

To keep costs low, leave Include details off, keep Max listings per portal small, and turn off the beta portal if you do not need it.

The Pricing tab shows the exact prices.

### Input

See the **Input** tab for all options. The main ones:

- **Searches**: a list. Each entry is a search URL or a simple search object:
  - `location`: a town, area or postcode, like "Kennington, London" or "SE11"
  - `operation`: "sale" or "rent"
  - `propertyType`: any, flat, house, detached, semi-detached, terraced, bungalow, land
  - `minPrice`, `maxPrice`: in GBP (rent is per month)
  - `minRooms`: minimum bedrooms
  - `minSize`: minimum size in m2
- **Portals**: rightmove, onthemarket, zoopla.
- **Max listings per portal**: default 200. Results are newest first.
- **Include details**: opens each listing page for more fields.
- **Monitor changes** and **Monitor ID**: keep the same Monitor ID on every scheduled run.

Example:

```json
{
  "searches": [
    { "location": "Kennington, London", "operation": "sale", "propertyType": "flat", "maxPrice": 800000, "minRooms": 2 },
    "https://www.rightmove.co.uk/property-to-rent/find.html?locationIdentifier=REGION%5E904&maxPrice=1500"
  ],
  "portals": ["rightmove", "onthemarket"],
  "maxListingsPerPortal": 100,
  "monitor": true,
  "monitorId": "kennington-flats"
}
```

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
[
  {
    "id": "gb-463bb373ef6e0243",
    "country": "GB",
    "portal": "rightmove",
    "url": "https://www.rightmove.co.uk/properties/123456789",
    "alsoListedOn": [{ "portal": "onthemarket", "url": "https://www.onthemarket.com/details/20000001/", "price": 750000 }],
    "title": "2 bedroom apartment for sale",
    "operation": "sale",
    "propertyType": "flat",
    "price": 750000,
    "currency": "GBP",
    "priceQualifier": "Offers in excess of",
    "sizeM2": 79,
    "sizeSqFt": 850,
    "pricePerM2": 9494,
    "bedrooms": 2,
    "bathrooms": 2,
    "address": "Example Place, London, SE11",
    "postcode": "SE11",
    "tenure": "leasehold",
    "leaseYearsRemaining": 995,
    "councilTaxBand": "E",
    "epcRating": "B",
    "changeType": "new",
    "daysOnMarket": 14
  },
  {
    "id": "gb-ea9a26bed8fa7cd4",
    "portal": "onthemarket",
    "title": "3 bedroom maisonette for sale",
    "price": 425000,
    "previousPrice": 450000,
    "changeType": "price_drop",
    "priceHistory": [{ "date": "2026-10-01T08:00:00.000Z", "price": 450000 }, { "date": "2026-10-22T08:00:00.000Z", "price": 425000 }]
  }
]
```

Each run also saves an **OUTPUT** record. It shows for each portal if it worked, was blocked, or was capped by your limit.

### How does the merge work?

Two listings are the same home when all of this is true:

- They are within 50 metres, or they have the same address.
- Their size is within 5%.
- They have the same number of bedrooms.
- Their price is within 10%.

When one portal does not show the size, we ask for both the same address and the same map position. The cheapest listing becomes the main record. The others go into `alsoListedOn`.

### Tips

- **Removed homes.** A home is only marked "removed" when the whole search finished. If you hit **Max listings per portal**, set it higher than the number of results.
- **Price changes.** The price is the lowest price across portals. If a cheaper copy shows up on another portal, you will see a price drop.
- **Zoopla is beta.** Zoopla has strong bot protection. Plain requests are blocked, even with a residential proxy. So the Actor opens Zoopla in a real browser (Firefox) with UK residential proxies, one page at a time, like a normal visitor. The Actor does not solve captchas. If Zoopla asks for one, Zoopla is skipped and the run summary says so. Rightmove and OnTheMarket do not need this and stay fast.
- **Location not found?** Paste a search URL from the portal instead of a place name.

### FAQ, disclaimers and support

**Is it legal to scrape UK property portals?** Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

**Does it work for Scotland, Wales and Northern Ireland?** Yes, wherever the portals have listings.

**Can I use it from my own code?** Yes. See the **API** tab.

**Something is wrong?** Open an issue in the **Issues** tab. Add your run link. We read every issue.

# Actor input Schema

## `searches` (type: `array`):

What to search. Each entry is either a search page URL copied from Rightmove, Zoopla or OnTheMarket, or a simple search object like {"location": "Manchester", "operation": "sale", "propertyType": "flat", "minPrice": 150000, "maxPrice": 300000, "minRooms": 2, "minSize": 50}. A simple search runs on every portal you turn on. operation is "sale" or "rent". propertyType is one of any, flat, house, detached, semi-detached, terraced, bungalow, land. minRooms means bedrooms. minSize is in square metres. Rent prices are per month.

## `portals` (type: `array`):

Which portals to scrape. Zoopla is in beta: it has strong bot protection and needs a residential proxy, so it is off by default.

## `maxListingsPerPortal` (type: `integer`):

Stop after this many listings on each portal. Results are sorted newest first. To get "removed" events in monitor mode, set this higher than the number of results of your search.

## `includeDetails` (type: `boolean`):

Open every listing page to get the full description, tenure, lease length, council tax band, EPC rating, service charge, ground rent and exact size. Slower and costs more. Off means list page data only.

## `browserForBeta` (type: `boolean`):

Zoopla (beta) blocks plain requests. When this is on, the Actor opens Zoopla in a real browser (Firefox) with a residential proxy, like a normal visitor. It is slower and costs more. It does not solve captchas: if Zoopla asks for one, Zoopla is skipped. Other portals always use fast plain requests.

## `monitor` (type: `boolean`):

Compare with the previous run and mark each home as new, price_drop, price_rise, removed, back or unchanged. Run it on a schedule to get a change feed.

## `monitorId` (type: `string`):

Name for the saved state of this tracker. Use the same name on every scheduled run. Leave empty to build a name from your searches.

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

Apify Proxy is used by default. Zoopla uses UK residential proxies automatically unless you pick proxy groups here.

## Actor input object example

```json
{
  "searches": [
    {
      "location": "Kennington, London",
      "operation": "sale",
      "propertyType": "flat",
      "maxPrice": 800000,
      "minRooms": 2
    }
  ],
  "portals": [
    "rightmove",
    "onthemarket"
  ],
  "maxListingsPerPortal": 20,
  "includeDetails": false,
  "browserForBeta": true,
  "monitor": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

One item per unique home, merged across portals

## `summary` (type: `string`):

Per portal status: works, blocked or capped, with counts

# 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 = {
    "searches": [
        {
            "location": "Kennington, London",
            "operation": "sale",
            "propertyType": "flat",
            "maxPrice": 800000,
            "minRooms": 2
        }
    ],
    "portals": [
        "rightmove",
        "onthemarket"
    ],
    "maxListingsPerPortal": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apizilla/uk-property-tracker").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 = {
    "searches": [{
            "location": "Kennington, London",
            "operation": "sale",
            "propertyType": "flat",
            "maxPrice": 800000,
            "minRooms": 2,
        }],
    "portals": [
        "rightmove",
        "onthemarket",
    ],
    "maxListingsPerPortal": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("apizilla/uk-property-tracker").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 '{
  "searches": [
    {
      "location": "Kennington, London",
      "operation": "sale",
      "propertyType": "flat",
      "maxPrice": 800000,
      "minRooms": 2
    }
  ],
  "portals": [
    "rightmove",
    "onthemarket"
  ],
  "maxListingsPerPortal": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call apizilla/uk-property-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apizilla/uk-property-tracker"
        }
    }
}
```

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/qGScDgRExGLOgOmRO/builds/HUKfATG7dsD3e5alK/openapi.json
