DEV Community

Cover image for Rightmove Scraper: pull UK property data to JSON for $0.002/listing
Devil Scrapes
Devil Scrapes

Posted on

Rightmove Scraper: pull UK property data to JSON for $0.002/listing

Quick answer: Rightmove is the UK's largest property portal and publishes no public API. A Rightmove scraper sends the same search request the browser makes and then optionally follows each detail page — returning price, address, bedrooms, bathrooms, EPC graph, floor plan URL, and agent phone as structured JSON. The Apify Actor below does it for $0.002 per listing (~$2.05 per 1,000 properties), with TLS fingerprint rotation, residential proxy, and exponential backoff handled for you.

If you've spent ten minutes on Rightmove hunting for a data download button, you already know it isn't there — by design, not oversight. The Land Registry publishes completed transactions and the ONS publishes aggregate indices, but neither gives you live asking prices, bedroom counts, agent contact details, EPC ratings, or floor plans at postcode granularity. For that you need the live portal, and the live portal requires a scraper.

This post covers the data shape, why a naive HTTP replay falls apart, and how to drive the Actor with the Apify Python SDK.

What is Rightmove? 🏠

Rightmove (rightmove.co.uk) is the UK's dominant residential property portal. It aggregates for-sale and to-rent listings from agencies across England, Scotland, Wales, and Northern Ireland, and is the canonical source of UK residential asking prices and letting-market data — for everyone from solo buy-to-let landlords to institutional PropTech analytics platforms.

It generates revenue by charging estate agents for listings and lead generation. There is no consumer-facing API and no bulk-data product for individual researchers; the official data-licensing product is priced for large institutional clients, not for solo founders or analysts running postcode-level research.

Does Rightmove have an API?

No — not a public one. Rightmove offers a private data feed to registered estate agents and a paid institutional data product to large property-data resellers. Neither is available to independent developers or researchers. The Property Data Trust Framework governs the UK property-data landscape, but it does not mandate a public API. Scraping the public search interface is the only practical route for anyone outside the agent ecosystem.

What the data looks like

Each listing comes back as one typed row. Here is a real example from the search-plus-detail enrichment path:

{
  "property_id": "167180126",
  "property_url": "https://www.rightmove.co.uk/properties/167180126",
  "address": "Gainsford Road, Walthamstow",
  "postcode": "E17 6ZL",
  "latitude": 51.587363,
  "longitude": -0.027555,
  "price_gbp": 300000,
  "price_qualifier": "Offers in Excess of",
  "price_frequency": null,
  "listing_type": "for-sale",
  "property_type": "Apartment",
  "property_type_full": "1 bedroom apartment for sale",
  "bedrooms": 1,
  "bathrooms": 1,
  "sqft": 443,
  "tenure": "LEASEHOLD",
  "epc_graph_url": "https://media.rightmove.co.uk/property-epc/.../...png",
  "epc_rating": null,
  "description": "A well-presented one bedroom apartment...",
  "key_features": ["Chain free", "Allocated parking", "EPC Rating D"],
  "listing_added_date": "2026-01-15T00:00:00+00:00",
  "listing_update_reason": "price_reduced",
  "agent_name": "haart, Walthamstow",
  "agent_phone": "020 3910 6244",
  "agent_url": "https://www.rightmove.co.uk/estate-agents/agent/haart/...",
  "photo_urls": ["https://media.rightmove.co.uk/...jpg"],
  "floor_plan_url": "https://media.rightmove.co.uk/property-floorplan/.../...jpeg",
  "scraped_at": "2026-05-31T09:14:02+00:00"
}
Enter fullscreen mode Exit fullscreen mode

Twenty-eight fields, the same shape every time. epc_rating is currently null — Rightmove publishes the EPC as an image, not a structured value; OCR it with Tesseract if you need the letter. Everything else drops straight into Pandas, BigQuery, or a property dashboard with no transformation.

The naive approach (and why it falls apart) 🔧

