knbs_indicators() lists what every verified indicator
source serves, and knbs_get_indicator() returns one
indicator as tidy observations. Three families exist today: tables from
the 2019 Population and Housing Census (CC BY 4.0), the
monthly consumer price series from the KNBS CPI
Explorer, the 323 economic dataflows of the KNBS Data
Portal — GDP, trade, balance of payments, county government
finance and much else, in SDMX form — and the 202 datasets
republished by Kenya Open Data for Africa, which carry the one
thing no first-party portal serves as data: Gross County Product.
knbs_indicators() # all families, source_id says which
cpi <- knbs_get_indicator("CPI_ALL_ITEMS", start = "2020-01")
gdp <- knbs_get_indicator("DF_NAT_GDPCP")
pop <- knbs_get_indicator("POPCEN0001", geo_level = "county")
gcp <- knbs_get_indicator("jhbzkjc") # Gross County Product, 2013-2020Every dataflow keeps its SDMX id (DF_NAT_GDPCP,
DF_BOP_A, DF_CPI_R…);
knbs_indicators(source = "knbs_opendata") lists all 323
with their statistical domain as topic. Annual flows carry
integer-year periods; monthly and quarterly ones carry first-of-period
Dates, so start and end behave as
everywhere else. Dimensions vary per flow; each becomes a pair of
columns named by its SDMX id in lower case — na_indic
holding the labels (“Accommodation and food service activities”) and
na_indic_code the codes — and a Sex dimension becomes
sex, lower-cased as in the census tables. The ids name the
columns, not the portal’s labels, because the portal labels ten
different dimensions just “Indicator”. Single-category dimensions
(“Prices = Current prices”, “Unit = Kenya Shillings”) are facts about
the whole dataflow and fold into knbs_metadata() notes
instead of constant columns.
Two cautions: the portal states no licence, and its
geography codes are SDMX area codes, not census
territories — geo_level is NA there,
and they must never be joined against
knbs_geographies().
Chunks that contact the services are shown but not run, so building this vignette never depends on them.
knbs_indicators(source = "opendataforafrica") lists the
202 datasets of kenya.opendataforafrica.org, the
Knoema-operated portal on KNBS’s own portals page — 169 sourced from
KNBS, the rest from the Central Bank of Kenya, ministries and agencies.
Dataset ids are the portal’s own opaque slugs, so name search is the
natural way in:
knbs_indicators(source = "opendataforafrica", search = "county product")
gcp <- knbs_get_indicator("jhbzkjc")
gcp[gcp$table_code == "T3" & gcp$period == 2020, ] # current-price GCP, 2020Three behaviours to know:
Dates, which cannot share a
column, so a mixed dataset refuses to pick silently — say
frequency = "annual" (or "quarterly",
"monthly") to choose.knbs_metadata() names the portal, the original producer,
the dataset’s own licence label (most KNBS-sourced datasets state
“Public Domain”) and the portal’s publication and update dates — the
data vintage is visible, and can lag the producer’s newest PDFs.KE, KE-110-NA, …), geo_level is
NA, and they must never be joined against
knbs_geographies().Three indicators, all monthly, all from one underlying series:
| id | measure | unit |
|---|---|---|
CPI_ALL_ITEMS |
the index level | index points |
CPI_INFLATION_YOY |
year-on-year change | percent |
CPI_INFLATION_MOM |
month-on-month change | percent |
period is a Date at the first of the month,
with a period_label like "2026-06".
start and end take a year, a
"YYYY-MM" month, or a date.
The default is the national series. The other level is
"region" — the CPI collection strata: the Nairobi income
bands, Nairobi Combined, and Rest of Urban.
knbs_get_indicator("CPI_ALL_ITEMS", geo_level = "region")
knbs_get_indicator("CPI_ALL_ITEMS", geo_code = c("national", "1"))These region codes are the source’s own and mean nothing outside it.
Do not join them against
knbs_geographies() — different coding system,
different concept, and the package keeps them apart deliberately.
Two more honesty notes, both from the source audit:
knbs_metadata() on any result says both,
so the caveat travels with the data rather than living only in this
vignette.The same portal publishes the monthly national average retail prices of the 22 commodities tracked for the CPI basket, in Kenya Shillings per stated unit:
knbs_retail_prices(commodity = "petrol", start = 2024)
knbs_retail_prices(start = "2026-06", end = "2026-06") # one month, all 22One row per commodity per month: commodity_code
(CPI001–CPI022), commodity,
unit, quantity, period,
price. National only — the source holds no regional retail
prices — and the licence caveat above applies here too.
Three properties worth knowing before you use it:
period is 2019 throughout,
and frequency is NA because a census table is
not a recurring release. Consumer prices, GDP and other running
indicators are not in this source (see the source-status
vignette for where that work stands).Thirty-two tables across four populated themes at the time of writing.
You can pass a name instead of an id; if several tables match you get an error listing the candidates rather than a silently chosen one.
The result has one row per cell:
indicator_id,
indicator_name, period,
value.geo_code, geo_name, geo_level.
Codes keep their leading zeros — "00" is Kenya, two digits
are counties, four digits are sub-counties — and geo_level
says which ("national", "county",
"subcounty").marital_status holding the
source’s labels (“Never Married”, “Total”) and
marital_status_code its codes ("1",
"T"). The census API names its dimensions by questionnaire
variable (p18_vs1) and labels them in long prose, so the
names are curated, one per dimension the 2019 tables carry:
age, religion, schooling_status,
internet_use, household_head_sex and so on. A
dimension added later that has no curated name keeps its source id. The
source’s own dimension labels are in
knbs_metadata(pop)$notes."0" to
"99") with five-year groups ("0-4" …
"95-99", "100-120") and a total, so summing
every row counts people twice. age_type says which is which
— "total", "single_year",
"age_group" or "other" — and the groups are
checked, on every read, to add up to the total and the single years to
their group. filter(age_type == "age_group") gives a
population pyramid that adds up.counties <- knbs_get_indicator("POPCEN0001", geo_level = "county")
nairobi <- knbs_get_indicator("POPCEN0001", geo_code = "47")Filters are applied after retrieval — the API serves whole tables — so the first call and the second cost the same request. Tables are cached for seven days by default.
County population aged 12+, both sexes, all marital statuses:
pop <- knbs_get_indicator("POPCEN0001", geo_level = "county")
totals <- pop[pop$sex == "total" & pop$marital_status == "Total",
c("geo_code", "geo_name", "value")]
totals[order(-totals$value), ]Because geo_code is character with leading zeros intact,
these codes join cleanly against any other dataset keyed the same
way.
The metadata carry the licence statement, the release date
(2019-12-31), the source statement (“KNBS Population Census
2019”) and the dimension list; the citation is built from them.
unit is NA in the catalogue: the source
does not state units, and counts-versus-proportions is knowable only
from each table’s name. The package does not guess.errore; the package translates.)knbs_error_schema_changed, not a
plausible-looking wrong table.