UK Property Sale Comps avatar

UK Property Sale Comps

Pricing

from $0.85 / 1,000 comparable sale delivereds

Go to Apify Store
UK Property Sale Comps

UK Property Sale Comps

Retrieve bounded HM Land Registry residential sales for permitted residential-price-information use only.

Pricing

from $0.85 / 1,000 comparable sale delivereds

Rating

0.0

(0)

Developer

Tim Zinin

Tim Zinin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Turn one to five exact England and Wales postcodes into a bounded Dataset of factual residential sales from HM Land Registry Price Paid Data. The Actor validates every fixed-source response before delivery, keeps the official attribution on every row, and never presents the result as a valuation or complete market coverage.

Exact postcodes become validated HM Land Registry sale rows

What you get

  • Transaction date and integer GBP price from the official Price Paid Data record.
  • Full postcode plus optional PAON/SAON, street, town, district, and county facts.
  • Property type, estate type, new-build flag, and transaction category.
  • Stable transaction URI, query and row fingerprints, source counts, and explicit truncation flags.
  • Exact HM Land Registry/Open Government Licence attribution and the permitted address-use boundary in every row.

The Actor returns zero to 100 rows in deterministic sale-date order. It is not a valuation: it does not estimate value, identify an owner or resident, enrich a contact, find listings, or claim that a bounded result is every relevant sale.

Who it is for

This Actor fits property-market researchers, residential price-information services, analysts, local-content teams, and automation builders who need a small, attributable comparable-sales input. It is designed for factual residential price context, not direct-mail prospecting, identity inference, credit or insurance decisions, tenancy screening, or an automated valuation model.

Quick start

Run public Task find-uk-property-sale-comps with a full postcode and inclusive date window:

{
"postcodes": ["PL6 8RU"],
"soldFrom": "2020-01-01",
"soldTo": "2026-08-31",
"propertyTypes": [],
"newBuild": "ANY",
"maxResults": 25,
"includePaonSaon": true
}

The example asks for at most 25 rows. At FREE-tier prices, set maxTotalChargeUsd to $0.038: one $0.013 Actor Start plus at most 25 delivered rows at $0.001 each.

Input reference

FieldRequiredMeaning
postcodesYesOne to five unique full England/Wales postcodes. Whitespace and case are normalized to canonical form.
soldFromYesFirst transaction date, inclusive, as a real Gregorian YYYY-MM-DD date.
soldToYesLast transaction date, inclusive; it must not precede soldFrom.
propertyTypesYesZero or more of DETACHED, SEMI_DETACHED, TERRACED, FLAT_MAISONETTE, OTHER; empty means all.
newBuildYesANY, YES, or NO.
maxResultsYesMaximum complete rows across all requested postcodes, from 1 to 100.
includePaonSaonYesInclude PAON/SAON address-object facts when the source supplies them.

Unknown fields, malformed or duplicate postcodes, impossible dates, unsafe characters, duplicate filters, and out-of-range limits fail as input_invalid before the source is contacted. Input cannot select a URL, query, proxy, browser, model, or credential.

How it works

  1. The Actor validates and normalizes the complete closed input.
  2. For each postcode, it builds one fixed SPARQL query to https://landregistry.data.gov.uk/landregistry/query; only validated postcode/date literals vary.
  3. It makes one fixed request per postcode with a 20-second timeout and a 1 MiB response limit. A transport failure or 429/selected 5xx status gets one bounded retry after 750 ms; every other response fails without retry.
  4. Every response must be identity-encoded SPARQL Results JSON with the exact expected variables, datatypes, official identifiers, and no more than 101 bindings.
  5. Duplicate transactions are collapsed only when all retained facts agree. Local filters, deterministic ordering, maxResults, fingerprints, and truncation flags are applied after every source response validates.
  6. The Actor checks the complete selected batch against row and batch size limits, then stores it in the default Dataset.
  7. In Pay Per Event runs, result-found is requested only after that complete Dataset write succeeds. A failed delivery never creates a named result charge.

There is no browser, proxy, geocoder, portal scrape, arbitrary SPARQL, redirect following, AI model, or downstream contact action. Source retry is limited to the one transient-failure retry described above.

Output Dataset

Factual comparable-sale fields, rights boundary, and paid delivery order

The default Dataset contains only complete factual sale rows. This field-complete example is based on the shipped bounded source fixture and illustrates the contract; it is not a live valuation or a claim that this transaction is currently representative:

