
CBS StatLine API gebruiken: OData v3 en v4
Het CBS biedt alle StatLine-tabellen als open data via OData, zonder API-sleutel. Er draaien twee versies naast elkaar: v3 op opendata.cbs.nl en v4 op datasets.cbs.nl. Bij v4 geeft u een tabelcode, een maat en een periode op en volgt u de nextLink. Hieronder staan getest voorbeelden in curl en Python, de limieten en de valkuilen.

Wat is de CBS StatLine API en welke versies bestaan er?
StatLine is de database met statistieken van het Centraal Bureau voor de Statistiek. Het CBS stelt elke tabel ook beschikbaar als open data. Een tabel heeft een code, zoals 85496NED voor Bevolking; kerncijfers. De letters aan het eind geven de taal aan: NED is Nederlands.
Op 11 oktober 2026 bleken twee API's te antwoorden. De oude OData v3-API staat onder opendata.cbs.nl/ODataApi/odata/ en geeft per tabel een wijde tabel (een kolom per maat). De nieuwere OData v4-API staat onder datasets.cbs.nl/odata/v1/CBS/ en geeft een lange vorm: één rij per waarneming, met een maatcode en een periode. Beide vragen geen sleutel en sturen Access-Control-Allow-Origin: * mee.
| Eigenschap | OData v3 | OData v4 |
|---|---|---|
| Basis-URL | https://opendata.cbs.nl/ODataApi/odata/{tabel} | https://datasets.cbs.nl/odata/v1/CBS/{tabel} |
| Vorm van de data | Wijd: TypedDataSet of UntypedDataSet | Lang: Observations met Measure, Value, dimensiecodes |
| Metadata | TableInfos, DataProperties, per dimensie een eigen set | Properties, MeasureCodes, MeasureGroups, Dimensions, PeriodenCodes |
| Limiet per antwoord | Minder dan 10.000 records | Maximaal 100.000 cellen, daarna @odata.nextLink |
| Catalogus | https://opendata.cbs.nl/ODataCatalog/Tables | https://datasets.cbs.nl/odata/v1/CBS/Datasets |
| Licentie | CC BY 4.0, vermeld in Properties van de v4-tabel | |
| Sleutel nodig | Nee | Nee |
Een andere route naar dezelfde cijfers is het gebiedsbestand van het CBS met wijk- en buurtgrenzen, dat via PDOK loopt; zie daarvoor CBS Wijken en Buurten.
Hoe vind ik de juiste tabel?
Zoek de tabelcode via de catalogus, niet via een zoekmachine. De catalogus accepteert OData-filters op titel, status en frequentie. Dat is nodig omdat er meerdere tabellen met bijna dezelfde titel bestaan, ook stopgezette.
curl -s -G "https://opendata.cbs.nl/ODataCatalog/Tables" \
--data-urlencode "\$format=json" \
--data-urlencode "\$filter=startswith(Title,'Bevolking; kerncijfers') and Frequency ne 'Stopgezet'" \
--data-urlencode "\$select=Identifier,Title,Modified,Period,Frequency"
Het antwoord op 11 oktober 2026 was één tabel: 85496NED, Bevolking; kerncijfers, periode 1950 tot en met 2025, frequentie per jaar. De voorganger 37296ned (Bevolking; kerncijfers, 1950-2022) staat als stopgezet in de catalogus en heeft geen waarden voor 2024. Wie dus een oude tabelcode uit een voorbeeld of blog overneemt, krijgt zonder foutmelding verouderde of lege cijfers terug.
Op de v4-kant kan dezelfde check met Datasets?$filter=Identifier eq '85496NED'. Daar staan onder meer Status (bij deze tabel Regulier), Modified en ObservationCount (3.432). Let op: de wijzigingsdatum in beide API's liep op 11 oktober 2026 niet gelijk. De v3-catalogus gaf 21 augustus 2026, de v4-Properties gaf 8 september 2025. De waarden voor 2023 tot en met 2025 waren in beide API's gelijk, maar controleer bij kritisch gebruik welke versie u leest.
Hoe haal ik cijfers op met OData v4 in curl en Python?
In v4 filtert u de collectie Observations op een maatcode en een periode. De maatcode zoekt u in MeasureCodes; de periode heeft de vorm 2025JJ00 voor een jaar.
curl -s -G "https://datasets.cbs.nl/odata/v1/CBS/85496NED/Observations" \
--data-urlencode "\$filter=Measure eq 'T001038_2' and Perioden ge '2023JJ00'" \
--data-urlencode "\$select=Perioden,Value"
Antwoord op 11 oktober 2026:
{"value":[
{"Value":17811291.0,"Perioden":"2023JJ00"},
{"Value":17942942.0,"Perioden":"2024JJ00"},
{"Value":18044027.0,"Perioden":"2025JJ00"}]}
Hetzelfde in Python met alleen de standaardbibliotheek, inclusief het volgen van @odata.nextLink:
import json, urllib.parse, urllib.request
BASE = "https://datasets.cbs.nl/odata/v1/CBS/85496NED"
def get(url):
with urllib.request.urlopen(url) as r:
return json.load(r)
# 1. welke code hoort bij "Totale bevolking"?
maten = get(BASE + "/MeasureCodes")["value"]
code = next(m["Identifier"] for m in maten if m["Title"] == "Totale bevolking")
print("eerste maatcode met die titel:", code)
# 2. observaties vanaf 2023, met nextLink-paginering
url = BASE + "/Observations?" + urllib.parse.urlencode({
"$filter": f"Measure eq '{code}' and Perioden ge '2023JJ00'",
"$select": "Perioden,Value",
})
while url:
page = get(url)
for o in page["value"]:
print(o["Perioden"], int(o["Value"]))
url = page.get("@odata.nextLink")
De uitvoer was T001038_2, gevolgd door de drie jaarwaarden hierboven. Let op de eerste regel: in deze tabel heet meer dan één maat Totale bevolking (ze horen bij verschillende groepen, zoals geslacht en burgerlijke staat). De code hierboven neemt de eerste. Kies een maat daarom op code en groep, en nooit alleen op titel.
Hoe haal ik dezelfde cijfers op met OData v3?
In v3 staat elke maat als kolom in TypedDataSet. De kolomnamen krijgen een volgnummer, zoals TotaleBevolking_1. De betekenis staat in DataProperties.
curl -s -G "https://opendata.cbs.nl/ODataApi/odata/85496NED/TypedDataSet" \
--data-urlencode "\$format=json" \
--data-urlencode "\$filter=Perioden ge '2024JJ00'" \
--data-urlencode "\$select=Perioden,TotaleBevolking_1,Mannen_2"
Dit gaf bij een herhaling op 12 oktober 2026, in bash en in zsh, drie rijen: 2024 met 17.942.942 inwoners (8.920.768 mannen), 2025 met 18.044.027 inwoners (8.978.451 mannen) en 2026 met 18.130.208 inwoners (9.025.827 mannen). De v3-tabel bevat dus al 2026, terwijl de v4-Observations op dezelfde dag tot en met 2025 liepen; dat past bij het verschil in wijzigingsdatum hierboven. De backslash voor $filter en $select is nodig: zonder die backslash maakt de shell er een lege variabele van en negeert de API het filter. Zonder $select krijgt u alle kolommen van de tabel per rij.
De grootste valkuil in v3 is de limiet. Een verzoek voor de tabel 83765NED (kerncijfers wijken en buurten 2017) zonder filter gaf status 500 met de melding dat de query minder dan 10.000 records moet opleveren. Beperk dus met $filter (bijvoorbeeld op Perioden of WijkenEnBuurten) en $select. Lukt dat niet, dan is v4 met zijn nextLink de betere keuze.
Het CBS beschrijft de limiet van v4 zo:
Een antwoord van een data-verzoek bevat maximaal 100 000 cellen, dus om een grotere dataset te downloaden moeten er meerdere verzoeken aan de API worden gedaan.
Bron: CBS, snelstartgids OData v4, gelezen op 11 oktober 2026. Het CBS legt daar uit dat bij een afgekapt antwoord de link naar het volgende deel in @odata.nextLink staat.
Hoe lees ik de periode-, regio- en maatcodes?
Een CBS-tabel is opgebouwd uit dimensies (zoals perioden en regio's) en maten (de getallen). De codes zijn tekst met een vast stramien en hoeven niet rekenkundig te zijn.
- Perioden
- Voor jaren
2025JJ00. Tabellen met kwartalen of maanden gebruiken andere codes. De volledige lijst staat inPerioden(v3) ofPeriodenCodes(v4). - Maat
- Een numerieke waarde met een eenheid, bijvoorbeeld aantal of procent. In v3 is dat een kolom, in v4 de waarde van
Measure. - Dimensie
- Een indeling zoals geslacht, regio of leeftijd. Elke dimensie heeft een eigen codelijst, die u via de metadata ophaalt.
- ValueAttribute
- In v4 een kenmerk bij een waarde. Bij de test stond het op
None. Lees de toelichting bij de tabel voordat u een waarde met een ander kenmerk gebruikt.
Cijfers uit StatLine over buurten en wijken koppelt u aan geometrie via de code van het gebied. Die code moet exact gelijk zijn, inclusief spaties. Hoe dat in de praktijk gaat met kaarten, leest u op de pagina CBS Wijken en Buurten en bij Python voor GIS.
Welke licentie en voorwaarden gelden?
De v4-metadata van tabel 85496NED noemt als licentie https://creativecommons.org/licenses/by/4.0/, dus CC BY 4.0. Commercieel gebruik is toegestaan, bronvermelding is verplicht. Vermeld dus het CBS, de tabelcode en het moment van ophalen.
Het CBS zegt over het aanbod zelf: "Alle datasets die via StatLine te bekijken en te downloaden zijn, worden ook beschikbaar gesteld als open data." Een API-sleutel of registratie wordt op de CBS-pagina's over open data niet genoemd en was bij de tests niet nodig. Een gepubliceerde limiet op het aantal verzoeken per seconde stond niet op de gelezen pagina's. Een GET-verzoek op de v3-dataverzoeken onder ODataApi, zoals TypedDataSet, stuurt Cache-Control: public, max-age=1800 mee; gebruik die om herhaald ophalen te beperken. De catalogus onder ODataCatalog stuurt private mee, en een HEAD-verzoek geeft no-cache (getest op 12 oktober 2026). Meer over de keuze tussen licenties staat op open data-licenties.
StatLine bevat geaggregeerde cijfers. Behandel een lege of ontbrekende waarde nooit als nul: de toelichting bij de tabel vertelt of een cel ontbreekt omdat het cijfer niet bestaat, nog niet bekend is of niet gepubliceerd wordt.
Valkuilen bij het gebruik van de CBS-API
- Stopgezette tabellen. De catalogus bevat veel tabellen met status Stopgezet. Filter op
Frequency ne 'Stopgezet'of controleerStatusin v4. - Dubbele titels. Meerdere maten of tabellen delen een titel. Werk met codes.
- Lege waarden. Een ontbrekende waarde kan verschillende oorzaken hebben. Lees
ValueAttributeen de toelichting bij de tabel. - Foutmelding bij te grote queries. In v3 volgt bij te veel records een 500 met een duidelijke melding. Filter eerst op periode of regio.
- Wijde versus lange vorm. Code voor v3 werkt niet op v4 en omgekeerd. Kolomnamen in v3 (zoals
TotaleBevolking_1) bestaan in v4 niet. - Versie-verschillen. De wijzigingsdatum van dezelfde tabel verschilde in de twee API's. Noteer in uw eigen bronvermelding welke API u gebruikte.
- Regiocodes en indelingen. Gemeenten fuseren en wijkindelingen veranderen per jaar. Gebruik de tabel van het jaar dat bij uw geometrie hoort.
Wanneer is StatLine niet de goede bron?
- Geometrie nodig. StatLine levert getallen, geen vormen. Voor grenzen en vlakken gebruikt u de CBS-gebiedsindelingen via PDOK; zie PDOK.
- Adres- of objectgegevens. Cijfers over individuele woningen en gebouwen komen uit de BAG, niet uit een statistiek.
- Realtime of dagelijkse gegevens. De tabellen verschijnen per jaar, kwartaal of maand. Dagcijfers komen er zelden in.
- Zware analyse. Laad een tabel eenmalig in een eigen database of dataplatform, in plaats van bij elke paginaweergave de API te bevragen.
Hoe u zulke cijfers in een dashboard of een open-dataplatform ontsluit, beschrijft de dienst dashboards en de dienst open data-platform. Voor een koppeling die elke nacht een CBS-tabel ophaalt en opslaat, zijn API-koppelingen het uitgangspunt, en de afspraken over API's bij de overheid staan in NL API Design Rules.
Veelgestelde vragen
Heeft de CBS StatLine API een sleutel nodig?
Nee. De OData v3- en v4-API's antwoordden op 11 oktober 2026 zonder API-sleutel of registratie. De licentie is CC BY 4.0, dus bronvermelding is verplicht. Een gepubliceerde limiet op het aantal verzoeken is niet gevonden. Gebruik daarom caching, bijvoorbeeld door een tabel eenmaal per nacht op te halen en lokaal op te slaan in plaats van bij elke paginaweergave.
Wat is het verschil tussen CBS OData v3 en v4?
V3 geeft een wijde tabel met een kolom per maat en weigert antwoorden vanaf 10.000 records. V4 geeft één rij per waarneming, met maximaal 100.000 cellen per antwoord en een @odata.nextLink voor de rest. Beide draaien naast elkaar en vragen geen sleutel. Kies v4 voor grote tabellen; v3 is handig als u een wijde tabel direct in een spreadsheet wilt.
Hoe vind ik de tabelcode van een StatLine-tabel?
Vraag de catalogus op: opendata.cbs.nl/ODataCatalog/Tables met een $filter op titel, of de v4-collectie Datasets. De code staat ook in de URL van de tabel op StatLine. Controleer altijd of de tabel niet is stopgezet: oude codes uit blogs en voorbeelden geven zonder foutmelding verouderde of lege cijfers terug.
Waarom krijg ik een lege lijst terug?
Meestal omdat de tabel stopgezet is of de periodecode niet bestaat. De tabel 37296ned loopt tot en met 2022, dus een filter op 2024JJ00 geeft een lege value-lijst. Gebruik de actuele tabel en kijk in de periodecodes welke waarden bestaan.
Kan ik CBS-cijfers op een kaart tonen?
Ja, door de cijfers te koppelen aan de gebiedscode van wijk, buurt of gemeente en de geometrie apart op te halen, bijvoorbeeld via PDOK. De gebiedsindeling verandert per jaar, dus gebruik tabel en geometrie van hetzelfde jaar. Let erop dat codes exact gelijk zijn, inclusief spaties aan het eind van v3-codes.
Bronnen
- CBS — StatLine als open data (gelezen op )
- CBS — Snelstartgids OData v4 (gelezen op )
- CBS OData v4 — tabel 85496NED (Properties) (gelezen op )
- CBS OData v4 — Datasets (gelezen op )
- CBS OData v3 — catalogus (gelezen op )
- CBS OData v3 — tabel 85496NED (TableInfos) (gelezen op )
Meer over TechinFlow
Een nieuw bureau in Haarlem voor maatwerk software, GIS en dataplatforms op open standaarden.
Een vraag of opdracht?
Vertel kort wat er speelt en voor welke organisatie. We reageren per e-mail.
Stuur een bericht