# Land Registry Price Paid Data — UK House Prices by Postcode (`nexgensignal/uk-price-paid-transaction-records`) Actor

HM Land Registry Price Paid Data: residential sales in England and Wales since 1995 — price, date, postcode, property type, new build and tenure. Filter by postcode, district, date and price. Official files, no API key. Part of NexGen Signal — official-source data products

- **URL**: https://apify.com/nexgensignal/uk-price-paid-transaction-records.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** Lead generation, Real estate, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 price paid transactions

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?

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

## 🏠 Land Registry Price Paid Data — UK House Prices by Postcode

Get HM Land Registry's Price Paid Data as clean JSON — residential property sales in England and Wales since 1995, each with its price, transfer date, postcode, property type, new-build flag, tenure, town, district and county — straight from Land Registry's official yearly and monthly files.

Filter by postcode (area, district, sector or full postcode), local authority district, town, county, sale date, price, property type, new build, tenure and Price Paid category. Sales come newest first. Property-level address lines (house number or name, flat, street and locality) are not delivered — see Legal & ToS.

The unit of output is one **sale**: one Price Paid transaction. You pay per sale delivered; a run that finds nothing costs nothing.

### Who buys this and for what job

- **Property investors, agents and valuers** pulling comparable sales by postcode district and property type.
- **Proptech and AVM teams** loading Land Registry sales into pricing models and dashboards, and keeping them current with the monthly change file.
- **Mortgage, lending and insurance analysts** tracking prices and volumes by area, tenure and new build.
- **Researchers and journalists** studying house prices across England and Wales.

Buyers usually search for this as **"land registry price paid data"** or **"uk house prices by postcode"**.

### 📊 Sample Output

