# Rightmove Properties Scraper (`scrapyx/rightmove-properties-scraper`) Actor

UK properties for sale and to rent from Rightmove: address, price, bedrooms, tenure, geo coordinates, selling agent, images and listing dates. Search by place name - locations are resolved for you.

- **URL**: https://apify.com/scrapyx/rightmove-properties-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.26 / 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/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

## Rightmove Properties Scraper

UK properties **for sale and to rent** from Rightmove — address, price,
bedrooms, bathrooms, tenure, **latitude/longitude**, the selling agent,
images and listing dates.

Search by plain place name; locations are resolved for you. HTTP only, no
browser, no login.

### Input

```json
{
  "channel": "buy",
  "locations": ["London", "Bath"],
  "minPrice": 300000,
  "maxPrice": 750000,
  "minBedrooms": 2,
  "maxPages": 5
}
```

`locations` also accepts a Rightmove identifier (`REGION^87490`) or a full
Rightmove search URL, so you can paste whatever you already have.

### What you get

| `recordType` | One per | Carries |
| --- | --- | --- |
| `SEARCH_SUMMARY` | location | resolved identifier and display name, **other matches for an ambiguous name**, upstream match count, the reachable ceiling, pages fetched, duplicates dropped, how many rows were featured |
| `PROPERTY` | listing | id, URL, address, price, bedrooms/bathrooms, tenure, geo coordinates, agent, images, listing dates — plus the raw upstream object |
| `ERROR` | failed input | why |

```jsonc
{
  "recordType": "PROPERTY",
  "propertyId": 148711631,
  "propertyUrl": "https://www.rightmove.co.uk/properties/148711631",
  "displayAddress": "One Hyde Park, Knightsbridge, London, SW1X",
  "propertySubType": "Apartment",
  "bedrooms": 5, "bathrooms": 5,
  "price": 60000000, "priceDisplay": "£60,000,000", "currency": "GBP",
  "latitude": 51.501871, "longitude": -0.161945,
  "tenure": "LEASEHOLD",
  "agentName": "Global 1, London",
  "isFeatured": false
}
```

### Known limits — read these before you rely on the output

**Rightmove reports far more matches than you can actually retrieve.** A
London sale search reports **59,420** matches, but paging is capped at
roughly **1,025 properties** — index 1000 returns rows, index 1025 returns
none. The count is not a lie about the market; it is a lie about what is
reachable. Both numbers are on every summary (`upstreamResultCount` and
`reachableCeiling`), and the run logs a warning when they diverge.

**To get past the ceiling, narrow the search rather than paging deeper** —
price bands, bedroom counts, or smaller locations (borough instead of
"London"). Several narrow searches beat one wide one.

**Featured listings are placed first regardless of sort.** Between 2 and 9 of
every 25 rows are promoted, so the top of a price-sorted page is routinely
out of order. Every row carries `isFeatured`, and the summary reports
`featuredRowsReturned`, so you can drop them before sorting yourself.

**Sale and rent prices are not the same kind of number.** Rent rows carry
`priceFrequency: "monthly"` and an `allDisplayPrices` list holding both
"£5,000 pcm" and "£1,154 pw". Comparing a rent `price` to a sale `price`
without reading the frequency compares one month's rent to a purchase price.

**A price of £1 is a real listing, not a parsing bug.** Auction and guide-price
listings carry a nominal amount with a `priceQualifier` such as "Guide Price".
They are flagged with `isNominalPrice` rather than being dropped or nulled.
Separately, some listings display **"POA"** while still carrying a real
`price` — the amount is present even though the site hides it.

**Ambiguous place names pick the top match.** "London" resolves to
`REGION^87490`, but Rightmove also offers Wimbledon, Central London and South
London for that query. The runners-up are reported in the summary as
`locationAlternatives`, so you can tell when you got a different Richmond
than you meant. Pass an identifier directly to be certain.

**Bad filter values return an empty page, not an error** — so this actor
refuses unknown sorts, property types, channels and radii up front. Without
that, a typo would look like "nothing matched" rather than "you sent a bad
filter".

