Geocode millions of addresses without sending one outside your infrastructure.
One country file. No database import, no external API quota, no per-request fee. CLI, Python and DuckDB.
Download free Run your first query See accuracy evidence
Fits: local, privacy-sensitive or high-volume address workloads in France, Italy, the Netherlands and Serbia — forward, reverse and batch, address-first. Does not fit today: worldwide coverage, a hosted endpoint, or POI-first search outside France.
gridpin meta france.bin prints the source, licence and attribution fields of the sheet; redistribution is governed by that source licence.Three ways to geocode, and what each costs you
| What it costs you | GridPin | Typical hosted geocoding API | Self-hosted OSM stack |
|---|---|---|---|
| Where your query text goes | stays on your machine | to the provider | stays on your infrastructure |
| Getting started | install the engine, download one country sheet | sign up, usually get a key | import a database, tune it |
| Running it | no service or database to operate; the CLI or library memory-maps the sheet | nothing of yours to operate | you keep the database alive and current |
| Cost per extra query | no vendor fee; the compute is yours | usually metered or plan-limited | no vendor fee; the compute is yours |
| Interfaces | CLI, Python, DuckDB | HTTP | HTTP |
| Coverage today | France, Italy, the Netherlands, Serbia | worldwide | worldwide |
The last row is the honest limit: if you need worldwide coverage or a hosted endpoint, GridPin is not your tool today. The rest of this page is about the case where it is.
Where the truth is the national registry, we are exact: 99.7% at rank 1, 0.00 m median error
On France’s BAN reference sets — the national address registry, which is also what our French sheet ships — GridPin answers 99.7% of clean queries and 99.3% of typo-mangled ones at rank 1, with a median coordinate error of 0.00 m. Photon, searching OSM, scores 44.9% and 37.8% with a 26.7 m median error on the same queries. Most of that gap is data rather than algorithms: an evaluation whose answer key is the registry favours the engine that ships the registry. If your addresses are French registry addresses, that is precisely the point — and it is also why we publish the harder measurement right below instead of stopping here.
| Engine | Recall@1, clean | Recall@1, typos | Median error |
|---|---|---|---|
| GridPin | 99.7% | 99.3% | 0.00 m |
| Photon | 44.9% | 37.8% | 26.7 m |
Truth: France’s national BAN registry. Recall@1 on clean and typo-mangled queries; median coordinate error on hits. Full record and reproducibility notes under Evidence.
Two more axes where the comparison is not close, and they are the reason people pick a file over a service: speed — ~3,000 exact lookups per second on a single arm64 core, with no network round-trip in the loop — and cost and privacy: no per-query fee at any volume, and not one query leaves your machine, so there is nothing for anyone to meter or log.
The second measurement is deliberately the hard one for us. Measured against Photon and
Nominatim in one run on 1,200 provenance-bearing rows, 1,000 of which are OSM-derived
— that is, the answer key is the data both competitors search. They lead that
slice: 97.3% and 94.2% against our 86.9%. On the 200 Overture Places rows — whose
relationship to all three engines is unknown, which is not a proof of
independence — the descriptive order inverts: GridPin 78.5%, Nominatim 66.5%,
Photon 59.5%. That slice is the smaller one because the provenance rules drop every row
whose coordinate could have come from the same export as the indexed sheet; we publish
the count rather than pad it. No country row has GridPin ahead of both, and Italy is
our weakest country.
Which of those resembles your own addresses is the one thing we cannot measure for you. The sheets are free and need no account, so the answer costs you an afternoon.
Download the free sheets Five-minute start Full measurement record
Evidence
Everything behind the numbers above: both runs with their corpora and hashes, the per-country and lineage breakdowns, competitor identities, the registry-reference and POI pilots, throughput, methodology, the reproduction recipe and the open work. Nothing here is hidden — it is folded because the buyer path should not run through a lab notebook.
Full benchmark runs — hybrid 1,200 rows and the strict 230-row POI corpus
August 2026 pre-release
Two measurements, kept apart on purpose. The first compares three services on one 1,200-row hybrid corpus; the second is a separate, smaller corpus whose coordinates are established as independent of OSM and of the registries we index. Same metric in both: hit@1 within 300 m, empty answers counted as misses.
Hybrid run — 2026-08-04, 1,200 rows
Result SHA-256 4158865253d072f40bc1f2cacfe1c7f3380d11e84c54356b527ab12ad7851ac9,
corpus SHA-256 d62033a60c434fe1d9a8937681cb014e8d2f75bccb934df465a791dda227433f.
All three services measured in one run, on the sheets this release ships. Read it split by
where the answer key came from — the two halves do not say the same thing.
| Where the answer key came from | Rows | GridPin | Photon | Nominatim |
|---|---|---|---|---|
OSM / Geofabrik — same_dataset_family for both competitors: they search OSM-derived data |
1,000 | 86.900% | 97.300% | 94.200% |
Overture Places — relationship to all three engines unknown, which is not a proof of independence |
200 | 78.500% | 59.500% | 66.500% |
On the OSM half we are 10.4 points behind Photon and 7.3 behind Nominatim. On the Overture half we are 19.0 points ahead of Photon and 12.0 ahead of Nominatim. Both halves are descriptive: no cell here is eligible for a headline, and five sixths of the corpus is the first row, which is why the mixed 1,200-row total often quoted as “the” number — GridPin 85.500%, Photon 91.000%, Nominatim 89.583% — mostly measures the first row. Per country the picture is: Photon leads the mixed total, France and Italy; in the Netherlands Photon and Nominatim tie at the top; in Serbia we are above Photon but below Nominatim. No country row has GridPin ahead of both.
Strict POI run — 2026-08-05, 230 rows (a different corpus)
A separate measurement, not a third row of the run above: another corpus,
another day, 230 rows instead of 1,200. It exists because the hybrid corpus is five
sixths OSM-derived, so no cell there is eligible for a headline. This one is built
from the single coordinate provider whose independence from OSM and from the
registries we index is established — Foursquare-sourced Overture Places
rows. That is the claim the evidence supports; independence from everything is not.
All 230 rows are outside_chain — FR 43, IT 129, NL 17,
RS 41 — and this is the cap-respecting maximum available.
Result SHA-256:
03a227a79967c1f41bb49a9f4c2c5228e69e1b8c15e1d80c2f9a2f70ee040d28,
generated 2026-08-05.
| Engine | hit@1 ≤300 m | 95% Wilson CI | vs GridPin | exact McNemar |
|---|---|---|---|---|
| GridPin | 60.870% 140 / 230 | 54.4–66.9 | — | — |
| Nominatim | 55.652% 128 / 230 | 49.2–61.9 | −5.217 pp | p = 0.0652 |
| Photon | 50.435% 116 / 230 | 44.0–56.8 | −10.435 pp | p = 0.0018 |
The two comparisons do not carry the same weight, and we do not blur the difference. Against Photon the lead is significant at the conventional 5% level. Against Nominatim it is not: p = 0.0652 means the direction favours GridPin while the evidence remains insufficient, so we make no claim of superiority over Nominatim from this run. The corpus comes from a single provider and its rows are places, not street addresses: this measures an adjacent capability, not general address accuracy. Italy contributes 129 of the 230 rows, so the total leans on our weakest country.
Per-country breakdown, and the recipe behind the corpus
Public lineage-disclosed benchmark (FR / IT / NL / RS)
Truth recipe: fixed Overture Places + Geofabrik OSM hybrid, exactly 300 rows
per country and at least 150 unknown_lineage rows per country.
Corpus SHA-256: d62033a60c434fe1d9a8937681cb014e8d2f75bccb934df465a791dda227433f.
Postcode is included when available. Metric: hit@1 within 300 m; empty
answers are misses. Status date: 2026-08-04.
| Country | GridPin | Photon | Nominatim |
|---|---|---|---|
| France | 85.333% 256 / 300 | 91.333% 274 / 300 | 87.000% 261 / 300 |
| Italy | 72.667% 218 / 300 | 89.667% 269 / 300 | 83.000% 249 / 300 |
| Netherlands | 96.667% 290 / 300 | 97.333% 292 / 300 | 97.333% 292 / 300 |
| Serbia | 87.333% 262 / 300 | 85.667% 257 / 300 | 91.000% 273 / 300 |
Photon leads the mixed total, France and Italy; in the Netherlands Photon and
Nominatim tie at the top; in Serbia we are above Photon but below Nominatim.
No country row has GridPin ahead of both. The mixed total —
GridPin 85.500%, Photon 91.000%, Nominatim 89.583% — is descriptive, not an
independent winner ranking: 1,000 of the 1,200 truth rows are direct OSM, so
five sixths of the corpus is same_dataset_family for both
competitors. The ranking inverts on the source split. On the 1,000 OSM
rows: Photon 97.300%, Nominatim 94.200%, GridPin 86.900%. On the 200 Overture
Places rows, whose relationship to all three engines is unknown:
GridPin 78.500%, Nominatim 66.500%, Photon 59.500%.
unknown lineage means the relationship has not been
established — it is not proof of independence.
Exact GridPin sheet identity
| Country | Sheet SHA-256 | source_release |
|---|---|---|
| FR | f7278398c1a63308ea3dc69e5cda2f779250716fc231b2122d6ee890da237839 | 2026-06-12 |
| IT | 37346d884e551189e91f0453d4aad7aafe211430e62b1e9054141081488b021c | 2026-06-17.0 |
| NL | d5205f8e323eeda309f3d411a3efcd45c259005d2da25fef33998bf9ca9d28e7 | 2026-06-17.0 |
| RS | 9e358bd6a940b290e01cd52081e476e2799513f16dd934dc6a5bc89ba4fb5388 | 2026-06-17.0 |
Result SHA-256: 4158865253d072f40bc1f2cacfe1c7f3380d11e84c54356b527ab12ad7851ac9,
generated 2026-08-04. These are the sheets this release ships — the
hashes above match the published files byte for byte, so the run can be
repeated on exactly the measured data.
Photon 1.2.0 (git c6dc628a) was self-hosted, not the public
demo, imported from the published planet dump with
-country-codes fr,it,nl,rs and languages en,fr,it,nl,sr;
its sealed response cache SHA-256 is
83b99805cddd0aabafe4847830bf430b9cc5ee7e478068ffb087a5fd6b994d83.
Nominatim 5.3.0 (database 5.3.99-1, data_updated
2026-08-04) was queried once through the public endpoint at a 1.5 s
sequential pause with an identifying User-Agent; its sealed cache SHA-256 is
9a071a3e12c45e2f9d550b2a35db2d7ac4fca07b075f38f49983af959b19789c.
Both competitors hold newer data than the compared sheets
(2026-06-12/2026-06-17.0); this was not corrected for.
Public benchmark by disclosed lineage
outside_chain means a directly evidenced coordinate source
outside the known sheet chain; common_upstream names a known
shared ancestor; unknown_lineage is deliberately fail-closed.
Empty class slices are reported as null, never as zero.
| Country | Lineage | GridPin | Photon | Nominatim |
|---|---|---|---|---|
| France | outside_chain · 27 | 92.593% | 74.074% | 74.074% |
| France | common_upstream · 0 | — | — | — |
| France | unknown_lineage · 273 | 84.615% | 93.040% | 88.278% |
| Italy | outside_chain · 5 | 20.000% | 40.000% | 40.000% |
| Italy | common_upstream · 0 | — | — | — |
| Italy | unknown_lineage · 295 | 73.559% | 90.508% | 83.729% |
| Netherlands | outside_chain · 1 | 100.000% | 100.000% | 100.000% |
| Netherlands | common_upstream · 0 | — | — | — |
| Netherlands | unknown_lineage · 299 | 96.656% | 97.324% | 97.324% |
| Serbia | outside_chain · 39 | 79.487% | 33.333% | 69.231% |
| Serbia | common_upstream · 0 | — | — | — |
| Serbia | unknown_lineage · 261 | 88.506% | 93.487% | 94.253% |
Lineage is disclosure, not a blanket independence badge. The known common ancestors are BAN for France; ANNCSU or OpenAddresses for Italy; BAG/Kadaster or OpenAddresses for the Netherlands; and RGZ or OpenAddresses for Serbia. OSM-derived rows remain unknown and also favour the OSM-backed comparators. Alsace, Isole, and Drenthe are regional rather than national OSM extracts (Serbia is country-wide); both source and geography limits must stay beside the numbers.
geocoder-tester interoperability
geocoder-tester
is an external compatibility fixture suite, not a geocoder, address
database, or accuracy oracle. Tested upstream identity:
5384d1534bc3c59e8d280be3d951a92356ce470b.
| Probe | Observed result | What it proves |
|---|---|---|
Official Alsace forward fixture with --loose-compare |
1 case passed | Photon-style forward response shape only |
| Same fixture, strict comparison | failed on apostrophe/accent normalization | Strict value compatibility is not complete |
| Full official Alsace numbered-address file | 230 / 285 passed (hybrid focus, 2026-08-07) | Forward house numbers interoperate; 55 component mismatches remain (0 → 173 → 208 → 230 as the adapter matured) |
| Reverse fixtures (upstream world file) | implemented; consumed without protocol errors | Photon /reverse endpoint added 2026-08-06; the file has no French case, so it cannot score the one-country France sheet |
This is not a full-suite pass. The one-case smoke proves that the
forward response is consumable and house-number output is no longer the
universal blocker. The remaining 55 mismatches prove that full component
compatibility is still incomplete. Accuracy comes from the separate
coordinate benchmark above, not from geocoder-tester.
Reproducibility: hybrid run 2026-08-07 (230/285), tested binary SHA-256
47a6ecf2cee6835dec7c7dd2fb331ebb5c8708f084e3b02f6bb5239b6e2103b8;
adapter-only baseline 208/285; historical 173/285 (2026-08-02) and 0/285 (2026-08-01).
Full JUnit/report hashes in
docs-public/BENCHMARK.md.
Registry-reference benchmark (Tier 1, France)
Truth: national BAN registry. Recall@1 on clean and typo-mangled queries; median coordinate error on hits.
| Engine | Recall@1, clean | Recall@1, typos | Median error |
|---|---|---|---|
| GridPin | 99.7% | 99.3% | 0.00 m |
| Photon | 44.9% | 37.8% | 26.7 m |
Read this before quoting the gap. Most of the difference is data, not algorithms. Photon geocodes OpenStreetMap; GridPin ships the BAN registry itself. An evaluation whose ground truth is the registry inherently favors registry-backed data. This table shows what you get when the registry is the truth you care about — it does not show that GridPin's matching is 55 points smarter than Photon's.
POI queries pilot (France)
Queries: place name + city. Truth: Wikidata coordinates. GridPin uses the optional POI layer (231 MB, Overture places).
| Engine | Resolved ≤ 500 m | Resolved ≤ 2 km |
|---|---|---|
| GridPin with optional POI layer | 49% | 62% |
| Photon | 71% | not measured* |
*Photon was measured at the 500 m threshold only; the 2 km figure will be added with the next run of the set.
Photon is stronger on POI queries today. The GridPin POI layer is opt-in and young; 49% within 500 m is where it stands, not where it claims to be. We publish this number for the same reason we publish the one above: per-release, on a fixed set.
Throughput, measured and stated with its conditions
How fast, honestly
Single arm64 laptop core, one thread, France sheet, warm mmap. Speed depends entirely on query shape: an exact match is an FST lookup, while a typo is answered by exploring edit-distance variants — hundreds of times more work.
| Query shape | Per core | Median latency |
|---|---|---|
| Exact, short (“10 rue de rivoli paris”) | ~3,000/s | <1 ms |
| Full clean address | ~600/s | <1 ms |
| Reverse (coordinate → address) | ~1,800/s | <1 ms |
| Typo / messy (fuzzy path) | ~10–50/s | ~60 ms |
Fuzzy matching is the slow path, and it is our headline feature — so we say so.
Feed messy input through geocode_many() or the batch command,
which spread work across every core. Making the fuzzy path itself faster is on the roadmap;
until it lands we would rather you size for tens of fuzzy queries per second per core than
be surprised in production.
What we measure, against what truth, and how a competitor qualifies
What we measure, and against what truth
A geocoder benchmark is defined by two choices: what counts as the ground truth, and how messy the queries are. We keep those choices explicit and report two tiers.
Registry-reference sets
Queries: well-formed addresses in two variants — clean, and typo-mangled (character-level corruption of the clean set).
Truth: the national address registry itself — for France, the official BAN registry. A hit means recall@1: the top result is the correct registry record; coordinate error is measured against the registry coordinate.
Answers: does the engine find the right record, and how far off is the pin.
Real messy human queries
Queries: curated live cases from real usage plus internal stress sets — abbreviations, transliteration, missing cities, bare area names.
Truth: mixed by design. Live cases are checked against independently sourced coordinates where available; the rest assert the expected street/commune text. Stress sets gate on the expected street/commune in the top-3 answers — they test behavior, not coordinate accuracy. The share of coordinate-checked cases is reported with each release.
Answers: how the engine behaves on input people actually type. Results are country-dependent; corpora dominated by bare area names are hard for every geocoder, ours included.
Lineage-disclosed comparison
Queries: exactly 300 unique rows for each of France, Italy, the
Netherlands, and Serbia: 50 pinned Overture Places plus 250 direct OSM
address nodes from exact Geofabrik snapshots. Every country has at
least 150 rows in the weakest unknown_lineage class. Each
query has a numbered street, municipality and country, plus a postcode
when the source provides one.
Truth contract: the pinned 2026-06-17.0
theme=places export is separate from the Overture Addresses
export used by several GridPin sheets; the OSM inputs are pinned by
URL, replication point, byte count, and SHA-256. Every coordinate
retains source-specific evidence and must state
same_export_as_indexed_sheet=false. Shared or uncertain
upstream lineage is disclosed, not relabelled as independent.
Answers: GridPin and each selected competitor receive the same composed query. Hit@1 within 300 metres is reported overall, by country, by lineage class, and by country plus lineage. Empty answers are misses.
Smoke test
Queries: 23 live checks against a build of Monaco constructed in CI from a raw OSM extract (engine built-in defaults — no ML sections or rule tables, exercising the fallback path), on every commit.
Truth: expected results pinned from a reviewed build and checked into the public repository.
Answers: that the whole pipeline — build, index, forward, reverse —
works end to end, verifiable by anyone with make smoke.
Reproduce it yourself
Reproduce it yourself
The offline contract does not depend on private sets or network services. It tests the observer and failure modes, not product accuracy. Repeating the pre-release comparison additionally needs the retained schema-v4 truth corpus, the four exact candidate release sheets, and a selected competitor with retained identity evidence and raw responses.
$ git clone https://github.com/gridpin/gridpin $ cd gridpin $ make public-bench-contract
The corpus recipe, supplied-sheet command, license review and exact post-release route are in
docs-public/BENCHMARK.md.
This measurement is bound to local sheet SHA-256 values and embedded
source releases. The clean-clone route is documented in
docs-public/BENCHMARK.md,
and the sheet builds named in the identity table above are the ones
v0.1.0 ships: the four SHA-256 values match byte for byte, so the
published sheets reproduce these numbers exactly.
The existing make smoke target still builds Monaco and runs the
end-to-end engine checks used by CI.
Known gaps and what this page will grow to include
What this page will grow to include
- Resolve the remaining 55 postcode, locality, street and wrong-number mismatches in the 285-case official Alsace numbered-address file; extend in-country reverse coverage (the Photon reverse endpoint is already in place).
- After v0.1.0 publishes the binary, four sheets, and checksums, execute the documented clean-clone reproduction command without local substitutions.
Questions about the methodology: contact@gridpin.dev.
The honest summary: where the answer key is OSM-derived, Photon and Nominatim score above us (by 10.4 and 7.3 points). On the Overture half of the same run the order inverts (we lead by 19.0 and 12.0). On the separate 230-row POI corpus we lead Photon by 10.4 points with statistical significance and Nominatim by 5.2 points without it. Which of those resembles your own addresses is the one thing we cannot measure for you — and the files are free, need no account, and answer it in an afternoon.
Download the free sheets Five-minute start Full measurement record