OpenStreetMap Places Scraper: Geocoding & POI Search avatar

OpenStreetMap Places Scraper: Geocoding & POI Search

Pricing

from $0.74 / 1,000 place scrapeds

Go to Apify Store
OpenStreetMap Places Scraper: Geocoding & POI Search

OpenStreetMap Places Scraper: Geocoding & POI Search

Geocode addresses, reverse-geocode coordinates and harvest points of interest from OpenStreetMap. Address components, bounding boxes and raw OSM tags. No key.

Pricing

from $0.74 / 1,000 place scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 days ago

Last modified

Share

OpenStreetMap Places Scraper: Addresses geocoded, coordinates reverse-geocoded, and every point of interest inside an area you draw

Does three things with the world's open map data: turns addresses into coordinates, turns coordinates back into addresses, and harvests every point of interest inside an area you draw.

It talks to the two OpenStreetMap endpoints built for exactly these jobs over plain HTTP: Nominatim for geocoding, Overpass for bulk area queries. There is no browser, no proxy, no credentials, no account and no per-request billing from a commercial geocoder. Rate limiting is built in, not left to you.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/openstreetmap-places-scraper.md

What you get

FieldWhat it holds
query, queryTypeThe input that produced this row, and whether it was a search, a reverse or a poi lookup
sourcenominatim or overpass, whichever endpoint answered
name, displayNameObject name, and the full human-readable label
latitude, longitudeWGS84 decimal degrees
osmType, osmId, osmUrlThe underlying node, way or relation and a link straight to it on openstreetmap.org
class, typeOSM classification pair, for example amenity / cafe
addressType, placeRank, importanceNominatim's own ranking signals, useful for picking between candidate matches
boundingBox{ south, north, west, east } extent of the object
houseNumber, road, city, state, postcode, country, countryCodeBroken-out address components
extraTagsRaw OSM tags: opening hours, website, phone, wheelchair access, brand, cuisine
placeIdNominatim's internal ID. null for Overpass rows, which have no equivalent
scrapedAtRun timestamp

RUN_SUMMARY in the key-value store holds per-run counts, the filters you used, and any query that failed.

Use cases

  • Bulk address geocoding. Put a customer address list in, get coordinates and standardised components out.
  • Address validation. Compare what you hold against displayName and the broken-out components.
  • Store locators and competitor mapping. Sweep a city bounding box for shop=supermarket or amenity=fuel.
  • Reverse geocoding telemetry. Turn GPS traces into street, city and postcode.
  • Enriching a places database. Pull opening hours, phone and website from extraTags.

Quick start

Geocode a few addresses:

{
"queries": ["Brandenburg Gate, Berlin", "10 Downing Street, London"],
"contactEmail": "you@example.com"
}

Reverse-geocode coordinates and break out the components:

{
"coordinates": ["48.8584,2.2945", "52.5163,13.3777"],
"includeAddressDetails": true,
"contactEmail": "you@example.com"
}

Every cafe and bakery in central Berlin, with opening hours and phone numbers:

{
"poiTags": ["amenity=cafe", "shop=bakery"],
"areaBoundingBox": { "south": 52.50, "west": 13.36, "north": 52.53, "east": 13.42 },
"includeExtraTags": true,
"maxResults": 2000,
"contactEmail": "you@example.com"
}

Input

FieldTypeDefaultNotes
queriesarray[]Free-text addresses or place names. Sent to Nominatim /search.
coordinatesarray[]"lat,lon" strings. Sent to Nominatim /reverse. An unparseable pair fails the run immediately rather than silently dropping a row.
poiTagsarray[]Tag filters like amenity=cafe, or a bare key like amenity to match any value. Sent to Overpass. Requires areaBoundingBox.
areaBoundingBoxobjectnone{ south, west, north, east } in degrees. Only read when poiTags is set.
countryCodesarray[]Two-letter ISO codes restricting forward geocoding. Ignored for reverse and POI lookups.
includeAddressDetailsbooleantrueBreak out house number, road, city, state, postcode and country.
includeExtraTagsbooleanfalseAttach raw OSM tags. Always present on POI rows regardless.
resultsPerQueryinteger1Candidate matches kept per forward-geocoding query. Nominatim's own ceiling is 40.
maxResultsinteger1000Cap on total places saved across the whole run.
contactEmailstringnoneGoes into the User-Agent. Strongly recommended, for the reasons below.

You can combine all three modes in one run. Results are de-duplicated on osmType and osmId, so a place found by both a geocode and a POI sweep is saved once.

Output example

