Principles
- The country is the primary unit; every visible number is traceable to its source (provenance object on every value).
- Exactly one source per (indicator, country, period) is kept, chosen by the registry source priority; alternatives are stored separately.
- Forecasts (IMF WEO projections) are flagged and never enter latest values, rankings or change detection.
- Unusual values are never deleted, only flagged. Revisions are recorded, never silently overwritten.
- Headlines, insights and change descriptions are template strings computed from data — no generative model.
Country registry
The registry lists 218 countries and territories with ISO 3166-1 alpha-2, alpha-3 and numeric codes, a URL slug, a short display name, capital, continent, World Bank region and income classification (FY2026), currency, area, borders and languages. Every dataset is mapped to this registry before anything else happens; a row whose country code is unknown is logged and dropped, and source aggregates (World, OECD…) are never stored as countries. Groups — World Bank regions, continents, income groups and organisations — are lists of registry members, so a group aggregate always means “across these member countries”.
Indicator registry & units
Each of the 261 indicators has a stable slug, a name, a topic and subtopic, a unit and short unit, a display format, a precision, a frequency, an aggregation rule (sum for additive quantities such as GDP or population; none otherwise), whether higher is better, whether it is eligible for rankings, optional bounds and a jump threshold for validation. Units are never converted at display time: the value stored is the value shown, in the registry unit.
Formats
- percent
- 126
- number
- 58
- currency
- 24
- index
- 12
- tonnes
- 12
- per_1000
- 8
- years
- 7
- per_100k
- 5
- kwh
- 2
- km
- 2
- per_million
- 2
- ratio
- 1
- celsius
- 1
- ha
- 1
Most common units
- % of GDP
- 32
- % of population
- 16
- current US$
- 15
- people
- 9
- terawatt-hours
- 9
- % of electricity generation
- 9
- index (2015 = 100)
- 7
- years
- 7
- annual %
- 6
- estimate (−2.5 to 2.5)
- 6
Frequencies
- Annual
- 249
- Monthly
- 5
- Quarterly
- 7
Aggregations
- sum
- 57
- weighted_mean
- 1
- none
- 203
Sources, priority and series-level selection
Each indicator lists its sources in priority order (1 = preferred). For each country × period the highest-priority source with a value is kept in `observations`; the others go to `observations_alt`.
Selection is made per series, not per point: for each country and indicator the whole history comes from one source, so a line never switches vintage halfway. The chosen source is the highest-priority one with any non-forecast value for that country, unless a lower-priority source is more than three years fresher, in which case the fresher one wins. The decision is recorded on every row. The non-chosen values remain available as alternatives.
Series mapped per connector
- worldbank
- 195
- owid
- 45
- fred
- 23
- eurostat
- 18
- oecd
- 17
- who
- 17
- imf
- 16
- bis
- 4
- ilo
- 2
Deep-link patterns
- worldbank
https://data.worldbank.org/indicator/{code}?locations={iso2} - owid
https://ourworldindata.org/grapher/{slug} - imf
https://data.imf.org/ - oecd
https://data-explorer.oecd.org/ - eurostat
https://ec.europa.eu/eurostat/databrowser/view/{dataset}/default/table - who
https://www.who.int/data/gho/data/indicators/indicator-details/GHO/{code} - fred
https://fred.stlouisfed.org/series/{code} - bis
https://data.bis.org/ - ilo
https://ilostat.ilo.org/
Validation rules and statuses
Every imported row passes deterministic checks. Unusual values are flagged, never deleted. A whole dataset is quarantined — and the previous good file kept — when it looks broken as a whole (duplicates, unit change, partial download).
| Rule | Severity | Effect |
|---|---|---|
| duplicate | error | Duplicate key inside one dataset → the dataset is quarantined. |
| out_of_bounds | error | Impossible values (negative counts, shares outside [-5, 105], life expectancy outside [20, 100]; registry `bounds`) → row quarantined. |
| unit_mismatch | error | Unit differs from the registry unit → dataset quarantined. |
| extreme_jump | warning | |Δ| > jump_threshold × robust std (MAD) of the country series → row flagged `warning`, kept. |
| partial_download | error | Fewer than 30 % of the rows of the previous run for the same dataset → dataset quarantined, previous kept. |
| stale | info | Source not updated / latest period older than stale_after_days (annual 800 d, quarterly 200 d, monthly 75 d) → status `stale`. |
| unknown_country | info | Unknown country code → row dropped and logged (aggregates are dropped unless mapped to a group). |
Statuses
- VerifiedPassed every check and matches a second source or a previous vintage.
- ImportedPassed every check; no independent confirmation.
- FlaggedKept, but flagged: an extreme jump versus the country’s own history.
- StaleThe latest observation is older than the freshness window for its frequency.
- QuarantinedFailed a hard check; stored for audit, excluded from every derived table.
Freshness windows
A series is stale when its latest period ends more than 800 days ago (annual), 200 days (quarterly) or 75 days (monthly).
Freshness
Three dates travel with every value. Source updated is the vintage the publisher advertises; retrieved is when the pipeline fetched the file; built is when the snapshot was assembled. Pages show all three where they matter, and the footer of every page names the snapshot. A new snapshot is built once a day; the API cache is keyed on the snapshot id, so nothing stale survives a rebuild.
Periods
- annual
YYYY-01-01- quarterly
YYYY-{01,04,07,10}-01- monthly
YYYY-MM-01
Rankings
Rankings compare countries (never territories or aggregates) for the same year. Rank 1 is the best value when the indicator declares a direction — the lowest infant mortality, the highest life expectancy — and simply the highest value when it does not. Group rankings recompute ranks within the group. Ranks are computed only for years with at least 20 countries; when a country’s latest year is more than two years behind the indicator’s latest year, its rank is flagged as stale.
Computed for every ranking-eligible indicator and every year with at least 20 countries. Rank 1 = highest value, or lowest when `higher_is_better` is false. Group rankings recompute ranks within the group.
Changes & events
Changes are detected per country and indicator with fixed, published rules. A year-over-year move counts when it exceeds a robust threshold (twice the median absolute deviation of the series’ yearly differences) and an indicator-specific floor. Record highs and lows, 10/20/30-year highs and lows, sign flips and accelerations are detected on the whole history. Severity is min(1, |z| / 4) blended with how far the move clears the floor, then weighted by the indicator’s importance. Recent detections form the changes feed; the whole history forms each country’s timeline.
Detectors per country × indicator: YoY beyond ±(2 × MAD of yearly diffs) and an indicator-specific floor (inflation ±2 pts, unemployment ±1 pt, GDP growth ±3 pts, population growth ±0.5 pt), record high/low, N-year high/low (10/20/30), sign flip, acceleration/deceleration. severity = min(1, |z| / 4) blended with the floor ratio.
Similarity
Peers are computed per mode from a fixed feature list. Heavy-tailed features (GDP per capita, population, area) are log-transformed, every feature is z-scored across countries using latest values, and the weighted Euclidean distance d between two countries becomes a score 100 × exp(−d / d₀), where d₀ is the median pairwise distance of the mode. A country needs at least 70 % of a mode’s features to be scored; each peer lists which features contributed most, so every match is explainable.
Modes
- Overall
- Economic, demographic, energy and social features together.
- Economic
- GDP per capita (log), growth, inflation, trade openness, sector shares, government size.
- Demographic
- Population (log), median age, fertility, urbanisation, life expectancy, migration.
- Energy
- Energy use per capita, electricity mix shares, CO₂ per capita, energy intensity.
- Social
- Education, health, inequality, digital adoption, quality-of-life indicators.
Heavy-tailed features log-transformed, z-scored across countries (latest values; countries with ≥ 70 % of a mode's features), weighted Euclidean distance d → score = 100 × exp(−d / d₀). Top 12 peers with per-feature contributions.
Insights
Key facts on country pages are template sentences filled with numbers computed from the data (change since a year, rank in a group, distance to the median, average growth). No language model writes or rewrites them; the raw numbers are stored next to the text.
Templates computed from data (e.g. "{country}'s population grew {pct}% since {y0}").
Country DNA
Nine descriptive dimensions, each the percentile rank (0–100) of the country among all countries for one representative indicator or the mean of two or three. It is a fingerprint for reading a country at a glance, not a score and not a ranking.
- Incomegdp-per-capita-ppp
- Demographicsmedian-age, fertility-rate
- Urbanisationurban-population-share
- Trade opennesstrade-pct-gdp
- Energy useenergy-use-per-capita
- Emissionsco2-per-capita
- Innovationrd-expenditure-pct-gdp, patent-applications-residents
- Educationtertiary-enrollment, expected-years-of-schooling
- Public spendinggovernment-expenditure-pct-gdp
The API does not store World Bank aggregates (WLD, OED…). Group values are computed across member countries: sum for additive indicators, population-weighted mean for per-capita/share indicators, median otherwise; the response says which.
Limitations
Group aggregates are computed from the countries present in the snapshot and can differ from published aggregates that use different membership, weights or imputed values. Coverage is uneven: small territories and conflict-affected countries have sparse series. Definitions differ between sources — a series is never mixed, but two countries may be served by two sources. Forecasts are shown only where the chosen source publishes them. Rankings of quarterly or monthly indicators use the last period of the year. Percentile-based fingerprints and similarity scores are sensitive to which countries report a feature.
Versioning & revisions
Every snapshot has a run id (shown in the footer and in every API response). A rebuild never overwrites a value silently: a changed value is recorded as a revision with the previous value and both vintages. Raw source files are kept per run so any number can be traced back to the exact payload it came from. Indicator slugs, group ids and API paths are stable; deprecations are announced on the API page before removal.
Licence
The CountryAtlas compilation is CC BY 4.0. Each value keeps its source licence in the provenance object; see the Sources page for the exact terms per source.
Display formatting
- currency
- compact scale (53.4k, 1.2B, 1.2T)
- percent
- 1 decimal + ' %'
- years
- 1 decimal + ' yrs'
- number
- thousand separators, compact ≥ 10k
- tonnes
- ' t'
- per_1000
- ' per 1,000'
- per_100k
- ' per 100k'