Stapel

Nederlands

Store data

What we have, and what we are missing

Arrival detection is only as good as the coordinates underneath it. Here are the measured figures, including the chains we score worst on.

Version
stores.v1.json, built on
Size
9,153 stores, 36 chains. 593 kB raw, 208 kB gzipped
Source
OpenStreetMap, fetched through Overpass, per chain on brand:wikidata
Licence
ODbL, the same as the source
SHA-256
87e74b87578f31b5eba095b4117c0a03437c03e02b4a53583e1d426ef60bce51

Coverage per chain

"Found" is what the pipeline kept after cleaning. "Published" is what the chain or Locatus says it has.

All 36 chains, worst coverage first. Measured on 7 September 2026, against live Overpass data.
Chain Found Published Coverage
DA21330071%
Pets Place12817075%
Decathlon222492%
C&A9610393%
Blokker576193%
Etos49352294%
Xenos15716595%
Kruidvat9871,01397%
GAMMA16216698%
Karwei12813198%
Praxis18018498%
La Place464798%
Primera54655099%
PLUS43744099%
Lidl437438100%
de Bijenkorf77100%
MediaMarkt5454100%
Trekpleister186185101%
Jumbo695685101%
HEMA560544103%
Ekoplaza8885104%
Welkoop167160104%
Intersport3735106%
IKEA1514107%
Intratuin5753108%
Albert Heijn1,1991,017118%
Holland & Barrett194
H&M85
vanHaren135
Douglas94
ICI PARIS XL141
Rituals96
Shell500
BP187
Esso468
Starbucks99

Why DA and Pets Place sit at the bottom

DA at 71% and Pets Place at 75% are the two worst, and it is not the filter: the shops are simply not in OpenStreetMap. Both are chains of small high-street shops, which is exactly where OSM coverage thins. A missing shop means no arrival alert there; the card itself works as normal.

Why Albert Heijn reads 118%

978 Albert Heijn plus 38 AH XL is 1,016 supermarkets, within one store of the Locatus figure. The entire difference is AH to go: OpenStreetMap knows 178, AH publishes 86. Of those 178, 84 sit inside OK fuel stations and 47 are NS station outlets, and 151 were edited during 2026, so it is not stale. AH appears not to count franchised forecourt shops.

A forecourt kiosk is not a full supermarket, so every record carries its sub-format and the screen decides what to do with it.

What is wrong with it

Five things you should know before trusting this data. All of them measured, none of them suspected.

1. Addresses are missing, and it varies by chain

The twelve worst of 36 chains. Coordinates are complete everywhere.
Chain No address Of total Share
Starbucks239923.2%
Xenos2815717.8%
La Place84617.4%
Shell8350016.6%
Esso7246815.4%
DA2921313.6%
vanHaren1413510.4%
Ekoplaza8889.1%
Douglas8948.5%
Rituals8968.3%
Intersport3378.1%
Praxis141807.8%

Arrival detection runs on coordinates and is unaffected. A postcode search is not: it silently finds nothing for almost a quarter of the Starbucks locations.

2. Kruidvat is too perfect

987 of 987 records have identical tag sets, no missing field, and source=AS Watson BNL: a corporate import, not volunteer mapping. Excellent while somebody refreshes it, and uniformly stale the day they stop, with nothing visibly changing. The other chains degrade gradually; this one falls off a cliff.

3. Nothing notices that a shop has closed

A shop that closes stays in OpenStreetMap until a volunteer removes it, and that lags by months. Etos already has one tagged as vacant while still carrying the brand. There is no check for this in any direction, and it is not solvable from our side. That is why you can pin a shop yourself in the app.

4. The validation catches drift, not wrongness

The build pipeline stops if a chain moves more than 20% against the previous release. Tested: it fails on a 27.2% Lidl swing and on a chain disappearing entirely, and tolerates 3.4%. But it cannot tell a correct number from a consistently wrong one, and the table of expected counts it compares against is hand-entered and rots.

5. The source is one volunteer-funded server

Fetching the first six chains took 881 seconds: 123 to 137 seconds per chain almost regardless of what comes back, because scanning the whole of the Netherlands dominates. For 41 chains that is about 100 minutes, and that is a floor. That load does not belong on a free public service, so the processing moves to a local Geofabrik extract.

How the file is built

  1. A list of Wikidata identifiers per chain, not one. Albert Heijn has three; with only one, 216 stores disappear silently.
  2. Query Overpass with out center meta and cache the answer. Overpass reports a timeout with HTTP 200, so that field is checked separately.
  3. Normalise, round coordinates to five decimals, and merge duplicates within 25 metres.
  4. Filter on a whitelist of shop types. Excluding by name pulls in 65 non-stores for AH alone, including car parks and two charging stations.
  5. Compare against the previous release and stop the build on a large swing.
  6. Stamp a version, a SHA-256 and an ECDSA P-256 signature on it, and publish. Not Ed25519: that only reaches java.security on Android 13, and Stapel runs from Android 8.
  7. Bundle the same file in the app, so a fresh install knows everything offline.

The build is reproducible byte for byte from the cached raw data.

What comes next

The target is 41 chains: an estimated 9,600 to 14,900 stores, 220 to 340 kB gzipped. What remains is extending the chain list and moving the fetch to a local extract.

Attribution and licence

Store locations are derived from OpenStreetMap, © OpenStreetMap contributors, available under the Open Database License (ODbL) 1.0.

The derived database that Stapel bundles and syncs is published under the same licence, along with the code that builds it, and the same attribution appears inside the app on the About screen.

Chain names and logos belong to those chains. The app ships no brand logos by default.