| Dataset | Consumer price inflation tables (MM23) |
|---|---|
| Dataset id | ons.mm23 |
| Series | 5,094 |
| Observations | 637,255 |
| Countries | 1 |
| Period range | 1988-01-01 to 2026-07-01 |
| Vintages | 1 |
| Last fetched | 2026-09-02 19:27 |
| Poll interval | 7 days |
| Archive | ons/mm23/*.csv.gz |
| Licence | Open Government Licence v3.0 |
| Redistributable | with-attribution |
| Terms read by a person | 2026-09-11 |
| Attribution | Office for National Statistics licensed under the Open Government Licence v.3.0 |
https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/
The connector's own docstring, verbatim. It lives beside the code so it cannot drift from it.
ONS connector: the UK consumer price indices, down to COICOP subclass.
The whole dataset is one 23 MB CSV -- mm23.csv, the machine-readable form of the monthly Consumer Price Inflation tables -- so one snapshot is one vintage and there is nothing to paginate. It yields 2,432 categories across CPI and CPIH, four measures each, at three published frequencies.
Seven things this connector had to get right. All of them were measured against the real file on 2026-09-02, not reasoned about.
The file is transposed. Columns are series and rows are periods, which is the opposite of every other source here. Row 0 is the title, row 1 the CDID (the ONS's own four-character series id), row 3 the unit; rows 7 onward are periods. A parser that reads it row-wise gets 4,053 observations of nothing.
One column carries up to three frequencies. Annual, quarterly and monthly periods sit in the same column: 1,836 columns publish all three, 1,082 are annual only, 980 monthly only. The annual figure is NOT the mean of the twelve months (RPI milk 2023: 15.5 published, 17.04 averaged), so it is a published series in its own right and is emitted as one. Three frequencies means up to three series ids per column, which is why the CDID is source_series_id and not the id.
The ONS misspells its own family names. CPI ANN RATE, CPI MTHLY RATE, CPIHMONTHLY RATE, CPIHMONTHLYRATE -- four spellings, seven columns, all of them real data. A tidy ^CPI MONTHLY RATE regex drops them and says nothing. Some titles also begin with a stray double quote, and in three columns the category code runs straight into the label with no separator (12.4.0.2Retire homes for elderly).
A letter after the code is part of the code; a letter touching the code is the label. 07.1.1A : NEW CARS and 07.1.1B : SECOND-HAND CARS are two different series, and the ONS publishes no plain 07.1.1 at all -- so a rule that stripped the letter would map both onto one id and silently keep whichever was parsed last. But 12.4.0.2Retire homes is not code 12.4.0.2R. The rule that separates them is a single letter followed by a non-letter.
These are two classifications, not one. A code like 01.1.1.1 is COICOP and is stored as such, in the IMF's CPxxxx notation, so that GBR CP01 is the same concept the IMF publishes for every other country. A code like 07.1.1A (an ONS split) or 08.2/3 (two COICOP classes merged) is not a COICOP code and must not claim to be; those keep taxonomy 'ons' and their code verbatim. 84 merged and 8 lettered columns take the second path.
The file carries other countries. 30 columns are HICP annual rates for Cyprus, France, Germany and so on, plus EU and euro-area aggregates. Filing them under GBR because the file is British would be a confident wrong answer, and country_iso3 is not checked against anything that would catch it -- an unknown code is dropped SILENTLY (see the contract). They are left out here, with the reason recorded below, rather than quietly mis-filed.
The IMF's "United Kingdom CPI" is this file's CPIH, exactly. Measured over all thirteen concepts the IMF publishes for GBR: 6,019 of 6,019 overlapping monthly index cells are identical to ONS CPIH, and 2,563 of 6,019 to ONS CPI. CP04 (housing) differs from the CPI by up to 16.1 index points, which is what owner occupiers' housing costs are worth. So this connector is not duplicating what the IMF already gives: it adds the UK's actual CPI, which the database did not hold, and the ONS's own published rates -- the IMF's YOY is the ratio of its rounded index at all 451 months, matching the ONS's published rate only 67% of the time.
What is deliberately left out, by family, with the reason. The line is drawn at the category code: a code is what makes a concept knowable, so a CPI/CPIH column with one is taken and a column without one is not.
806 RPI and its sub-indices a different index on a different
classification; no COICOP codes at all
322 special aggregates 'CPI wts: Durables GOODS', 'CPIH excl
and goods/services splits council tax' -- named, not coded
97 RPI average prices levels in PENCE; storing them as GBP
would be a factor-of-100 error, and
item 15's exchange rates are not here
72 historical modelled estimates 1965=100 back-estimates, which are a
different series from the published
index they share a code with
30 other countries' HICP see above
27 CPI-CT, CPIY constant-tax variants, no codes
30 purchasing power of the pound an inverted RPI, in pence
~200 differences, formula effect, analytical residuals whose measure is
indirect tax effects not one of the four in catalog.MEASURES
Conditional requests work here, which they did not for IBGE or the IMF. The ONS sends an ETag and honours If-None-Match with a 304, so gate 2 fires and an unchanged month costs one request instead of 23 MB. The content hash still decides whether a 200 becomes a vintage.