The first thing a scraper-aware developer tries:

  1. Open Chrome DevTools, copy the XHR request to Rightmove's internal search endpoint
  2. Replay it with requests.get()
  3. Parse the embedded JSON, paginate, done

It fails within a few requests. Three reasons, all load-bearing:

1. TLS fingerprint inspection. Rightmove's CDN inspects the JA3/JA4 TLS signature on your connection before serving a response. Python's stdlib SSL emits a signature that matches no real browser — the server returns a 403 or redirects to a CAPTCHA before your payload is even read. We rotate across Chrome, Firefox, and Safari TLS + HTTP/2 fingerprints via curl-cffi, so each connection looks like a real browser at the handshake level — because technically it is.

2. Session binding between search and detail pages. To pull the full dataset — floor plan URL, EPC graph, agent phone, full description — you need to follow each listing's detail page. Detail pages are bound to the same session as the search. Rotating IPs carelessly between the search and detail requests breaks the session. We thread Apify residential proxies with sticky sessions: each search run keeps one stable UK exit IP and cookie jar across all its detail requests, then rotates only when the target signals a block.

3. Pagination requires search-area resolution. Rightmove's search API takes an internal region/outcode identifier, not a free-form string. Getting from "Walthamstow" to the correct identifier requires a prior typeahead call. Naive replays skip this step and either query the wrong area or return zero results. We resolve every searchLocation through Rightmove's own typeahead endpoint before issuing the search, so you can pass "SW1A", "Manchester", or "Yorkshire and The Humber" and get the right results.

On 408 / 429 / 5xx we retry with exponential backoff (max 5 attempts), honour Retry-After headers, and surface partial success with a clear status message rather than returning an empty dataset and a green light.

The Actor 🚀

The result is the Rightmove UK Property Scraper on the Apify Store. Run it from the Console UI, or drive it programmatically:

