Quick answer
OpenStreetMap's Overpass API is free and keyless, but its public instances are shared, load-shed, and will hand you a 429 or 504 the moment your query gets greedy — which is why a "just curl it" script tends to work for the first ten businesses and then quietly stall. The OSM POI Scraper takes a place name or bounding box plus a business category (dentist, restaurant, gym, hotel, car repair, pharmacy, EV charging, supermarket, cafe) and returns name, address, phone, website, email, opening hours and coordinates as flat rows, at $5.05 per 1,000 results.
The two things that break a naive Overpass client 🧱
A shared public API means someone else's query is eating your timeout. Overpass instances don't rate-limit you personally — they load-shed everyone equally when the shared query queue backs up, and a busy instance returns 429 or a 504 on a query that would have succeeded five minutes earlier. A script that treats either as fatal loses the whole run over a transient load spike that had nothing to do with the query itself. This Actor retries 429/504 specifically — up to 5 attempts with exponential backoff, honoring Retry-After when Overpass sends one — while treating any other 4xx (a malformed query, for instance) as the real failure it is and surfacing it immediately instead of retrying blind. It also self-throttles to at least one second between outbound requests, so it isn't the query contributing to the next instance's overload, and falls back to a second Overpass mirror if the primary exhausts its retries.
Only node elements carry coordinates directly. OpenStreetMap represents a business as a node (a point), a way (an outline — a building footprint), or a relation (a multi-part outline, like a shopping mall). A dentist mapped as a building outline instead of a point has no lat/lon fields at all — the coordinates live under a center object that Overpass only computes if you ask for it with out center instead of the default out. A query written against out; and reading element.lat will silently return null coordinates for every way and relation, which for building-outline POIs can be a meaningful chunk of the result set. This Actor queries all three element kinds with out center, and the parser reads element.lat/element.lon for nodes and falls back to element.center.lat/element.center.lon for ways and relations.
The judgement call: one malformed element skips itself, not the run 🔍
Overpass's response is a flat elements array with no natural retry boundary — there's no "page 4 failed" the way a paginated REST API gives you. If element index 340 out of 2,000 is missing an id, or has neither lat nor a usable center, a parser that isn't defensive about it either crashes the whole run or writes a row full of nulls that looks like real data.
This Actor checks every element for a valid id, a recognized type (node/way/relation), and resolvable coordinates before it becomes a row. Anything that fails the check is logged and skipped — you keep the other 1,999 rows instead of losing the batch to one bad element, and you don't get a row silently claiming a business exists at coordinates null, null.
What you get per row
Business name, category (echoed from your input), street, house number, city, postcode, country, phone (falls back to contact:phone when the bare tag is missing), website (same fallback pattern), email (same), opening hours, latitude and longitude, plus the OpenStreetMap osm_id, osm_type, and a direct osm_link back to the source element for verification.
Point it at a place name (resolved to a bounding box via Nominatim) or hand it an explicit [south, west, north, east] bbox directly. There's also a rawOverpassQuery escape hatch for anyone who wants to write their own Overpass QL and skip the category translation entirely.
What it costs
Pay-per-event: a $0.05 warm-up fee per run plus $0.005 per POI row that lands in your dataset. A thousand POIs works out to $5.05. No subscription, no minimum, no API key to request, and Apify hands every new account $5 of free credit to try it before paying anything.
Where it fits
Local lead generation — a category, a city, and a dial-ready list. Franchise siting — mapping competitor and complementary-business density before committing to a location. Field-sales territory planning — addresses and coordinates ready for route mapping. Market research — counting and profiling businesses by category across regions without touching a commercial maps API.
Top comments (0)