{
"schemaVersion": "1.0",
"source": "hm-land-registry-price-paid-data",
"sourceEndpoint": "https://landregistry.data.gov.uk/landregistry/query",
"sourceDocumentationUrl": "https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads",
"sourceAttribution": "Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.",
"rightsBoundary": "CONDITIONAL_RESIDENTIAL_PRICE_INFORMATION_ONLY",
"rightsNotice": "Address fields are supplied only for personal/non-commercial use or display in residential property price information services unless separately licensed; no direct marketing, contact enrichment, identity inference, lead generation, or credit, insurance, or tenancy decisions.",
"securityNotice": "Fixed official HM Land Registry endpoint and closed SPARQL template only; buyer input cannot select a URL, query, proxy, browser, or LLM.",
"transactionId": "3B5CE841-9457-EE3A-E063-4804A8C0D6F1",
"transactionUri": "http://landregistry.data.gov.uk/data/ppi/transaction/3B5CE841-9457-EE3A-E063-4804A8C0D6F1/current",
"transactionDate": "2025-06-30",
"priceGbp": 217750,
"postcode": "PL6 8RU",
"paon": "104",
"saon": null,
"street": "PATTINSON DRIVE",
"town": "PLYMOUTH",
"district": "CITY OF PLYMOUTH",
"county": "CITY OF PLYMOUTH",
"propertyType": "SEMI_DETACHED",
"estateType": "FREEHOLD",
"newBuild": false,
"transactionCategory": "STANDARD_PRICE_PAID",
"requestPostcode": "PL6 8RU",
"requestSoldFrom": "2020-01-01",
"requestSoldTo": "2026-08-31",
"queryFingerprint": "fe1bbb433fa4840255062f4b5b29af793b058ed991a1db212a861d378e53a2ad",
"rowFingerprint": "efbab00b1a5864bb008727797c96780ce9e3560372895de4f3325820a17db633",
"sourcePostcodeBindingCount": 1,
"sourcePostcodeTruncated": false,
"resultPosition": 1,
"resultCount": 1,
"resultSetTruncated": false
}

Field interpretation

  • transactionUri and transactionId identify the HM Land Registry Price Paid Data transaction, not a current listing or a person.
  • priceGbp is the recorded price paid for the transaction; it is not an asking price, present value, forecast, or appraisal.
  • propertyType, estateType, newBuild, and transactionCategory are closed mappings of source facts. The Actor does not infer missing categories.
  • sourcePostcodeBindingCount describes the validated response for that requested postcode before global selection.
  • sourcePostcodeTruncated=true means the fixed query reached its 101-binding sentinel.
  • resultSetTruncated=true means the source sentinel or the buyer's maxResults prevented the delivered set from being represented as complete.
  • queryFingerprint identifies the exact fixed query; rowFingerprint identifies the normalized delivered facts. Neither is a source signature or proof of legal authenticity.
  • An empty Dataset means every source response validated but no row matched the declared filters. It does not prove that no relevant sale exists.

Pricing

The Actor uses Pay Per Event with only the automatic Actor Start and the primary result-found event. One result-found corresponds to one complete comparable-sale row already stored in the default Dataset.

TierActor startEach delivered sale25-row Task maximum
FREE$0.013000$0.001000$0.038000
BRONZE$0.012350$0.000950$0.036100
SILVER$0.011700$0.000900$0.034200
GOLD$0.011050$0.000850$0.032300
PLATINUM$0.010660$0.000820$0.031160
DIAMOND$0.010400$0.000800$0.030400

Cost is Actor start + delivered rows × row price. The hard 100-row maximum costs at most $0.113 on FREE pricing. Invalid input, source failure, failed Dataset delivery, and zero-result runs create no result-found; the automatic start charge still applies.

Before any source request, a paid run verifies its active event prices, prior counters, and capacity for the requested maximum batch. It fails closed instead of starting work that the run budget cannot fund. After delivery it validates the charge receipt and counter; inspect the original Run and Dataset before retrying an ambiguous client timeout.

API and automation

Start the public Task and wait for a terminal status. Replace USERNAME and keep the token outside source control and shared logs:

curl -X POST \
"https://api.apify.com/v2/actor-tasks/USERNAME~find-uk-property-sale-comps/runs?token=YOUR_APIFY_TOKEN&waitForFinish=240" \
-H "Content-Type: application/json" \
--data '{"postcodes":["PL6 8RU"],"soldFrom":"2020-01-01","soldTo":"2026-08-31","propertyTypes":[],"newBuild":"ANY","maxResults":25,"includePaonSaon":true}'

After a SUCCEEDED Run, read defaultDatasetId from the Run object and fetch its rows:

$curl "https://api.apify.com/v2/datasets/DEFAULT_DATASET_ID/items?clean=1&format=json&token=YOUR_APIFY_TOKEN"

In Make, use Apify's “Run a Task” module, select find-uk-property-sale-comps, wait for completion, then use “Get dataset items”. Branch on terminal status and resultSetTruncated before publishing or aggregating results.