**Rightmove's own property categories are loose.** A `bungalow` search returns
some rows sub-typed `Land` or `Detached`. That is upstream's classification,
passed through unchanged.

### Technical

Server-rendered Next.js; the whole page of results is strict JSON inside
`<script id="__NEXT_DATA__">` at `props.pageProps.searchResults` — no HTML
parsing at all. 25 properties per page, paged with `&index=` in steps of 24.

**The TLS fingerprint pool is an allowlist, not a preference.** On the same
URL, `chrome124`, `chrome120`, `safari17_0`, `safari15_5` and `edge101` all
return 200, while `chrome131` and `firefox133` are refused with an empty-body
403\. Only verified-passing profiles are used, so a retry can never rotate
into a guaranteed block.

`robots.txt` was checked at **path** level on both hosts used — the search
path and the location typeahead.

Full recon trail is in `CRAWLING_METHOD.md`.

# Actor input Schema

## `channel` (type: `string`):

Properties for sale or to rent. Rent rows carry a price frequency (monthly) that sale rows do not - comparing a rent amount to a sale amount without reading it compares a month of rent to a purchase price.

## `locations` (type: `array`):

Where to search. Accepts a plain place name (London, Bath, Manchester), a Rightmove identifier (REGION^87490), or a Rightmove search URL. Names are resolved through Rightmove's own location lookup; when a name is ambiguous the runners-up are reported in the summary, so you can see whether you got the Richmond you meant.

## `sortBy` (type: `string`):

Result ordering. Note Rightmove places featured and premium listings FIRST regardless of sort, so the top rows of a sorted page are routinely out of order - every row carries isFeatured so you can filter them before sorting yourself.

## `minPrice` (type: `integer`):

Lower price bound in GBP. For rent this is per month. Verified to genuinely narrow results.

## `maxPrice` (type: `integer`):

Upper price bound in GBP. For rent this is per month.

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

Lower bedroom bound. Verified: a value of 4 returned only 4+ bed properties.

## `maxBedrooms` (type: `integer`):

Upper bedroom bound.

## `radius` (type: `integer`):

How far beyond the location to search, in miles. Only Rightmove's own steps are accepted: 0, 0.25, 0.5, 1, 3, 5, 10, 15, 20, 30, 40 — any other value is refused. 0 is the location itself; larger values genuinely widen the result set (London at 0 miles = 59,420 matches, at 10 miles = 102,280).

## `propertyTypes` (type: `array`):

Optional filter: bungalow, detached, flat, land, park-home, semi-detached, terraced. An unrecognised type is refused here, because Rightmove answers one with an empty page rather than an error - which would read as nothing matched. Note Rightmove's own categories are loose: a bungalow search returns some rows sub-typed Land or Detached.

## `maxPages` (type: `integer`):

Pages to fetch per location; each page is 25 properties. Paging is capped by Rightmove at roughly 1,025 properties per search no matter how many matches it reports - see the actor README.

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

Optional cap on total property rows across the run, shared across every location. Counted after de-duplication.

## `maxConcurrency` (type: `integer`):

How many requests may be in flight at once. Only matters when several locations are listed; paging within one is sequential.

## `minRequestInterval` (type: `number`):

The honest speed control: the shortest gap between two request starts. Search pages are about 1.2 MB each.

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

Residential with no country pin is the cloud default. Rightmove is UK-only and prices are GBP, so the proxy country does not change your data. Note the actor uses a fixed allowlist of TLS fingerprints - some Chrome and Firefox builds are refused outright by the site.

## Actor input object example

```json
{
  "channel": "buy",
  "locations": [
    "London"
  ],
  "sortBy": "default",
  "radius": 0,
  "propertyTypes": [],
  "maxPages": 5,
  "maxConcurrency": 2,
  "minRequestInterval": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/rightmove-properties-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/rightmove-properties-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 '{}' |
apify call scrapyx/rightmove-properties-scraper --silent --output-dataset

```

## MCP server setup

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