Environment — entry 008 of 18
Luchtmeetnet
Luchtmeetnet is the Dutch national air-quality monitoring network (run by RIVM and partners), publishing measured and forecast pollutant levels from over a hundred stations across the Netherlands. It's a fully open government data feed — no key or registration needed.
Luchtmeetnet is the Dutch national air-quality network (RIVM and partners), exposing 102 monitoring stations (5 pages of /stations, counted live this run) and their measured pollutant readings as open, keyless JSON. A live GET this run against /stations?page=1 returned a real paginated station list (25 stations on page 1 of 5, access-control-allow-origin: *), and a live GET against /measurements?station_number=NL49565 returned genuine current NO2/PM10/NO readings for that station after following a redirect (see gotchas).
GreatAPIs Score
Auth quickstart
- No API key, signup, or credit card required — live GETs this run against
/stationsand/measurementsboth returned real data with zero credentials andaccess-control-allow-origin: *on every response.
Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.
List monitoring stations
GEThttps://api.luchtmeetnet.nl/open_api/stations?page=1
{"pagination":{"last_page":5,"first_page":1,"prev_page":1,"current_page":1,"page_list":[1,2,3,4,5],"next_page":2},"data":[{"number":"NL49565","location":"Oude Meer-Aalsmeerderdijk"},{"...":"24 more stations on this page, 5 pages total"}]}Every list route wraps its results in this same {pagination, data} envelope, confirmed live this run — page_list gives you every page number up front rather than just a boolean has-more flag.
Try it
Developer reference
https://api.luchtmeetnet.nl/open_api100 requests per 5 minutes (fair-use limit), per Luchtmeetnet's own OpenAPI documentation at api-docs.luchtmeetnet.nl
- GET/stations?page={n}
- GET/stations/{number}
- GET/measurements?station_number={number}&page={n}
Gotchas & limits
/measurements?station_number=...doesn't return data directly — a live GET this run got HTTP 302 back with no body, redirecting to a URL the API itself constructs with an injected default 7-day window (.../measurements?...&start=2026-07-24T12:10:46...&end=2026-07-31T12:10:46...&order_by=timestamp_measured). A plain HTTP client must follow that redirect (curl -Lor your library's default) to get the actual readings; a client that doesn't follow redirects silently gets an empty 302 response instead of data.- Once followed,
/measurementsreturns one row per pollutant per hour, not one row per station — a live GET this run for a single station returned separate entries forNO2,PM10, andNOall sharing the sametimestamp_measured, distinguished only by theformulafield. Code that expects one combined reading object per timestamp will silently drop pollutants. - An unknown station number 404s cleanly and predictably — a live GET this run against
/stations/NOTASTATIONreturned{"reason":"not_found","message":"Not Found"}withaccess-control-allow-origin: *still present, so a missing station is easy to distinguish from a CORS or auth failure. - Station numbers are RIVM codes like
NL49565, not free-text city names — get them from/stationsfirst; there's no?city=or geocoding shortcut on the measurements route itself.