Free evaluation sample of UK MOT reliability statistics — first-time pass rates, defect patterns, severity tiers, mileage behaviour and survival curves by make, model, year and fuel — aggregated from the complete DVSA MOT history record. This sample covers Volvo only.
Nobody will pay for DVSA MOT data — it is free and open. This sample is the engineering between the raw feed and a usable cohort statistic: model normalisation, severity taxonomy, data-quality corrections, fuel-level grain, survival curves, and daily freshness.
Contains public sector information licensed under the Open Government Licence v3.0.
CarHunch is not affiliated with, or endorsed by, DVSA or DVLA.
Derived fields © Donald Simpson Limited.
Licence: evaluation only — see LICENCE.md. Full UK commercial bundle: data@carhunch.com.
Snapshot: 2026-07-19 · Filter: vehicle_count > 50 · ~2,094 cohorts · ~1.1 MB total
Built for teams working with UK MOT history data and used-car reliability statistics who need it aggregated rather than raw:
- Used-car warranty and underwriting — pricing risk by cohort; structural vs routine-wear split for reserving.
- Dealer, auction and remarketing tools — filtering stock and informing residual-value models before you bid.
- Parts, servicing and repair platforms — predicting what a make/model/year cohort needs next.
- Vehicle data providers and fleet analytics — adding a reliability layer to an existing feed.
- Researchers and journalists — UK vehicle defect data at national scale, under an open-data source licence.
If you only need to look up a single car, the free consumer site does that: carhunch.com.
This dataset is not an export made for sale — it is the layer behind a live public site. The same Volvo cohorts, rendered for humans:
- XC60, 2018 — a single cohort row from
volvo_cohort_stats.parquet, with its defect patterns and mileage distribution. - XC60, all years — the model rollup, which is
model_normdoing its job across 4,030 raw trim strings. - Best year to buy an XC60 — derived analysis built on the same cohort statistics.
Figures on the site are refreshed daily; the files here are a pinned snapshot
(snapshot_date is stamped on every row).
The DVSA feed has no model taxonomy — only free-text trim strings. For Volvo alone the source holds 4,030 distinct raw model strings, which normalise to 347 models. Within this filtered sample, 611 raw strings collapse to 54.
If you have ever tried to group MOT data by model, that ratio is the whole problem. It is also the part that looks like a fortnight of work and is not.
Raw DVSA-style model (examples) |
→ model_norm |
|---|---|
XC60 + B5 MHEV AWD AUTO |
XC60 |
XC60 + T6 RECHARGE AWD AUTO |
XC60 |
XC60 ULTRA T8 PHEV AWD AUTO |
XC60 |
XC60 + BLK ED B5 MHEV AWD AUTO |
XC60 |
XC60 ULTIMTE T8 RECHARGE AWD A |
XC60 |
XC60 + T6 PHEV AWD AUTO |
XC60 |
XC60 + B4 MHEV AWD AUTO |
XC60 |
XC60 |
XC60 |
How the join works is documented in docs/NORMALISATION.md — that document is itself part of the product.
volvo_defect_severity.parquet is a cohort-level rollup of a hand-built severity taxonomy applied at ~1.87 billion defect rows in production. You get counts and weighted severity by tier_name (advisory, safety_wear, mechanical_safety, structural_concern, dangerous, …). Raw MOT gives you a text blob; this gives you a weighted severity model. No registration-level rows are included.
A naive pipeline falls into these traps; this sample already handles them:
- Incomplete-outcome suppression —
pass_rate_reliable = falsewhereavg_tests_per_vehicle <= 1.0(partial / unreliable outcome history). - Mileage anomaly separation — genuine clocking (~4.5% of vehicles) vs typos / unit errors (four false-positive classes found on real cars). Site logic; aggregates here inherit cleaned inputs.
- Odometer unit distrust —
MI/KMlabels are not reliable (~0.6% mislabelled); do not average across units naively. - Hybrid fuel classification — hybrids classified by combustion engine; treat labels like
Hybrid Electric (Clean)with care. - Retest exclusion — retests are not counted as first-time outcomes in pass-rate metrics.
Stats are at make × model × manufacture_year × fuel_type — not just model/year. Most competitors stop earlier.
volvo_survival.parquet — how many vehicles from a manufacture year are still being MOT-tested in later years. Useful for warranty reserving and residual-value work.
Built from CarHunch’s daily DVSA delta pipeline, not an annual dump. Every file carries snapshot_date and generated_at.
Raw MOT failure text is dominated by consumables — tyres and brakes top almost every cohort, which tells you nothing. The severity taxonomy separates structural failures (corrosion, mounts, subframes — expensive, often terminal) from routine wear. That distinction is the product.
Aggregated from volvo_defect_severity.parquet (~29.7M defect records). Reproduce with the
year-bucket SQL in docs/preview-tables.md.
Volvo cohorts ranked by structural share of all defects (cohorts with >20,000 defects):
| model | years | fuel | defects | structural % | routine-wear % |
|---|---|---|---|---|---|
| 300 | 1990 | Petrol | 72,398 | 12.2% | 11.5% |
| 300 | 1987 | Petrol | 67,871 | 11.2% | 10.8% |
| V40 | 1996 | Diesel | 30,097 | 10.9% | 17.8% |
| 400 | 1993 | Petrol | 479,547 | 10.5% | 12.8% |
| V40 | 1999 | Diesel | 89,767 | 10.1% | 19.1% |
| … | |||||
| XC60 | 2017 | Petrol | 32,874 | 0.0% | 60.8% |
| XC90 | 2020 | Diesel | 28,102 | 0.0% | 54.9% |
| XC40 | 2020 | Petrol | 122,564 | 0.0% | 68.6% |
The inversion is the signal: pre-2000 cohorts spend ~11% of their defects on structural failure and little on wear; 2017+ cohorts show zero structural defects and 50–69% routine wear. For warranty reserving that is the difference between a claim that writes the car off and one that costs a tyre — and it is not recoverable from the raw feed without the taxonomy.
Reproduce it in one query — see docs/preview-tables.md, which also
carries the top-20-by-dangerous-defect table.
Non-technical preview: open data/volvo_preview.csv in Excel (~20 rows).
| File | Rows | What it is |
|---|---|---|
data/volvo_cohort_stats.parquet |
2,094 | Core cohort metrics at fuel-level grain + model_norm |
data/volvo_defect_patterns.parquet |
5,029 | Top defect texts / type counts at model_norm × year_bucket × fuel × engine |
data/volvo_defect_severity.parquet |
6,284 | Severity-tier rollups (cohort-level only) |
data/volvo_survival.parquet |
9,844 | Vehicles still tested by test year |
data/volvo_mileage_band_pass.parquet |
2,860 | Pass rate & severity score by mileage band |
data/volvo_mileage_percentiles.parquet |
175 | Mileage p20/p40/p60/p80 by make/model |
data/volvo_preview.csv |
20 | Excel-friendly slice |
Full column dictionary: SCHEMA.md.
SELECT model, manufacture_year, fuel_type, vehicle_count,
first_time_pass_rate, pct_with_dangerous_defect, model_norm
FROM read_parquet('data/volvo_cohort_stats.parquet')
WHERE model_norm = 'XC60' AND pass_rate_reliable
ORDER BY pct_with_dangerous_defect DESC
LIMIT 10;import polars as pl
df = pl.read_parquet("data/volvo_cohort_stats.parquet")
print(
df.filter(pl.col("model_norm") == "XC60")
.sort("pct_with_dangerous_defect", descending=True)
.select(["model", "manufacture_year", "fuel_type", "vehicle_count",
"first_time_pass_rate", "pct_with_dangerous_defect"])
.head(10)
)import pandas as pd
df = pd.read_parquet("data/volvo_cohort_stats.parquet")
print(
df.query("model_norm == 'XC60'")
.sort_values("pct_with_dangerous_defect", ascending=False)
[["model", "manufacture_year", "fuel_type", "vehicle_count",
"first_time_pass_rate", "pct_with_dangerous_defect"]]
.head(10)
)Join defect patterns via model_norm + year_bucket (see docs/NORMALISATION.md):
SELECT c.model, c.manufacture_year, c.fuel_type, c.vehicle_count,
d.top_defect_texts, d.dangerous_defect_count
FROM read_parquet('data/volvo_cohort_stats.parquet') c
LEFT JOIN read_parquet('data/volvo_defect_patterns.parquet') d
ON c.model_norm = d.model_norm
AND c.fuel_type = d.fuel_type
AND ((c.manufacture_year // 3) * 3 + 1) = d.year_bucket
AND d.engine_capacity IS NULL
WHERE c.model_norm = 'V40'
LIMIT 5;- Volvo only — this is an evaluation sample, not the full UK dataset.
vehicle_count > 50— small cohorts are excluded deliberately (noisy stats).modelvsmodel_norm—modelis the raw DVSA-style string and may be either a normalised model (XC60) or a trim-level variant (XC60 R-DESIGN D4 AWD AUTO).model_normis the normalised rollup key — group on it, and do not also sum the trim-level rows, or you will double-count. For a single cohort matching the public site, filtermodel = '<name>'.- Defect patterns do not share an exact key with cohort stats — join is many-to-one via
model_norm+ year bucket; seedocs/NORMALISATION.md. Do not invent a fuzzy match. - CarHunch Score is not included — proprietary to carhunch.com.
- No per-vehicle / registration / VIN data — aggregates only.
- Not underwriting advice — validate before pricing risk.
Commercial UK licence / quarterly refresh: data@carhunch.com
Product site: carhunch.com
