How to Analyse HM Land Registry Price Paid Data in Python

On this page

Problem statement

In 2024, 763,905 homes in England and Wales sold on the open market for a median of £291,000: £415,000 for a detached house, £235,000 for a terrace, £530,200 in Greater London. Every one of those sales is in HM Land Registry's Price Paid Data, free under the Open Government Licence, and getting the figures out of it is a matter of summarising by property type, by county and by month — once the 167,548 sales that are not ordinary market purchases have been set aside.

This page loads the 2024 file. It names the columns and decodes the codes, separates standard market sales from the rest, and summarises prices by property type, by region and by month.

Quick answer

Read the file with the column names supplied, and keep standard sales (category A):

COLS = ["transaction_id", "price", "date", "postcode", "property_type", "old_new", "duration", "paon", "saon",
        "street", "locality", "town", "district", "county", "ppd_category", "record_status"]
P = pd.read_csv(CSV, header=None, names=COLS, parse_dates=["date"])
A = P[P.ppd_category == "A"]
print(f"{len(P):,} transactions registered for 2024; standard (A): {len(A):,}; additional (B): {(P.ppd_category == 'B').sum():,}")
print(f"median price of standard sales £{A.price.median():,.0f}; mean £{A.price.mean():,.0f}")
931,453 transactions registered for 2024; standard (A): 763,905; additional (B): 167,548
median price of standard sales £291,000; mean £369,875

931,453 transactions are registered for 2024: 763,905 standard sales and 167,548 additional ones. The median standard sale was £291,000, and the mean £369,875, pulled up by expensive sales.

The sixteen columns of HM Land Registry Price Paid Data, in file order. the sixteen columns#column#column1transaction ID9SAON2price10street3date of transfer11locality4postcode12town/city5property type13district6old/new14county7duration15PPD category8PAON16record statusno header row in the CSVHM Land Registry, Open Government Licence spatialworkflow.io
The file has no header row; the order comes from the documentation.

Decode the codes, by county and month, additional sales

1. Decode the codes

TYPES = {"D": "detached", "S": "semi-detached", "T": "terraced", "F": "flat/maisonette", "O": "other"}
t = A.assign(type=A.property_type.map(TYPES)).groupby("type").price.agg(["size", "median"])
print(t.sort_values("median", ascending=False).rename(columns={"size": "sales", "median": "median £"}).to_string())
print(f"new builds (old_new = Y): {(A.old_new == 'Y').mean():.1%}; leasehold (duration = L): {(A.duration == 'L').mean():.1%}")
                  sales  median £
type                             
detached         199414  415000.0
semi-detached    226978  269950.0
flat/maisonette  133331  245000.0
terraced         204182  235000.0
new builds (old_new = Y): 9.5%; leasehold (duration = L): 22.1%

Detached houses sold for a median of £415,000, semi-detached houses for £269,950, flats for £245,000 and terraced houses for £235,000. 9.5% of standard sales were new builds and 22.1% leasehold.

Step histograms of 2024 standard sale prices by property type on a log scale Step histograms of 2024 standard sale prices by property type on a log scale
Detached homes have the highest median, £415,000; terraced the lowest, £235,000.

2. By county and by month

c = A.groupby("county").price.agg(["size", "median"]).sort_values("median", ascending=False)
print("most expensive counties:", c.head(3)["median"].astype(int).to_dict())
print("least expensive:", c.tail(3)["median"].astype(int).to_dict())
m = A.groupby(A.date.dt.to_period("M")).price.agg(["size", "median"])
print(f"sales per month: {m['size'].min():,} ({m['size'].idxmin()}) to {m['size'].max():,} ({m['size'].idxmax()})")
most expensive counties: {'GREATER LONDON': 530200, 'WINDSOR AND MAIDENHEAD': 530000, 'SURREY': 503752}
least expensive: {'CITY OF KINGSTON UPON HULL': 136000, 'BLACKPOOL': 135000, 'BLAENAU GWENT': 135000}
sales per month: 45,798 (2024-01) to 77,498 (2024-10)

Greater London is the most expensive county by median, £530,200, closely followed by Windsor and Maidenhead and Surrey. Kingston upon Hull, Blackpool and Blaenau Gwent are the least expensive, at about £135,000. Monthly sales ran from 45,798 in January to 77,498 in October.

3. The additional price paid category

Category B covers repossessions, buy-to-let sales identified by a mortgage, transfers to companies and other non-standard sales:

B = P[P.ppd_category == "B"]
print(f"category B: {len(B):,} sales, median £{B.price.median():,.0f}; type mix {B.property_type.map(TYPES).value_counts(normalize=True).round(2).head(3).to_dict()}")
print(f"top price in the file: £{P.price.max():,.0f} (category {P.loc[P.price.idxmax(), 'ppd_category']})")
category B: 167,548 sales, median £215,000; type mix {'other': 0.32, 'terraced': 0.27, 'flat/maisonette': 0.18}
top price in the file: £180,000,000 (category B)