{
"query": "Brandenburg Gate, Berlin",
"queryType": "search",
"source": "nominatim",
"placeId": 143634177,
"name": "Brandenburger Tor",
"displayName": "Brandenburger Tor, 1, Pariser Platz, Friedrich-Wilhelm-Stadt, Mitte, Berlin, 10117, Deutschland",
"latitude": 52.5162699,
"longitude": 13.3777034,
"osmType": "way",
"osmId": 518071791,
"osmUrl": "https://www.openstreetmap.org/way/518071791",
"class": "building",
"type": "gate",
"addressType": "building",
"placeRank": 30,
"importance": 0.5504719991549523,
"boundingBox": { "south": 52.516117, "north": 52.5164328, "west": 13.3775798, "east": 13.3778251 },
"houseNumber": "1",
"road": "Pariser Platz",
"city": "Berlin",
"state": null,
"postcode": "10117",
"country": "Deutschland",
"countryCode": "de",
"extraTags": {
"height": "26",
"tourism": "attraction",
"historic": "monument",
"wheelchair": "yes",
"opening_hours": "24/7",
"wikidata": "Q82425"
},
"scrapedAt": "2026-08-06T12:00:00.000Z"
}

Country and city names come back in the local language: Deutschland, not Germany. countryCode is the stable field to key on.

Nominatim versus Overpass

The two endpoints answer different questions, and using the wrong one is how people get blocked:

You wantEndpointInput to use
An address turned into coordinatesNominatim /searchqueries
Coordinates turned into an addressNominatim /reversecoordinates
Every object of a given kind in an areaOverpasspoiTags plus areaBoundingBox

Nominatim's usage policy allows one request per second and explicitly asks that systematic and bulk queries go to Overpass instead. This Actor enforces the one-second gap in code, sends an identifying User-Agent on every request, and routes area sweeps to Overpass automatically. You do not have to remember any of that.

Overpass has no fixed per-second rate. It allocates query slots and will answer 429 or 504 when it is busy. Those are retried three times with linear backoff, and a 504 on the first attempt is normal for a large box and usually succeeds on the second.

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~openstreetmap-places-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"queries": ["Brandenburg Gate, Berlin"],
"includeAddressDetails": true,
"contactEmail": "you@example.com"
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/openstreetmap-places-scraper').call({
poiTags: ['amenity=cafe'],
areaBoundingBox: { south: 52.5, west: 13.36, north: 52.53, east: 13.42 },
includeExtraTags: true,
maxResults: 500,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const place of items) {
console.log(`${place.name ?? '(unnamed)'} at ${place.latitude}, ${place.longitude} (${place.extraTags.opening_hours ?? 'hours unknown'})`);
}

Notes

  • Nominatim gets one request per second, always. The gap is applied after every call including failed ones, so a run cannot burst past the policy even when queries are erroring.
  • A contactEmail is not decoration. OpenStreetMap uses the User-Agent to reach heavy users before blocking them, and without one you are anonymous traffic, which gets throttled first. The Actor logs a warning when it is missing.
  • Ways and relations get a centroid. Overpass returns no coordinates for non-node objects, so the query asks for out center and the centroid lands in latitude and longitude. boundingBox is null for POI rows because centroids carry no extent.
  • Overpass errors arrive as HTML. A malformed tag or a timeout produces an HTML page rather than JSON, so the Actor digs the real message out of the markup and reports it instead of throwing a parse error.
  • One bad query won't kill the run. Failures land in RUN_SUMMARY.failures, and the Actor only errors out if every query fails.
  • Public data only. OpenStreetMap data is published under the ODbL, and the attribution "© OpenStreetMap contributors" is required if you publish anything derived from it.

FAQ

Do I need an API key? No. You supply no credentials.

How fast can I geocode a list? One address per second, by policy. Ten thousand addresses is a little under three hours. If you need it faster, run your own Nominatim instance, because the public one is a volunteer service.

Why did my POI sweep return nothing? Either the box is empty, or the tag is wrong. Check the tag on the OpenStreetMap wiki: it is shop=supermarket, not amenity=supermarket.

Why did Overpass time out? The box was too large for the tag. Split it into quadrants and run them as separate queries, because a city-wide amenity=restaurant sweep is a lot of geometry.

Can I get opening hours and phone numbers? Yes, in extraTags, when mappers have recorded them. Coverage varies enormously by country and by category.

Can I use this commercially? Yes, under the ODbL: attribute OpenStreetMap and share alike if you redistribute a derived database. Read the licence before you build a product on it.