![Table of HM Land Registry sales in the M1 (Manchester city centre) postcode district: transfer date, price, postcode, property type and tenure.](https://api.apify.com/v2/key-value-stores/IXCaMKjxSmUTLHhmq/records/uk-price-paid-transaction-records.png)

| transfer_date | price_gbp | postcode | property_type | tenure | new_build |
|---|---|---|---|---|---|
| 2026-08-11 | 195000 | M1 2BQ | Flats/Maisonettes | Leasehold | false |
| 2026-07-31 | 205000 | M1 2WE | Flats/Maisonettes | Leasehold | false |
| 2026-07-27 | 210000 | M1 2EW | Flats/Maisonettes | Leasehold | false |
| 2026-07-24 | 350000 | M1 4DA | Flats/Maisonettes | Leasehold | false |
| 2026-07-24 | 200000 | M1 2BQ | Flats/Maisonettes | Leasehold | false |
| 2026-07-22 | 180000 | M1 5BY | Flats/Maisonettes | Leasehold | false |

Rows from live run `iBKjebqWHpBJ3KaUq` on Apify (the Store example: postcode district M1, 10 sales). Notice the newest sales first, read from the 2026 yearly file; prices are in pounds as stated on the transfer deed.

### ✅ What you get

Every field of each record:

- `record_id` — `PPD:<transaction id>`, stable for upserts.
- `transaction_id` — Land Registry's transaction unique identifier.
- `price_gbp` — sale price stated on the transfer deed, in pounds.
- `transfer_date` — date the sale completed (`YYYY-MM-DD`).
- `postcode`, `postcode_outward`, `postcode_area` — postcode at the time of sale, its outward code (e.g. `M1`) and area letters (e.g. `M`).
- `property_type_code`, `property_type` — D Detached, S Semi-Detached, T Terraced, F Flats/Maisonettes, O Other.
- `new_build` — true for a newly built property, false for an established building.
- `tenure_code`, `tenure` — F Freehold or L Leasehold.
- `town_city`, `district`, `county` — town or city, local authority district and county as Land Registry records them.
- `ppd_category_code`, `ppd_category` — A standard price paid entry; B additional entry (repossessions, buy-to-lets identified by a mortgage, sales to non-private buyers, 'Other' property types).
- `record_status_code`, `record_status` — A Addition, C Change, D Delete — meaningful in `latest_monthly_update` mode; yearly files carry A.
- `source_file`, `source_file_last_modified`, `source`, `source_url` — the Land Registry file read and its Last-Modified date.
- `licence`, `attribution`, `observed_at` — the attribution statement Land Registry requires, a source line and the UTC read time.

### ⚙️ Sample inputs

**1. The Store example — latest sales in one postcode district**

```json
{
  "postcodes": ["M1"],
  "maxRecords": 10
}
```

Returned the 10 sales above in run `iBKjebqWHpBJ3KaUq`, from pp-2026.csv (386,238 sales read, 116 in M1); $0.50 on the Free plan.

**2. One year, one district, one property type**

```json
{
  "districts": ["CARDIFF"],
  "years": [2025],
  "propertyTypes": ["T"],
  "maxRecords": 40
}
```

Returned 40 terraced-house sales in Cardiff, newest first, in run `YE52HOgc0RgL5UvyG` (974,087 sales read from pp-2025.csv, 2,026 matched).

**3. Keep a copy current with the monthly change file**

```json
{
  "mode": "latest_monthly_update",
  "districts": ["LEEDS"],
  "maxRecords": 20
}
```

Returned 20 Leeds rows from Land Registry's latest monthly update file (90,867 rows) in run `QhgY7pkWpvDWh70ld`, each with its record status: apply additions and changes, remove deletions, by `record_id`.

Input fields:

| Field | Meaning |
|---|---|
| `postcodes` | area (`M`), district (`M1`), sector (`M1 4`) or full postcode (`M1 4BT`). A district matches exactly: `M1` does not match `M11`. |
| `districts`, `towns`, `counties` | names as Land Registry writes them (any case), e.g. `MANCHESTER`, `EAST RIDING OF YORKSHIRE`. |
| `dateFrom`, `dateTo` | transfer date range; picks the yearly files for you. |
| `years` | yearly files to read (1995 onwards); empty = your dates, or the latest three years. |
| `propertyTypes` | D, S, T, F, O. |
| `newBuild` | `any`, `new_only`, `established_only`. |
| `tenure` | `any`, `freehold`, `leasehold`. |
| `category` | `all`, `standard_only` (A), `additional_only` (B). |
| `minPrice`, `maxPrice` | price range in pounds. |
| `mode` | `yearly` (default) or `latest_monthly_update`. |
| `order` | `newest_first` (default) or `oldest_first`. |
| `maxRecords` | stop after this many sales (1-100,000; default 1,000). |

### 🧾 JSON sample record

```json
{
  "record_id": "PPD:5A7B802C-D7F0-1886-E063-4704A8C021AE",
  "transaction_id": "5A7B802C-D7F0-1886-E063-4704A8C021AE",
  "price_gbp": 195000,
  "transfer_date": "2026-08-11",
  "postcode": "M1 2BQ",
  "postcode_outward": "M1",
  "postcode_area": "M",
  "property_type_code": "F",
  "property_type": "Flats/Maisonettes",
  "new_build": false,
  "tenure_code": "L",
  "tenure": "Leasehold",
  "town_city": "MANCHESTER",
  "district": "MANCHESTER",
  "county": "GREATER MANCHESTER",
  "ppd_category_code": "A",
  "ppd_category": "Standard price paid entry",
  "record_status_code": "A",
  "record_status": "Addition",
  "source_file": "pp-2026.csv",
  "source_file_last_modified": "Mon, 28 Sep 2026 05:12:21 GMT",
  "source": "HM Land Registry Price Paid Data",
  "source_url": "https://price-paid-data.publicdata.landregistry.gov.uk/pp-2026.csv",
  "licence": "Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.",
  "attribution": "HM Land Registry Price Paid Data (England and Wales)",
  "observed_at": "2026-10-12T02:52:12Z"
}
```

### 🔧 How it works

1. **Robots check.** The download host's `robots.txt` is requested on every run. It currently answers HTTP 403 (it is a file bucket), so no robots policy is readable; that is recorded in the receipt. A readable robots file that disallowed the files would stop the run with nothing charged.

2. **Pick the files.** Land Registry publishes one CSV per year of transfer date (`pp-1995.csv` … `pp-2026.csv`) and a monthly change file. The actor reads the years you name, the years your dates cover, or the latest three years.

3. **Stream and filter.** Each file is streamed and every sale checked against your filters as it arrives; the actor keeps the newest (or oldest) matches up to `maxRecords`. Because yearly files are collated by transfer date, it stops opening older files once it holds enough sales.

4. **Deliver, then charge.** Matches are pushed in batches, each charged after delivery, so records and charges always match.

5. **Receipt.** `RUN_RECEIPT` records the robots result, the files planned and read, rows read and matched, the address columns withheld, and delivered and charged counts.

No login, API key, proxy or bot workaround — Land Registry's public files only.

### 💰 Pricing example

Per sale delivered, no start fee, no monthly charge:

| Apify plan | Price per sale |
|---|---|
| Free | $0.05 |
| Bronze | $0.045 |
| Silver | $0.04 |
| Gold, Platinum, Diamond | $0.0335 |

- 10 records (the Store example): $0.50 on the Free plan, $0.335 on Gold.
- 1,000 records (the default cap): $50 on Free, $45 on Bronze, $40 on Silver, $33.50 on Gold.

**Coverage and size.** England and Wales only, from January 1995. On 28 Sep 2026 Land Registry's files held 974,087 sales dated 2025 and 386,238 dated 2026 (to August 2026). Land Registry notes that sales take two weeks to two months to be registered, so the two most recent months are incomplete. Excluded by Land Registry: sales not for value, right-to-buy discounts, transfers by gift, court order or compulsory purchase, and some other non-market transfers.

### ⚖️ Legal & ToS

Data: HM Land Registry Price Paid Data. Land Registry releases it under the Open Government Licence v3.0 and says it may be used "for commercial or non-commercial purposes". Every record carries the attribution statement Land Registry requires: "Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0."

**Address data.** Land Registry states that the OGL does not cover third-party rights: the address data in Price Paid Data comes from Ordnance Survey's AddressBase Premium, which incorporates Royal Mail's PAF, and Royal Mail and Ordnance Survey permit that address data only for personal and/or non-commercial use, or for display for the purpose of providing residential property price information services. This actor therefore does **not** deliver the house number or name, flat, street or locality of any sale; it delivers the postcode, town, district and county with each sale. No names of buyers or sellers exist in the data.

The download host's robots.txt is unreadable (HTTP 403), which is recorded on every run. Public files only, declared User-Agent, no login, key, proxy or form. Not affiliated with or endorsed by HM Land Registry.

### ❓ FAQ

**Do I need a Land Registry account or API key?**
No. The actor reads Land Registry's public download files.

**Why is there no street address?**
Royal Mail and Ordnance Survey restrict the address data inside Price Paid Data (see Legal & ToS), so the actor delivers postcode, town, district and county only.

**Does it cover Scotland or Northern Ireland?**
No. Price Paid Data covers England and Wales.

**How fresh is it?**
Land Registry refreshes the files monthly; `source_file_last_modified` shows the date of the file each sale came from.

**What are category B sales?**
Additional Price Paid entries Land Registry has collected since October 2013: repossessions, buy-to-lets where identified by a mortgage, sales to non-private buyers and 'Other' property types. Use `category: standard_only` to exclude them.

### 🆘 Troubleshooting

- **0 records for a postcode** — check the format: `M1` is a district and matches exactly; use `M` for the whole area or `M1 4` for a sector.
- **Run reads several files** — with no years or dates and a rare filter, the actor reads up to the latest three yearly files; set `years` or dates to control it.
- **Latest month looks small** — registrations lag sales by two weeks to two months; re-run after Land Registry's next monthly update.
- **District name not matching** — use Land Registry's own spelling, e.g. `EAST RIDING OF YORKSHIRE`; matching ignores case but not wording.
- **SOURCE UNAVAILABLE message** — the source did not answer after four tries; nothing was charged — run again later.
- **CAPPED message** — your maximum total charge was reached; raise it in the run options.
- **Run failed with "Invalid input"** — a filter value is malformed; the message names the field. Nothing was charged.

### 🔗 Related Actors

- [Ireland House Prices — Property Price Register Sales Search](https://apify.com/nexgensignal/ie-property-price-register-records) — the Irish equivalent, with sale prices by address.
- [Europe House Prices — Eurostat House Price Index (Quarterly)](https://apify.com/nexgensignal/eurostat-house-price-index) — house price indices across Europe.
- [UK Planning Applications — Camden, Worthing, Adur, Doncaster](https://apify.com/nexgensignal/uk-planning-application-records) — planning applications for selected councils.
- [UK Construction Output Monthly - ONS](https://apify.com/nexgensignal/uk-construction-output-observations) — construction output, including new housing.
- [UK CPIH Inflation Time Series - ONS](https://apify.com/nexgensignal/uk-cpih-time-series-observations) — UK inflation including owner-occupiers' housing costs.

🏢 **About NexGen Signal** — official-source data products from government and regulator publications. Browse the catalog: [apify.com/nexgensignal](https://apify.com/nexgensignal)

### ⭐ Found this useful?

If this actor saved you time, a rating on its Apify Store page helps other buyers find it.

Part of NexGen Signal — official-source data products.

# Actor input Schema

## `postcodes` (type: `array`):

Postcode area (M), district (M1, SW1A), sector (SW1A 1) or full postcode (SW1A 1AA). A district matches exactly: M1 does not match M11.

## `districts` (type: `array`):

District names as Land Registry writes them, e.g. MANCHESTER, CARDIFF, EAST RIDING OF YORKSHIRE (any case).

## `towns` (type: `array`):

Town or city names, e.g. MANCHESTER (any case).

## `counties` (type: `array`):

County names, e.g. GREATER LONDON, GREATER MANCHESTER (any case).

## `dateFrom` (type: `string`):

First transfer date wanted, e.g. 2025-01-01. Picks the yearly files for you.

## `dateTo` (type: `string`):

Last transfer date wanted, e.g. 2025-12-31.

## `years` (type: `array`):

Yearly files to read, e.g. \[2024, 2025] (1995 onwards). Leave empty to use your dates, or the latest three years.

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

D Detached, S Semi-Detached, T Terraced, F Flats/Maisonettes, O Other. Leave empty for all.

## `newBuild` (type: `string`):

Land Registry's old/new flag.

## `tenure` (type: `string`):

Freehold or leasehold.

## `category` (type: `string`):

A = standard sale of a single residential property for value. B = additional entries: repossessions, buy-to-lets identified by a mortgage, sales to non-private buyers and 'Other' property types.

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

Lowest sale price wanted.

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

Highest sale price wanted.

## `mode` (type: `string`):

latest_monthly_update reads only the newest monthly change file, with each row's record status, to keep a copy up to date.

## `order` (type: `string`):

By transfer date.

## `maxRecords` (type: `integer`):

Stop after this many sales (each is charged once).

## Actor input object example

```json
{
  "postcodes": [
    "M1"
  ],
  "districts": [],
  "towns": [],
  "counties": [],
  "years": [],
  "propertyTypes": [],
  "newBuild": "any",
  "tenure": "any",
  "category": "all",
  "mode": "yearly",
  "order": "newest_first",
  "maxRecords": 10
}
```

# Actor output Schema

## `results` (type: `string`):

The delivered (and billed) Price Paid transactions.

## `receipt` (type: `string`):

Files read, rows read and matched, delivered and charged 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 = {
    "postcodes": [
        "M1"
    ],
    "maxRecords": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/uk-price-paid-transaction-records").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 = {
    "postcodes": ["M1"],
    "maxRecords": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/uk-price-paid-transaction-records").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 '{
  "postcodes": [
    "M1"
  ],
  "maxRecords": 10
}' |
apify call nexgensignal/uk-price-paid-transaction-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/uk-price-paid-transaction-records"
        }
    }
}
```

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/Uc14epbwh8etblTbc/builds/0ogIqtM67cX7R2v7w/openapi.json
