Nominatim: “Access blocked”, 403 and 429
Why nominatim.openstreetmap.org blocks a script or an app, what its usage policy allows, how to send requests it accepts, and what to do when one request a second is not enough.
Why the public Nominatim blocks requests
Nominatim is the search engine of openstreetmap.org. The public server is run by the OpenStreetMap Foundation on donated hardware and shared by everyone, so its usage policy sets firm limits:
- An absolute maximum of one request per second, from all your users together.
- A valid HTTP Referer or User-Agent that identifies the application. The default User-Agent of an HTTP library does not count.
- Results must be cached on your side. Clients that send the same query again and again may be treated as faulty and blocked.
- No autocomplete, not even from the browser of your users.
- Bulk geocoding of larger amounts of data is discouraged. Scripts that run longer than a day, or at regular intervals, are held to 4 requests a minute.
- Show the OpenStreetMap attribution where the results appear.
A client that breaks these rules gets HTTP 403 with a page titled “Access blocked”. It says the client violated the usage policy, asks you to check that your software sends a custom Referer or User-Agent and no massive bulk requests, and gives nominatim@openstreetmap.org as the contact if the block seems wrong or stays after a fix. Too many requests in a short time can also bring 429 Too Many Requests.
Send a User-Agent that names your app
A missing or generic User-Agent is the most common reason for a block. Name the app and a way to reach you:
curl -A 'shop-locator/1.2 (admin@example.com)' \ 'https://nominatim.openstreetmap.org/search?q=Bundesplatz+3,+Bern&format=jsonv2'
import requests
s = requests.Session()
s.headers["User-Agent"] = "shop-locator/1.2 (admin@example.com)"
r = s.get("https://nominatim.openstreetmap.org/search",
params={"q": "Bundesplatz 3, Bern", "format": "jsonv2"}, timeout=10)
r.raise_for_status()
print(r.json()[0]["display_name"])
const res = await fetch(
"https://nominatim.openstreetmap.org/search?" + new URLSearchParams({ q: "Bundesplatz 3, Bern", format: "jsonv2" }),
{ headers: { "User-Agent": "shop-locator/1.2 (admin@example.com)" } },
);
if (!res.ok) throw new Error(`Nominatim answered ${res.status}`);
console.log((await res.json())[0].display_name);
In a web page the browser sends the Referer of the page, which identifies your site, and does not let you set the User-Agent. Make sure the page does not send Referrer-Policy: no-referrer.
Stay below one request a second, and cache
- Send requests one after the other, from one thread, with at least one second between them. Several workers that each wait one second still break the limit together.
- Keep every answer you got, keyed by the query, and look there first. For a list of addresses, remove duplicates before geocoding.
- After a 429 or 403, stop the run. Retrying at once makes a block longer.
import time # s: the requests.Session with the User-Agent from above def geocode_all(addresses): seen = {} for a in dict.fromkeys(addresses): # each address once, in order r = s.get("https://nominatim.openstreetmap.org/search", params={"q": a, "format": "jsonv2", "limit": 1}, timeout=10) r.raise_for_status() # stops at 403 or 429 seen[a] = r.json()[:1] time.sleep(1.1) return seen
509 Bandwidth Limit Exceeded
In February 2026 the public Nominatim came under extreme load from anonymous scrapers spread across more than 100,000 IP addresses. While the operations team fought them off, some normal clients got 509 for a few days. The maintainers asked users to retry before reporting it, and advised commercial apps to use a commercial geocoding service or a server of their own (forum thread).
geopy and other libraries
geopy refuses to use the public Nominatim with its default or a sample user_agent and raises ConfigurationError; a 403 becomes GeocoderInsufficientPrivileges and a 429 GeocoderRateLimited. See geopy: GeocoderInsufficientPrivileges, GeocoderRateLimited and ConfigurationError.
When one request a second is not enough
The policy points to two ways out: a commercial service, several of which are listed on the Nominatim page of the OpenStreetMap wiki, or a Nominatim of your own. A server of your own for the whole world needs about 1 TB of fast disk and 64–128 GB of RAM, and the first import takes two to three days. For one country it is much less.
overpass.ch answers the Nominatim search and reverse requests with the same parameters and fields, so code written for the public server needs only another base URL and a key:
# before https://nominatim.openstreetmap.org/search?q=Bundesplatz+3,+Bern&format=jsonv2 # after https://api.overpass.ch/v1/YOUR_KEY/nominatim/search?q=Bundesplatz+3,+Bern&format=jsonv2
Search as you type works there too, through the Photon API on the same data. The differences from Nominatim are listed in the documentation.
Geocoding from overpass.ch
The Nominatim and Photon APIs on OpenStreetMap data, without the one-request-a-second limit. 100'000 requests a month are free, and you may store the results.