Real estate
Rightmove Scraper: Sold Prices Data and Estate Agent Leads
Scrape Rightmove sold prices with full transaction history, and pull estate agent branch contacts for lead generation. Inputs, output and API examples.
Real estate
Scrape Rightmove sold prices with full transaction history, and pull estate agent branch contacts for lead generation. Inputs, output and API examples.
Rightmove is where most UK property research starts. Two of its datasets are especially useful in bulk: the house-prices pages, which show what properties actually sold for, and the estate agent branch pages, which list each office’s contact details. Neither comes with a public API.
Epic Scrapers has a Rightmove actor for each:
They solve different jobs, so this guide covers them separately.
Each sold property comes back as one record with:
address, propertyType, bedrooms, bathroomslatestTransaction with displayPrice, dateSold and tenurelocation.latitude and location.longitudedetailUrl (the Rightmove house-prices page) and imageInfo.unsizedUrlsearchLocation (the resolved outcode or area) and scrapedAtTurn on includeTransactionHistory and each record also gets a transactionHistory object: every recorded sale in transactions (price, deed date, tenure, change from the previous sale), plus propertyDetails with when the property was last advertised (advertisedFrom, advertisedTo, soldPropertyLastListed).
SW6, M20), an area name (Manchester), or a Rightmove house-prices URL.The same search as JSON, for flats sold in the last two years within half a mile of SW6, with sale history:
{
"location": "SW6",
"maxItems": 200,
"soldWithinYears": "2",
"propertyType": "FLAT",
"radius": "0.5",
"sortBy": "MOST_RECENT",
"includeTransactionHistory": true,
"proxyConfiguration": { "useApifyProxy": true }
}
Valid values:
| Input | Options |
|---|---|
soldWithinYears |
"1", "2", "3", "5", "10", "15", "20", "30" |
propertyType |
"" (any), DETACHED, SEMI_DETACHED, TERRACED, FLAT |
radius (miles) |
"0", "0.25", "0.5", "1", "3", "5", "10", "15", "20", "30", "40" |
sortBy |
MOST_RECENT, OLDEST, LOWEST_PRICE, HIGHEST_PRICE, ADDRESS |
Note that soldWithinYears and radius are strings, not numbers.
{
"uuid": "b1822394-aec6-4efe-ad1c-a7a2d09c7649",
"address": "88a, Orbain Road, London SW6 7JY",
"propertyType": "FLAT",
"bedrooms": 3,
"bathrooms": 1,
"detailUrl": "https://www.rightmove.co.uk/house-prices/details/b1822394-aec6-4efe-ad1c-a7a2d09c7649",
"latestTransaction": {
"displayPrice": "£686,000",
"dateSold": "17 Apr 2026",
"tenure": "LEASEHOLD"
},
"location": { "latitude": 51.47946, "longitude": -0.21141 },
"transactionHistory": {
"transactions": [
{
"displayPrice": "£686,000",
"displayDeedDate": "17 Apr 2026",
"tenure": "Leasehold",
"displayAbsoluteChange": "£0",
"absoluteChangeType": "NO_CHANGE"
}
],
"source": "LR",
"propertyDetails": {
"advertisedFrom": "March 2025",
"advertisedTo": "October 2025"
}
},
"searchLocation": { "id": "2519", "type": "OUTCODE", "name": "SW6" },
"scrapedAt": "2026-07-25T14:31:14.763Z"
}
Transaction history costs one extra request per property and is billed as a separate event, only when it succeeds. If it fails for a property, the record is still saved with transactionHistory: null. Leave it off for quick comps and turn it on for due diligence.
bedrooms, and you have a comps table for a valuation or offer.sortBy: "MOST_RECENT" and chart median sold price by property type.advertisedFrom and advertisedTo in propertyDetails give a rough marketing period before the sale.The branch scraper returns one record per branch ID:
branchId, name, brandName, rightmoveUrladdress, latitude, longitudetelephoneNumbers (each with label, number and a main flag) and emaildevelopment, resale, lettings: whether the branch does new builds, resales and lettingsfullDescription, summary, branchLogo, largeBranchLogo, branchPhoto, updateDate, scrapedAtFind branch IDs on Rightmove: open an estate agent’s branch page and take the number at the end of the URL, such as 292349 in https://www.rightmove.co.uk/estate-agents/agent/292349. Paste as many as you want into Branch IDs:
{
"branchIds": ["292349", "12345", "87654"]
}
That’s the only input. Batch runs with hundreds of IDs are the intended use.
{
"branchId": 292349,
"name": "King's Road Park",
"brandName": "Berkeley Group",
"address": "1 Sand's End Lane, London, SW6 2FP",
"telephoneNumbers": [
{ "label": "Tel", "number": "020 4572 7682", "main": true }
],
"email": "sales@kingsroadpark.co.uk",
"latitude": 51.47688773268107,
"longitude": -0.18908181465922225,
"development": true,
"resale": true,
"lettings": false,
"rightmoveUrl": "https://www.rightmove.co.uk/estate-agents/agent/292349",
"scrapedAt": "2026-07-25T11:40:40.569Z"
}
lettings, resale and development to target lettings-only offices or new-homes teams separately.branchId or rightmoveUrl to add addresses, coordinates and logos to existing agency records.brandName and plot latitude/longitude to see how chains and independents cover a region.Both actors run through the Apify API. In Python with apify-client:
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
sold = client.actor("epicscrapers/rightmove-sold-listings-scraper").call(run_input={
"location": "Manchester",
"maxItems": 500,
"soldWithinYears": "1",
"propertyType": "SEMI_DETACHED",
})
for row in client.dataset(sold["defaultDatasetId"]).iterate_items():
print(row["address"], row["latestTransaction"]["displayPrice"])
branches = client.actor("epicscrapers/rightmove-branch-scraper").call(run_input={
"branchIds": ["292349"],
})
for b in client.dataset(branches["defaultDatasetId"]).iterate_items():
print(b["name"], b["email"])
Or with cURL, returning items as CSV:
curl -X POST "https://api.apify.com/v2/acts/epicscrapers~rightmove-sold-listings-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN&format=csv" \
-H "Content-Type: application/json" \
-d '{"location": "SW6", "maxItems": 100, "soldWithinYears": "2"}'
Want the same kind of data outside the UK? The Idealista scraper guide covers Spain, Italy and Portugal, and the Subito scraper guide covers Italian classifieds and real estate.
Rightmove has feeds for agents uploading their own listings, but no public API for searching sold prices or agent directories. Scraping the public pages is the practical route.
Rightmove’s house-prices section is based on HM Land Registry records (source: "LR" in the output), combined with Rightmove’s own listing details like bedrooms and photos. Recent sales appear after they’re registered, which can take a few months.
Both actors read publicly visible pages and don’t log in. Sold-price records are public property data. Branch emails and phone numbers are business contacts, but UK GDPR and PECR still apply when you use them for marketing: have a legitimate interest, keep messages relevant, include an opt-out, and honour unsubscribes. Follow Rightmove’s terms too. This isn’t legal advice.
These two actors cover sold properties and estate agent branches. They don’t scrape live for-sale or to-rent listings.
Up to 10,000 per run via maxItems. For bigger areas, split the work by outcode or property type.
Try a single outcode with 50 sold listings, check the fields, then switch on transaction history or widen the radius. Run the Rightmove Sold Listings Scraper for sold prices, and the Rightmove Branch Scraper for estate agent contacts.