| Dataset | Consumer price index, China |
|---|---|
| Dataset id | nbs.cpi |
| Series | 47 |
| Observations | 5,660 |
| Countries | 1 |
| Period range | 1978-01-01 to 2026-07-01 |
| Vintages | 2 |
| Last fetched | 2026-09-10 11:45 |
| Poll interval | 7 days |
| Archive | nbs/cpi/*.json.gz |
| Licence | NBS terms of use |
| Redistributable | with-attribution |
| Terms read by a person | 2026-09-11 |
| Attribution | National Bureau of Statistics of China |
The connector's own docstring, verbatim. It lives beside the code so it cannot drift from it.
NBS connector: China's CPI, through the API behind the rebuilt data.stats.gov.cn.
The August probe recorded this source as refusing us — easyquery.htm returns 403 and still does. What it could not know is that NBS has rebuilt the site as a single-page app under /dg/website/, with a keyless JSON API behind it that answers an ordinary request. No scraping, no key, no registration.
Three calls do everything: queryIndexTreeAsync walks the catalogue tree, queryIndicatorsByCid lists one catalogue's indicators, and a POST to stream/esData returns values for a period range.
Six things this connector had to get right, none of them documented anywhere.
China publishes no monthly index level. The monthly CPI comes only as ratios — "the same month last year = 100" and "the preceding month = 100" — where 100.5 means prices rose 0.5%. Those are not percentages. Storing them as measure = 'rate' would have put 100.5 beside the IMF's 0.5 for the same quantity with nothing in the response to say they differ, so they carry the ratio measure added to catalog.MEASURES for them: never rebased, neutral at 100 rather than zero. The one genuine index level NBS publishes is annual, on a 1978 base, and comes from a different tree.
History is split across era catalogues — (2026-), (2021-2025), (2016-2020), (-2015) — each with its own id and its own indicator ids. One series takes four requests. The 2026 catalogue alone holds seven months, which is what makes the API look empty if you stop at the page the site opens on.
The category structure changed in 2016 and is not smoothed over. Before it, 食品类 (food) and 烟酒类 (tobacco and liquor) are separate categories; from 2016 there is one combined 食品烟酒类. They are different concepts and get different codes here, so no series quietly changes meaning in January 2016.
The category key is the source's Chinese label, not its code. The code looked like the better key and is not: NBS uses different codes for the same category in the month-over-month and year-over-year families — 食品类 is 6039803100002 under one and 601300100001 under the other — so keying on the code would split one category into two concepts that differ only by which rate was asked for. The English label cannot be the key either, because NBS renamed 其他用品及服务类 from "Other Goods and Services" to "Miscellaneous Goods and Services" between two era catalogues while the category itself did not change.
The dimension order is not fixed. In most rows the transformation code sits in kj1 and the category in kj2; in the month-over-month catalogues for two eras they are the other way round. Both are therefore searched for a known category, and a row with none is the headline.
The English path is a translation, not a dataset. Dropping /en/ from the URL returns Chinese labels against identical ids and identical values, so the two are one dataset. English is used for the indicator listing and the Chinese label for the category key, which is the combination that is stable.
Deliberately not taken, on Alberto's instruction of 2026-09-03 to keep to the index, the monthly rate and the annual rate:
the year-to-date ratio "the same period last year=100", a third
transformation of the same categories
the quarterly tree no consumer price series this does not already
have monthly
urban and rural monthly separate catalogues repeating all of the above
for two sub-populations
the per-category deep one catalogue per category, repeating what the
catalogues by-category catalogues already carry