The tech behind Plens
KNMI radar, Open-Meteo, openrouteservice and the PDOK Locatieserver: which source Plens uses for what, on which terms, and where it went wrong.
Published Updated 8 min read
In short
- The KNMI radar provides precipitation two hours ahead, in five-minute steps on a one-kilometre grid. Plens pulls it in with its own ingest.
- Open-Meteo adds wind, temperature and the forecast beyond two hours. openrouteservice plans the route, PDOK finds Dutch addresses.
- The most important rule in the code: no data is not the same as no rain.
Plens combines the KNMI radar forecast for the next two hours, Open-Meteo for wind, temperature and the longer forecast, openrouteservice for the route and the PDOK Locatieserver for Dutch addresses.
What data does rain advice for your route need?
Four kinds: precipitation in small steps, the weather around it, the route with your pace, and an address to start from. Plens gets them from four sources, for the app and for plensapp.nl.
| What | Source | Why this one |
|---|---|---|
| Precipitation, 0 to 120 minutes | KNMI Data Platform, radar_forecast 2.0 | 5-minute steps on 1 km, CC BY 4.0 |
| Wind, temperature, later forecast | Open-Meteo | Model forecasts, also beyond the radar |
| Route and elevation | openrouteservice | No caching ban in the terms |
| Addresses in the Netherlands | PDOK Locatieserver | Government data, no key needed |
On top of that, Plens uses its own OpenStreetMap index for shelters and street lighting, and BeSt Address for Belgian addresses. Every source sits behind its own interface, so a provider can be swapped without the scoring model noticing. The sources and licences are public on plensapp.nl/bronnen.
The native app talks to none of these sources directly. The architecture document says the server calculates the departure advice once, following the same product rules as the web app. How Plens went from idea to app is in how we built Plens.
KNMI radar: what it is and how far ahead it looks
The KNMI radar forecast looks two hours ahead, in five-minute steps on a one-kilometre grid. KNMI is the Dutch national weather service. Plens uses the radar_forecast 2.0 dataset from the KNMI Data Platform: a forecast that moves current showers forward in time (an advection nowcast built with pySTEPS), fed by corrected radar images from the Netherlands, Belgium and Germany.
According to the team's source analysis, a new file is ready about 1 minute 50 seconds after its validity time. The licence is CC BY 4.0: commercial use is allowed, with attribution. The Plens sources page adds that KNMI is not involved in Plens and does not endorse it. The radar also covers all of Belgium, measured as far as Arlon and Torgny.
Why Plens doesn't query KNMI per request
The KNMI Open Data API needs an API key. According to the KNMI developer portal, a registered key has a quota of 1,000 requests per hour, and the anonymous key shares its limit with every other anonymous user. Forwarding each user request is therefore not an option.
So Plens runs its own ingest, as a separate worker on its own server. It subscribes over MQTT to notifications of new radar files, downloads the HDF5 file for each notification (about 580 kB), decodes the images, projects the grid and puts the result behind its own HTTP API. That is where the app fetches its per-point series. According to the documentation, that comes down to 288 downloads a day, regardless of the number of users.
The team calls one pitfall the most likely way for this pipeline to fail silently: the sentinel values 65534 (missing) and 65535 (out of image). Fail to mask them and a pixel outside the image comes out at roughly 655 mm per five minutes, which the scoring model turns into an infinitely wet ride.
Why not hourly data?
Because a short shower disappears in an hourly average. The Plens provider documentation makes the point with an example: a shower that starts at 08:12 and stops at 08:34 simply does not exist in an hourly average.
On a twenty-minute ride, that is the difference between arriving dry and arriving wet. So the radar leads on precipitation as far as it reaches, and Open-Meteo is the source for everything around it.
Open-Meteo: what for, and on which terms
Open-Meteo provides what the radar doesn't: wind, temperature and the precipitation forecast beyond two hours. Plens merges the two series. The radar leads on precipitation, Open-Meteo adds temperature and wind, and beyond the radar horizon the model takes over.
That handover went wrong at first, and the documentation is open about it. The merged series stopped at the last radar step, so a four-hour ride got that final radar frame for its last two hours. If it happened to be raining when the radar looked, it rained all afternoon. On a commute you never notice. It only showed up once longer tours were added. Plens now appends the model steps after the radar series, each with its own time span, so an hour between two model steps doesn't count as a gap in the data.
Open-Meteo is clear about its terms. According to its terms of use, the free API is for non-commercial use only, and apps with subscriptions or advertising are explicitly called commercial. For that, Open-Meteo offers paid API plans. The data is licensed CC BY 4.0, so attribution is required. Plens shows a source line with your weather that says which data was actually used, including when the radar is temporarily missing.
Route and pace: openrouteservice
openrouteservice plans the route, and Plens splits it into chunks of about two minutes of cycling. It samples by time, not distance: at most 40 points per route, each in the middle of its chunk.
That matches the radar. At 18 km/h you cover one and a half kilometres in five minutes, so points at equal riding time fit five-minute steps on a one-kilometre grid. And each point stands for the same number of minutes outside, so fast stretches don't quietly count for more.
The weather interface works with time series per point. Twelve departure times times twelve route points are not 144 requests but twelve series. That makes a full comparison of departure times cheap enough to run at every check. Elevation comes back in the same routing request, at no extra cost.
Why openrouteservice
A commute rarely changes, so you want to plan it once and store it. That ruled out most route planners: according to the team's analysis, Google, Mapbox and Stadia Maps, among others, forbid storing routes. The openrouteservice terms contain no caching ban. As a result, ride planning requests a regular route at most once every thirty days.
The free tier has a per-minute and a per-day limit, each with its own error code: 429 for too many requests per minute, where waiting helps, and 403 when the daily quota is used up, which only tomorrow fixes. Until 7 September the code only recognised the 429. Anyone who had used up the daily quota was told to try a different starting point, which could never work.
On 6 October openrouteservice returned seven timeouts and one HTTP 502 between 22:40 and 22:45. Since then there is a layer around it. If the service hasn't answered after 2.5 seconds, a second request goes out alongside. A successful route stays in server memory for ten minutes, and after three failures within a minute Plens skips the service for thirty seconds. If that still fails, the advice carries on with an estimated route and the screen says the route is estimated.
Addresses: the PDOK Locatieserver
For Dutch addresses Plens uses the PDOK Locatieserver: an open, free geocoding API on government data such as the BAG address register, with no API key and commercial use allowed. For Belgium it uses BeSt Address from the Belgian federal government (BOSA).
Plens queries one country, and the other only if the first found nothing. PDOK knows no Belgian addresses and BeSt no Dutch ones, so an empty list really does mean the wrong country. That keeps traffic to two free government services low.
Typos needed a fix of their own. For “Delfseplein 27” the suggest endpoint returns zero results, but in the same response PDOK sends a spelling correction with 14 hits for “delftseplein 27”. Plens didn't read that block at first, so someone missing one letter was told their address did not exist. Now Plens does one second round on that correction.
Plens doesn't look up stations through PDOK. They sit in its own index of 2,005 train, metro and bus stations from OpenStreetMap, stored as a file in the repo: no request, no quota, no waiting.
Limits and pitfalls
The biggest pitfall is a failed request that looks like dry weather. A failed weather request returns zeros, and zeros look like a dry ride. That is why every weather sample carries a hasForecast flag, and without a forecast Plens gives no advice and no notification. The documentation calls this the one failure mode the product cannot afford. There are tests on it.
The second limit is reliability. The scoring model rates it as high up to 35 minutes of lead time, medium up to two hours and low after that, backed by verification studies of radar forecasts over the Netherlands. Uncertainty is not part of the score. At lower reliability the threshold for giving advice goes up, by up to 1.6 times, and the wording changes. The KNMI nowcast itself is deterministic, so no probability comes out of it, and Plens doesn't invent one.
The third is quota. The app may not query KNMI per request, and the openrouteservice daily quota is shared between the route drawer and ride planning. Drawing a loop with twenty points costs twenty requests.
The fourth lies in the source. The radar works in coarse steps: the smallest is 0.12 mm per hour, and light rain drops below that threshold at longer lead times. So you can feel drizzle while the screen says 0.0. Plens therefore also looks at the eight cells around your point and reports dry on your route with rain nearby, without that shifting your departure time.
And the thresholds are a choice. On 11 September 2026, 96 settings were tested against 99,301 rides from 2025. Precision barely moved, between 47 and 57 percent, while the number of pieces of advice halved. The threshold decides how much of the forecast you believe. It doesn't make the forecast any better.
Language is a separate layer. A model works out which destination and which intention someone means, but the calculating, planning and decision rule stay in code. How that works is in where Jev fits in your product. It is how we often build: the model gets a narrow task, and the rest stays code you can check.
To see what this adds up to, the Plensradar and the departure advice work without an account on plensapp.nl, and the product's current status is on our product page.
Frequently asked questions
Is the KNMI API free?
The radar_forecast dataset is licensed CC BY 4.0 and may also be used commercially, with attribution. You do need an API key. According to KNMI, a registered key has a quota of 1,000 requests per hour, and for new files KNMI recommends its Notification Service.
Can you use Open-Meteo commercially?
Not with the free API. According to Open-Meteo's terms, it is for non-commercial use only, and apps with subscriptions or advertising count as commercial. Paid API plans cover that.
What is PDOK?
PDOK (Publieke Dienstverlening Op de Kaart) is the platform where the Dutch government publishes geodata. The Locatieserver is its search service for addresses, postcodes and place names, among other things, open and free.
Why doesn't the app call the providers directly?
For three reasons. The quotas don't allow it, no provider key belongs in the app bundle, and the server calculates the advice once following the same product rules as the web app. That way the app and the website give the same advice.
Sources
- KNMI Developer Portal: Open Data APIdeveloper.dataplatform.knmi.nl
- Plens: sources and licencesplensapp.nl
- Open-Meteo: API documentationopen-meteo.com
- Open-Meteo: terms of useopen-meteo.com
- openrouteservice for developersopenrouteservice.org
- PDOK Locatieserverpdok.nl
- Creative Commons CC BY 4.0creativecommons.org