# UK House Price Statistics by Postcode: Land Registry Data (`kyungminlee/uk-property-sold-prices`) Actor

Aggregated UK house price statistics from official HM Land Registry data: median, mean and quartile sold prices and sales counts by postcode district or sector, town, local authority or county, per month, quarter or year. England and Wales. No addresses. Unofficial.

- **URL**: https://apify.com/kyungminlee/uk-property-sold-prices.md
- **Developed by:** [Kyungmin Lee](https://apify.com/kyungminlee) (community)
- **Categories:** Real estate, Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 area statistics

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does UK House Price Statistics do?

**UK House Price Statistics** turns the official **HM Land Registry Price Paid Data** for **England and Wales** into clean, aggregated market statistics. Pick a postcode district (`SW11`, `M1`), a postcode sector (`SW11 6`), a town, a local authority or a county, choose monthly, quarterly or yearly periods, and get one row per area and period with the **number of sales, mean, median, lower and upper quartile, minimum and maximum price**, and the **change of the median versus the previous period and versus the same period a year earlier**. Optionally split each period by property type, new build or tenure.

This Actor returns **statistics only**. It never outputs addresses, house numbers, street names, transaction IDs or the price and date of any individual sale. This is unofficial: it is not affiliated with, endorsed by or connected to HM Land Registry, Royal Mail or Ordnance Survey. It only reads the public Price Paid Data download files; no login, cookies, browser or proxy are involved.

### Why use UK House Price Statistics?

- **Real sold prices, not asking prices.** Land Registry records what buyers actually paid, so medians and quartiles reflect the true market.
- **Ready-made time series.** Monthly, quarterly or yearly rows with percentage changes, ready for dashboards, reports, spreadsheets and models.
- **Small-count protection.** Cells with fewer than 3 sales have their prices withheld, so no single sale can be read from the output.
- **Companion to current listings.** For homes currently on the market use the [Rightmove Property Scraper](https://apify.com/kyungminlee/rightmove-property-scraper) and compare asking prices with the sold-price statistics from this Actor.
- **Fair pricing.** You pay per statistics row saved. Input problems and searches without results are never charged.

### How to use UK House Price Statistics

1. Click **Try for free**.
2. Enter one or more **postcode districts or sectors**, **towns**, **local authorities** or **counties**.
3. Choose the **period** (monthly, quarterly, yearly), an optional **breakdown**, and the sold-from / sold-until dates (default: the last 24 months).
4. Add price, property type, new build or tenure filters if you need them.
5. Click **Start** and download JSON, CSV or Excel, or use the Apify API.

### Input

```json
{
  "postcodes": ["SW11"],
  "towns": ["MANCHESTER"],
  "period": "monthly",
  "breakdownBy": "none",
  "dateFrom": "24 months",
  "minPrice": 100000,
  "maxPrice": 900000,
  "propertyTypes": ["flat"],
  "newBuild": "any",
  "tenure": "any",
  "includeAdditionalTransactions": true
}
```

- Every district, sector, town, local authority and county is its own area. Town, authority and county names must match Land Registry spelling (case is ignored): `MANCHESTER`, `CITY OF WESTMINSTER`, `GREATER MANCHESTER`.
- Full postcodes such as `SW11 6AB` are rejected on purpose; use the district or sector.
- `dateFrom` / `dateTo` accept `YYYY-MM-DD` or relative values such as `12 months`. One yearly Land Registry file is read per calendar year, so a run covers at most 10 years.
- Filters (dates, price, property type, new build, tenure, standard versus additional transactions) are applied before the statistics are calculated.

### Output

One row (monthly, broken down by property type):

```json
{
  "area": "SW11", "areaType": "postcode district",
  "periodStart": "2026-03-01", "periodEnd": "2026-03-31", "period": "monthly",
  "propertyType": "flat",
  "transactionCount": 112, "meanPrice": 596250.4, "medianPrice": 540000,
  "lowerQuartile": 425000, "upperQuartile": 690000, "minPrice": 190000, "maxPrice": 2100000,
  "suppressed": false,
  "medianChangeVsPreviousPeriodPct": 1.9, "medianChangeYoYPct": -0.8,
  "currency": "GBP",
  "licence": "Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0."
}
```

The key-value store `SUMMARY` record lists the files read, matching sales per area and the newest sale date in the data.

### Data fields

| Field | Description |
|---|---|
| `area`, `areaType` | The area you asked for and its type (postcode district, postcode sector, town, local authority, county) |
| `periodStart`, `periodEnd`, `period` | The period covered (cut at your date range) and its length |
| `propertyType` / `newBuild` / `tenure` | Present only when you choose that breakdown |
| `transactionCount` | Number of sales in the cell |
| `meanPrice`, `medianPrice`, `lowerQuartile`, `upperQuartile`, `minPrice`, `maxPrice` | Price statistics in GBP; `null` when suppressed |
| `suppressed` | `true` when the cell has fewer than 3 sales and prices are withheld |
| `medianChangeVsPreviousPeriodPct` | Change of the median versus the previous period of the same series, in percent |
| `medianChangeYoYPct` | Change of the median versus the same period a year earlier, in percent |
| `licence` | The attribution statement required by the licence |

Change fields are `null` when the earlier period lies outside your date range, has no sales or is suppressed. To get year-over-year values for the first months of a series, start your date range 12 months earlier.

### Pricing

This Actor uses **pay per event** with one event, **`area-stat`**: **$0.003 per statistics row saved** (primary event). A 2-year monthly series for one postcode district is about 24 rows, roughly **$0.07**; a 5-year yearly series by property type is about 25 rows. Rows with suppressed prices count as rows. You are charged only for saved rows, and the run respects the maximum cost per run you set. See the Pricing tab for the exact current price.

### Tips

- Use **postcode districts** for neighbourhoods and **local authorities** for boroughs. Sectors are finer but often have months with fewer than 3 sales; prefer quarterly or yearly periods there.
- Use `breakdownBy: propertyType` to separate flats from houses, whose prices differ widely.
- For an owner-occupier view switch off additional transactions and set `newBuild` to `exclude`.
- Counties and large cities are heavy: each year is a 100-230 MB file regardless of the area, so keep ranges short.
- Schedule a monthly run to track an area.

### FAQ

**Which areas are covered?** England and Wales only. Scotland and Northern Ireland have separate registers.

**Why are there no addresses or individual sales?** Land Registry address data derives from Royal Mail and Ordnance Survey data that may only be used non-commercially or for residential property price information services. This Actor therefore publishes aggregated statistics only.

**What does suppressed mean?** If a cell has fewer than 3 sales, the count is shown but all price fields are `null` and `suppressed` is `true`, so no single sale price can be inferred.

**How fresh is the data?** Land Registry publishes new sales once a month and sales are registered 1-2 months after completion, so the newest weeks are always partial. The latest sale date is shown in the run message and in `SUMMARY`.

**Is it legal to use?** The data is released under the Open Government Licence v3.0, which allows commercial reuse. If you use or publish it, include this attribution: *Contains HM Land Registry data © Crown copyright and database right 2021. This data is licensed under the Open Government Licence v3.0.* You are responsible for using the data in line with these terms.

**Where does the data come from?** The yearly Price Paid Data CSV files that HM Land Registry publishes for download. Nothing else is accessed.

# Actor input Schema

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

Postcode districts (`SW11`, `M1`, `SW1A`) or postcode sectors (`SW11 6`). Each entry is one area. Full postcodes (`SW11 6AB`) are not accepted because this Actor returns statistics only, never address-level data. England and Wales only (Scottish `EH`/`G` and Northern Irish `BT` postcodes have no data). You can combine these with the town, local authority and county fields below.

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

Town or city names exactly as Land Registry records them, for example `MANCHESTER`, `BRISTOL`, `LEEDS` (case does not matter). The match is on the whole name, not a part of it.

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

Local authority / district names, for example `CITY OF WESTMINSTER`, `BIRMINGHAM`, `CAMBRIDGE`, `CORNWALL` (case does not matter). Use this for boroughs and councils; use Towns for the postal town.

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

County names as Land Registry records them, for example `GREATER MANCHESTER`, `KENT`, `GREATER LONDON`, `WEST YORKSHIRE`. Counties are large: combine with a short date range and a price or property type filter, or expect long runs.

## `period` (type: `string`):

Length of each statistics period: `monthly`, `quarterly` or `yearly`. One row is saved per area, period (and breakdown value) that has at least one sale. Periods are calendar months, quarters or years, cut at the date range you choose.

## `breakdownBy` (type: `string`):

Split every period into separate rows by `propertyType` (detached, semi-detached, terraced, flat, other), `newBuild` (new or existing) or `tenure` (freehold, leasehold, unknown). `none` gives one row per area and period. A breakdown multiplies the number of rows, and so the price.

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

Only sales with a date of transfer on or after this date: `YYYY-MM-DD`, or a relative value such as `12 months` or `2 years` (that long before the run). Empty = 24 months before the end date. The run reads one Land Registry file per calendar year, so keep the range to 10 years or less.

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

Only sales with a date of transfer on or before this date: `YYYY-MM-DD` or a relative value such as `1 month`. Empty = today. Land Registry publishes new sales once a month, usually 1-2 months after the sale date, so the newest weeks are never complete.

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

Only sales at or above this price in pounds. Empty = no minimum.

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

Only sales at or below this price in pounds. Empty = no maximum.

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

Only these property types. Empty = all types. `flat` includes maisonettes; `other` is everything Land Registry does not classify (land, commercial-style plots, some converted buildings).

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

`any` keeps every sale, `only` keeps only newly built properties (first sale), `exclude` removes them.

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

`freehold` or `leasehold` only, or `any`. Most flats are leasehold, most houses freehold.

## `includeAdditionalTransactions` (type: `boolean`):

Land Registry splits sales into standard transactions (ordinary sales to individuals at market value) and additional ones (repossessions, buy-to-let and company purchases, transfers under a power of sale). Leave on for the complete picture; switch off for a cleaner owner-occupier market view.

## Actor input object example

```json
{
  "postcodes": [
    "SW11"
  ],
  "period": "monthly",
  "breakdownBy": "none",
  "newBuild": "any",
  "tenure": "any",
  "includeAdditionalTransactions": true
}
```

# Actor output Schema

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

No description

# 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": [
        "SW11"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kyungminlee/uk-property-sold-prices").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": ["SW11"] }

# Run the Actor and wait for it to finish
run = client.actor("kyungminlee/uk-property-sold-prices").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": [
    "SW11"
  ]
}' |
apify call kyungminlee/uk-property-sold-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kyungminlee/uk-property-sold-prices"
        }
    }
}
```

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/1EgtHi4HicH8S47hI/builds/y5Iqo3ejYMQe34Nm5/openapi.json
