Nominatim Geocoding Pipelines Jump to heading
A geocoder that returns an answer for every input is not the same as a geocoder that returns the right answer, and Nominatim is honest about the difference in a way that trips up pipelines built on the assumption that geocoding is a lookup. It is a search engine over OpenStreetMap places, it ranks candidates, and every ranking decision it makes is one your pipeline has to either constrain in advance or evaluate afterwards.
The Problem This Topic Solves Jump to heading
You have a column of addresses, place names or coordinates and you need geometry attached to each one. Nominatim answers both directions — forward, from text to a place, and reverse, from a coordinate to the place containing it — over the same OpenStreetMap data your other pipeline stages already use, which makes it uniquely consistent with the rest of your stack.
The failure scenario is worth stating plainly because it is so common. A pipeline geocodes fifty thousand addresses as free text against the public instance, at whatever rate the client manages, with no country constraint. Three things then happen: the source is blocked within the hour for exceeding the usage policy; the results that did arrive include a number of confident matches in the wrong country, because several place names are not unique globally; and none of it is reproducible, because a rerun a month later returns slightly different coordinates as the underlying map improves. Every one of those three is preventable, and all three prevention measures are cheap.
Prerequisites Jump to heading
Read the parent Querying OSM: Overpass, Nominatim & APIs overview for the quota context. Understand OSM address tagging as covered in Tag Taxonomy & Key-Value Standards, because Nominatim’s structured fields map onto the addr:* namespace and its gaps are the same gaps. And be clear about identity — a geocode returns an OSM object reference, and what that reference guarantees over time is the subject of OSM Feature Identity & ID Stability.
The Ranking Model Jump to heading
Three numbers travel with every Nominatim result, and reading them correctly is most of the skill.
Place rank describes how specific the matched feature is, on a scale that runs from a continent at the coarse end to an individual building or address point at the fine end. A result with a place rank corresponding to a city, returned for a query that supplied a house number, tells you the house number was not matched — the geocoder fell back to the containing settlement rather than failing.
Importance is a normalised score used to order otherwise comparable candidates. It derives from the underlying data’s prominence. It is a tie-breaker between places of similar specificity, not a confidence score, and treating it as a probability that the answer is right is a category error.
The address detail object — returned when you ask for it — decomposes the match into house number, road, suburb, city, state, postcode and country. This is the single most useful part of the response for a pipeline, because it lets you assert that the component you cared about actually matched rather than inferring it from a display string.
Structured Queries Beat Free Text Jump to heading
Nominatim accepts a free-text query and does a creditable job of parsing it, but a pipeline almost always knows more about its own data than the parser can infer. Supplying street, city, state, postalcode and country as separate fields removes the guesswork about which token is which, and it makes the failure mode much better: a structured query that cannot match a house number falls back to the street, and you can see that in the returned place rank.
Constraining is equally important. A countrycodes parameter eliminates the entire class of wrong-country matches in one step. A viewbox with bounded mode restricts results to a rectangle. Both cost nothing and both convert a silent correctness problem into an empty result you can handle.
The remaining lever is deduplication before the call. Real address lists repeat heavily, and normalising case, whitespace and punctuation before lookup routinely removes a third of the requests without changing a single result. That is covered in practice in Batch Geocoding with Nominatim Without Getting Blocked, alongside the rate discipline the public instance requires.
Reverse Geocoding and the Zoom Parameter Jump to heading
Reverse geocoding takes a coordinate and returns the place containing it, and its behaviour is governed by a zoom parameter that most integrations leave at the default and then find confusing. Zoom selects the level of the hierarchy you want back: a low value returns a country or state, a middle value returns a city or suburb, and a high value returns a building or address point.
The practical rule is to set zoom from the question, not from the data. “Which country is this point in” and “what is the nearest address to this point” are different questions that happen to share an endpoint, and asking one while expecting the other’s answer is the usual cause of a reverse geocoder that seems to return the wrong level of detail at random.
Validation and Error Handling Jump to heading
| Condition | Root cause | Detection | Remediation |
|---|---|---|---|
| Result in the wrong country | Unconstrained free-text query | address.country_code differs from expectation |
Pass countrycodes, or a bounded viewbox |
| House number missing from the answer | No matching address point exists | place_rank coarser than an address |
Accept the street-level fallback explicitly, or reject |
| Empty result for a valid address | Over-constrained structured query | Zero candidates with all fields supplied | Relax one field at a time, most specific first |
| Different coordinates on a rerun | The underlying map improved | Coordinate drift beyond a few metres | Store the result plus its date; re-resolve on a schedule |
| HTTP 403 or persistent 429 | Missing User-Agent or over one request per second |
Blocked responses from every request | Identify the client, throttle, or self-host |
| Same place returned for many inputs | Inputs normalised too aggressively | Many distinct addresses share one result | Loosen normalisation; keep house numbers distinct |
| Plausible but wrong suburb | Ambiguous name matched a different feature | osm_type is a node where a boundary was expected |
Assert on the returned address components |
Performance, Scale and the Self-Hosting Threshold Jump to heading
The public Nominatim instance permits roughly one request per second from a single source. That is a hard ceiling on throughput, and it means a hundred thousand addresses is somewhere over a day of continuous, polite requesting — which is both slow for you and a poor use of a shared resource.
Three things extend the useful range. Deduplicate before calling, as described above. Cache every result keyed on the normalised query, so reruns are free and your test suite is deterministic. Batch the work into stages so that a failed run resumes from where it stopped rather than starting over.
Past roughly the ten-thousand-lookup mark, the right answer stops being a better client. Importing your own instance from a regional extract removes the rate limit entirely, makes results reproducible until you choose to re-import, and lets you tune the address indexing to your region. It is a real operational commitment — the import is long and the database is large — and Importing Nominatim from an OSM Extract sizes it honestly.
Failure Modes and Gotchas Jump to heading
- The first result is not the answer. It is the highest-ranked candidate. Assert on the returned address components before accepting it.
- Place rank reveals fallback. A city-level rank for a query with a house number means the house number did not match. That is information, and discarding it means storing a city centroid as if it were a building.
- Importance is not confidence. Two results with importance 0.4 and 0.3 are not “57% likely” and “43% likely”; they are simply ordered.
- Accents and abbreviations matter. Normalisation helps, but stripping accents can merge genuinely distinct places. Normalise conservatively and keep the original string.
- Coordinates move. A building’s centroid changes when a mapper traces it more accurately. Store the date alongside every geocode.
- Reverse geocoding without zoom is ambiguous. Set it from the question you are asking, not from the default.
- Postcodes are not universally mapped. In some countries the postcode in a Nominatim result is inferred from a containing area rather than from the feature itself.
Integration Points Jump to heading
Geocoded output feeds two very different consumers. When the result is a coordinate to be stored, it belongs in the same normalized feature table as everything else, and the composite osm_type/osm_id key is what links it back to the map — the same key discussed in Converting Overpass JSON to a GeoDataFrame. When the result is a match between your record and an OSM feature, it is the first step of a conflation workflow, and it should be scored and audited the way OSM Conflation & Data Enrichment describes rather than accepted wholesale.
Upstream, address strings should be cleaned before they reach the geocoder, using the same value-standardisation discipline as any other OSM-adjacent field; Value Standardization & Regex Cleaning covers the techniques.
Guides in This Topic Jump to heading
- Batch Geocoding with Nominatim Without Getting Blocked — deduplication, caching, throttling and resumability for a large address list.
- Importing Nominatim from an OSM Extract — sizing and running a private import, and keeping it current.
- Parsing Nominatim Address Details into Columns — turning the address object into a typed, assertable table.
Frequently Asked Questions Jump to heading
Why does Nominatim return a city when I asked for a street address?
Because no matching address point or road existed, so the geocoder fell back to the most specific containing feature it could match. The returned place rank tells you exactly what level it settled on, which is why it should be read on every result. Storing a city-level fallback as though it were a building coordinate is one of the most damaging silent errors in a geocoding pipeline, and a single assertion on place rank prevents it.
Is the importance score a confidence value?
No. It orders candidates that are otherwise comparable and derives from how prominent a place is in the underlying data, not from how well it matched your query. A high importance on a wrong match is entirely possible and entirely normal — a famous city will outrank an obscure village of the same name regardless of which one you meant. Confidence has to come from asserting that the address components you supplied appear in the result.
How do I stop getting results from the wrong country?
Constrain the query. Passing a country code restriction eliminates the whole class of problem in one parameter, and a bounded view box does the same for a smaller area. Free-text queries without any constraint are asking the geocoder to guess which of several real places sharing a name you meant, and it will guess based on prominence, which has no connection to your intent.
At what volume should I run my own instance?
Somewhere around ten thousand distinct lookups, though the honest trigger is time rather than count. The public instance’s roughly one request per second ceiling means ten thousand lookups is several hours of continuous requesting, at which point a failure halfway through is expensive and reproducibility is impossible. A private import removes the rate limit, makes results stable between re-imports, and turns a slow nightly job into a fast one.
Why do my geocodes drift between runs?
Because the underlying map changed. A building traced more accurately moves its centroid; a point replaced by a polygon changes both the coordinate and the object identifier. That drift is the map improving, not the geocoder being unreliable, but a pipeline that assumes stability will see it as churn. Store the coordinate, the object reference and the resolution date together, and re-resolve deliberately on a schedule you control.
Related Jump to heading
- Querying OSM: Overpass, Nominatim & APIs — the parent section and the shared quota model.
- Matching OSM Features to External Datasets — what to do with a geocode once you treat it as a match rather than a coordinate.
- Value Standardization & Regex Cleaning — cleaning address strings before they reach the geocoder.
- Validating OSM Address Tags Against a Reference — the quality check that pairs naturally with geocoding.
- Tag Taxonomy & Key-Value Standards — the address namespace the structured fields map onto.
- OSM Feature Identity & ID Stability — what a returned object reference does and does not guarantee.
Up one level: Querying OSM: Overpass, Nominatim & APIs.