Category B sales have a lower median, £215,000, and a third of them are of type "other", which does not occur among standard sales at all. The highest price in the file, £180 million, is a category B transaction, which is why category B must be kept out of typical-price statistics.

Every sale of a single address

The data used on this page

HM Land Registry Price Paid Data for 2024, the yearly file pp-2024.csv as published at the time of the run, which contains HM Land Registry data © Crown copyright and database right 2026, licensed under the Open Government Licence v3.0. The yearly files are revised monthly as late registrations arrive.

from pathlib import Path

import pandas as pd
import requests

Path("data").mkdir(exist_ok=True)
CSV = Path("data/pp-2024.csv")
if not CSV.exists():
    r = requests.get("http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-2024.csv", timeout=1800)
    r.raise_for_status(); CSV.write_bytes(r.content)
print(f"{CSV.name}: {CSV.stat().st_size / 1e6:.0f} MB")
pp-2024.csv: 162 MB

The 2024 file is 162 MB.

Example 1: a single address

Every row has a full address. Find the sales on one street to see what a record looks like:

s = A[(A.street == "DOWNING STREET") | (A.street == "ABBEY ROAD")][["date", "price", "postcode", "property_type", "paon", "saon", "street", "town"]]
print(f"sales on Downing Street or Abbey Road in 2024: {len(s)}")
print(s.sort_values("date").head(3).to_string(index=False))
sales on Downing Street or Abbey Road in 2024: 363
      date   price postcode property_type             paon saon     street       town
2024-01-08  525000 NR26 8HH             D               1A  NaN ABBEY ROAD SHERINGHAM
2024-01-08  365000 DN39 6TJ             D ORCHARD RISE, 17  NaN ABBEY ROAD     ULCEBY
2024-01-11 1322996  BS9 3QN             D                9  NaN ABBEY ROAD    BRISTOL

363 sales were on streets called Downing Street or Abbey Road, all over England and Wales. The first three are in Sheringham, Ulceby and Bristol. Street names are not unique, so locate sales by postcode, not by street.

Line of monthly median price above bars of monthly sales for 2024 Line of monthly median price above bars of monthly sales for 2024
Sales run from 45,798 in January to 77,498 in October.

Where Price Paid Data comes from

The single-letter codes in Price Paid Data. what the letters meancodes2024 standard salesproperty typeD S T F Omedian £235k-415kold/newY new, N old9.5% newdurationF free, L lease22.1% leaseholdcategoryA std, B addl763,905 A931,453 transactions in pp-2024.csv spatialworkflow.io
Four codes carry most of the meaning in each record.

Price Paid Data comes from the registration of each sale with HM Land Registry, so it covers residential sales in England and Wales for value that are registered, including leaseholds of more than seven years. Scotland and Northern Ireland have separate registers. Each record has a transaction ID, the price, the date of transfer, the postcode and full address, the property type (detached, semi-detached, terraced, flat or other), whether the property was newly built, the tenure, and a category. Category A holds standard sales at full market value, and category B holds additional transactions such as repossessions, buy-to-let purchases and transfers to non-private individuals. The files have no header row; the column order is documented on the download page.

For price analysis, the conventions matter. Use category A for typical market prices, as the official UK House Price Index does, and medians rather than means, since a few sales at tens of millions dominate an average. Property type and new-build status change the price a lot, so compare like with like. The data is a register of sales, not of homes: areas with little turnover, or with many sales of one type, look different from their housing stock. The files change as late registrations arrive and errors are corrected, which is recorded in the record_status column of the monthly change files.

Monthly updates, no coordinates and address matching

Price Paid Data problems and fixes. price paid trapsSymptomFixfirst sale used as headerheader=None, names=mean far above mediankeep category Aa £180M "house"category B, drop itlast months look quietregistration lag2024 file: category A median £291,000 spatialworkflow.io
The £180,000,000 top price is a category B transaction.
  • Monthly updates: the monthly change file has record status A (added), C (changed) and D (deleted); apply them to keep a copy current.
  • No coordinates: locate sales by joining postcodes to the ONS Postcode Directory, or aggregate by district.
  • Address matching: PAON and SAON (primary and secondary addressable object names) identify the building and the flat within it.
  • Size: the complete file since 1995 is about 5 GB; read only the columns you need, or use DuckDB.

FAQ

Where can I download UK house price data?

HM Land Registry publishes Price Paid Data for England and Wales as CSV files, yearly, monthly and complete, free under the Open Government Licence.

What are the columns in Land Registry price paid data?

Transaction ID, price, date, postcode, property type, old/new, duration, PAON, SAON, street, locality, town, district, county, PPD category and record status; the files have no header.

What is PPD category A and B?

A is a standard sale at market value; B covers additional transactions such as repossessions, buy-to-let and company purchases.

Does price paid data include Scotland?

No; it covers England and Wales only.