from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("DevilScrapes/rightmove-uk-property").call(
    run_input={
        "searchLocation": "Walthamstow",
        "listingType": "for-sale",
        "maxPriceGbp": 400000,
        "minBedrooms": 1,
        "maxProperties": 100,
        "enrichDetails": True,
        "proxyConfiguration": {"useApifyProxy": True},
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["address"], item["price_gbp"], item["agent_phone"])
Enter fullscreen mode Exit fullscreen mode

Key inputs at a glance:

  • searchLocation — free-form UK location: city, district, postcode prefix, or region
  • listingType"for-sale" or "to-rent"
  • maxPriceGbp — price ceiling in GBP (total for sales, monthly for rentals)
  • minBedrooms — bedroom floor filter
  • maxProperties — hard cap, 1–1000 (Rightmove's own search caps at ~1,000 results per query)
  • enrichDetailstrue to follow each detail page for floor plan, EPC, full description, and agent phone; false for search-payload-only (halves request count)

The Apify Python client handles polling, dataset pagination, and error propagation. No webhook setup required for synchronous runs.

What you'd actually build with this 💡

Five concrete scenarios from the README and the marketing brief — not generic "property analytics":

1. Buy-to-let yield tracker across postcodes. Pull to-rent listings for 20 postcode districts weekly, join on for-sale median prices from the same postcodes, compute gross yield = (annual rent / sale price) × 100. Schedule via Apify's built-in scheduler; no server required.

2. Sub-£500k 2-bed buyer alert. Pull today's listings, compare property_id against yesterday's dataset, push net-new IDs to a Slack webhook via Make or n8n. First run sets the baseline; every run after is a diff.

3. Estate-agent directory for CRM. Pull agent_name + agent_phone + agent_url across 50 postcodes, deduplicate on agent_url, and you have a cold-outreach list of UK estate-agent branches with phone numbers.

4. Floor-plan + EPC enrichment pipeline. floor_plan_url and epc_graph_url are only populated when enrichDetails: true. Pull them, run a floor-plan digitizer and OCR the EPC image, and you get structured area-per-room + energy-rating data at scale. This is the wedge over scrapers that stop at the search page.

5. Academic housing-market dataset. Rightmove data is routinely cited in UK housing research. Export clean CSV or JSON from the Apify Console in one click — no wrangling before the analysis phase.

Pricing — exact numbers 💰

Pay-Per-Event. You pay for rows that land in your dataset; nothing for rows you asked for that didn't make it.

Event Price (USD) What it is
actor-start $0.05 One-off per run (warm-up, typeahead resolution)
result-row $0.002 Each property listing written to the dataset
Pull size Cost
50 listings (default) $0.15
500 listings $1.05
1,000 listings $2.05
1,000 listings × 5 postcodes/day ~$10.25/day

Apify's $5 free-trial credit covers your first ~2,500 listings with no credit card. Rightmove's own institutional data product is enterprise-priced; this Actor gives individual researchers and small PropTech teams the same raw data for a few pence per property.

The technically interesting bit

Location resolution is the hidden hard part. Rightmove's search endpoint requires an internal region identifier — not a postcode or city string. That ID comes from a typeahead API that maps free-form text to one of several namespaces (REGION, OUTCODE, POSTCODE, STATION, and others), each returning a different downstream structure. We resolve the searchLocation string through the typeahead first, pick the best-match identifier, and feed it into the search — which is why you can pass "Walthamstow", "E17", or "Yorkshire and The Humber" and get sensible results instead of a cryptic empty response.

Limitations 🚧

The honest list — no omissions:

  • ~1,000 results per query ceiling. Rightmove caps any single search at around 1,000 listings. To cover more, issue multiple queries (different postcode prefixes, tighter radius, different price bands).
  • epc_rating is always null. The EPC rating letter is not in Rightmove's JSON; it's rendered inside a graph image. epc_graph_url gives you the image; OCR it separately to get the letter.
  • Some agent phones are click-to-reveal. On certain listing types, the agent phone is hidden behind a JavaScript widget rather than present in the page HTML. In those cases agent_phone returns null.
  • enrichDetails: true doubles request count and run time. If you need only price, address, bedrooms, photos, lat/long, and agent name, set it to false — the search payload delivers those fields without any detail-page fetches.
  • No Zoopla or OnTheMarket. This Actor covers rightmove.co.uk only. Other portals need their own scraper.

FAQ ❓

Is scraping Rightmove legal?

Rightmove's ToS restricts automated bulk extraction and commercial redistribution. This Actor scrapes the public search interface at a polite pace, collects no personal data (phone numbers are business contact details published by estate agents), and is intended for research, personal investment analysis, and PropTech prototyping — not bulk resale. As always, review Rightmove's current Terms of Service and your own jurisdiction before running at scale.

Can I export to Google Sheets or a warehouse?

Yes — export CSV, Excel, or JSON directly from the Apify Console after a run, set up a webhook on ACTOR.RUN.SUCCEEDED to push to Make / n8n / Zapier, or pull via the Apify API to BigQuery, Postgres, or any other sink.

Is there a Rightmove API I'm missing?

No public one. Rightmove's private data feeds are for registered estate agents only, and the institutional data product is enterprise-priced. The Actor is the most accessible option for independent developers and researchers.

Does this work for rental listings?

Yes — set listingType to "to-rent". price_gbp is then the monthly rent figure and price_frequency reads "monthly". All other fields behave identically.

Try it

The Actor is live on the Apify Store: apify.com/DevilScrapes/rightmove-uk-property.

$5 free trial credit, no credit card. Run it on "Walthamstow" with enrichDetails: true and you'll have 50 fully enriched listings — with floor plans, EPC graph URLs, and agent phone numbers — in your dataset in a few minutes. Building something on top of this? Drop a comment below — we ship new fields based on what people are actually constructing.

Further reading:


Built by Devil Scrapes — Apify Actors with attitude. Pay-per-event, transparent pricing, no junk fields. 😈

Top comments (0)