In n8n, use an HTTP Request node for the Task run endpoint, verify status === "SUCCEEDED", then request the returned default Dataset. Preserve transactionId, queryFingerprint, and rowFingerprint as idempotency/provenance keys. Do not automatically retry a timeout: a paid Dataset batch may already exist even if the initiating client disconnected.

Source rights and attribution

The fixed source is HM Land Registry Price Paid Data, queried through its official linked-data endpoint. HM Land Registry permits commercial and non-commercial reuse of Price Paid Data under the Open Government Licence v3.0, subject to third-party address-data rights.

Every row includes the required statement: “Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.”

Royal Mail and Ordnance Survey permit the included address fields for personal/non-commercial use or display in residential property price information services. Other address-data use requires separate permission from Royal Mail. This Actor therefore limits its sellable scope to residential price information and explicitly prohibits direct marketing, contact enrichment, identity inference, lead generation, and credit, insurance, or tenancy decisions.

Security and data handling

  • Runtime permission is Apify LIMITED_PERMISSIONS; the Actor does not call another Actor or an AI service.
  • Buyer input cannot select the host, path, query syntax, protocol, proxy, browser, or redirect target.
  • Postcodes and dates pass closed validation before interpolation into a fixed SPARQL template.
  • Source responses use fatal UTF-8 decoding, strict datatypes and official identifiers, bounded streamed bodies, no followed redirects, and at most one transient-failure retry.
  • Retained address text rejects controls, format characters, and HTML-like markup; spreadsheet-formula prefixes are neutralized.
  • The runtime logs only safe aggregate counts and status codes, not input postcodes, address facts, source bodies, or arbitrary errors.
  • Apify stores run INPUT in the default Key-Value Store and successful rows in the default Dataset under account permissions and retention settings. Submit only the declared postcode/date/filter fields.

Hard limits

BoundaryLimit
Postcodes per run1–5
Source requests1–5
Automatic retries / followed redirectsAt most 1 / 0
Timeout per source request20 seconds
Response body per postcode1,048,576 bytes
Combined source bodies5,242,880 bytes
Source bindings per postcode101 sentinel rows
Delivered rows0–100
Encoded row / complete batch32,768 / 3,276,801 bytes
Actor memory / timeout128 MB / 240 seconds

Limits and interpretation

  • Price Paid Data excludes transactions that have not been lodged with HM Land Registry and sales that were not for value; source records can be corrected later.
  • The fixed query reads only the first 101 ordered bindings per postcode. Always inspect both truncation fields before treating the result as a bounded sample.
  • A postcode/date sample is not proof of neighbourhood comparability. Property condition, floor area, lease terms, tenure details, transaction circumstances, and current market conditions are outside the output.
  • Address fields are property-related source data, not evidence of current occupancy, ownership, identity, or consent to contact.
  • includePaonSaon=false suppresses those two Dataset fields but does not widen the permitted-use boundary or change the other returned address facts.
  • No result should be used alone for valuation, planning, legal, title, credit, insurance, tenancy, or investment decisions.

Troubleshooting

Why did the run report input_invalid?

Use complete England/Wales postcodes, real inclusive dates, unique closed filters, a 1–100 result limit, and no unknown keys. soldFrom must not follow soldTo.

Why did the run report source_request_failed or source_status_invalid?

The fixed HM Land Registry endpoint remained unavailable after its single bounded transient retry or returned another non-success response. Run again only after checking the original Run state.

Why did the run report source_shape_invalid?

The response did not match the closed factual contract, contained an unsupported source value, or included conflicting duplicate transactions. The complete run is withheld instead of guessing.

Why did the run report source_too_large or output_too_large?

A streamed source response or complete selected Dataset batch exceeded its fixed byte ceiling. Lowering maxResults may reduce output but cannot reduce the already bounded source response.

Why did the run report budget_insufficient or pricing_misconfigured?

The run cap could not fund the selected maximum rows, or active event pricing did not match the delivery contract. Increase maxTotalChargeUsd or lower maxResults; no Dataset delivery starts for this rejection.

Why is the Dataset empty?

No validated source transaction matched the input. The automatic Actor-start charge can still apply, but no result-found is charged.

FAQ

Does this Actor scrape Rightmove, Zoopla, or estate-agent listings? No. It makes only fixed queries to official HM Land Registry Price Paid Data.

Does it return a valuation or recommended offer? No. It returns factual recorded transactions and explicit sampling limits.

Can I search an address, owner, resident, or arbitrary radius? No. Input is limited to one to five exact postcodes and fixed factual filters.

Can I use the rows for direct mail or contact enrichment? No. That is outside the address-data permission and this product's contract.

Is every run charged for 25 rows? No. The named event is charged only for rows actually delivered; the Task cap merely funds the maximum. Actor Start is automatic.

Can zero results succeed? Yes. A fully validated zero-result run succeeds with an empty Dataset and no result-found charge.