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.

What you get
No query leaves the machine. The engine makes no network calls while geocoding, so there is nothing for us to receive or log.
No quota, no per-request fee. A flat file answers a thousand queries or a billion at the same price.
No server, no import, no warm-up. The sheet is memory-mapped; the process opens it and answers.
Three ways in. One self-contained CLI binary, a Python wheel, a DuckDB extension — and batch mode for bulk work.
Speed you can plan around. ~3,000 exact lookups per second on a single arm64 core; typo-tolerant fuzzy matching is much slower, tens of ms per query.
Provenance travels with the data. gridpin meta france.bin prints the source, licence and attribution fields of the sheet; redistribution is governed by that source licence.
How it compares

Three ways to geocode, and what each costs you

What it costs youGridPinTypical hosted geocoding APISelf-hosted OSM stack
Where your query text goesstays on your machineto the providerstays on your infrastructure
Getting startedinstall the engine, download one country sheetsign up, usually get a keyimport a database, tune it
Running itno service or database to operate; the CLI or library memory-maps the sheetnothing of yours to operateyou keep the database alive and current
Cost per extra queryno vendor fee; the compute is yoursusually metered or plan-limitedno vendor fee; the compute is yours
InterfacesCLI, Python, DuckDBHTTPHTTP
Coverage todayFrance, Italy, the Netherlands, Serbiaworldwideworldwide

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.

Accuracy, without cherry-picking

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
Results

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 / Geofabriksame_dataset_family for both competitors: they search OSM-derived data 1,00086.900%97.300%94.200%
Overture Places — relationship to all three engines unknown, which is not a proof of independence 20078.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.

Enginehit@1 ≤300 m95% Wilson CIvs GridPinexact McNemar
GridPin60.870%
140 / 230
54.4–66.9
Nominatim55.652%
128 / 230
49.2–61.9−5.217 ppp = 0.0652
Photon50.435%
116 / 230
44.0–56.8−10.435 ppp = 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
France85.333%
256 / 300
91.333%
274 / 300
87.000%
261 / 300
Italy72.667%
218 / 300
89.667%
269 / 300
83.000%
249 / 300
Netherlands96.667%
290 / 300
97.333%
292 / 300
97.333%
292 / 300
Serbia87.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

CountrySheet SHA-256source_release
FRf7278398c1a63308ea3dc69e5cda2f779250716fc231b2122d6ee890da2378392026-06-12
IT37346d884e551189e91f0453d4aad7aafe211430e62b1e9054141081488b021c2026-06-17.0
NLd5205f8e323eeda309f3d411a3efcd45c259005d2da25fef33998bf9ca9d28e72026-06-17.0
RS9e358bd6a940b290e01cd52081e476e2799513f16dd934dc6a5bc89ba4fb53882026-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
Franceoutside_chain · 2792.593%74.074%74.074%
Francecommon_upstream · 0
Franceunknown_lineage · 27384.615%93.040%88.278%
Italyoutside_chain · 520.000%40.000%40.000%
Italycommon_upstream · 0
Italyunknown_lineage · 29573.559%90.508%83.729%
Netherlandsoutside_chain · 1100.000%100.000%100.000%
Netherlandscommon_upstream · 0
Netherlandsunknown_lineage · 29996.656%97.324%97.324%
Serbiaoutside_chain · 3979.487%33.333%69.231%
Serbiacommon_upstream · 0
Serbiaunknown_lineage · 26188.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.

ProbeObserved resultWhat 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
Throughput

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 shapePer coreMedian 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
Methodology

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.

Tier 1

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.

Tier 2

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.

Public

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.

Public

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.

Why the Tier 1 and Tier 2 sets are private. If the test set is public, it is only a matter of time before releases are tuned — deliberately or not — to the test rather than to reality. Keeping the sets closed and the methodology open means the internal numbers stay useful across releases. The lineage-disclosed benchmark and public smoke test provide two checks that do not require access to those sets.
Reproduce it yourself
Reproduce

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.

terminal
$ 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
Coming next

What this page will grow to include

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.