# Local Business & POI Extractor (`mina_safwat/osm-poi-scraper`) Actor

Extracts local businesses and points of interest from OpenStreetMap — names, addresses, phones, websites, and opening hours

- **URL**: https://apify.com/mina_safwat/osm-poi-scraper.md
- **Developed by:** [Mina](https://apify.com/mina_safwat) (community)
- **Categories:** Lead generation, Business, Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Extract **local businesses and points of interest** for any area — names, addresses, phone numbers, websites, and opening hours — from OpenStreetMap.

### What does Local Business & POI Extractor do?

Name an area and pick what you are looking for — restaurants, shops, hotels, pharmacies, gyms, clinics, and 20 more categories — and it returns every matching place mapped in that area, with the contact details attached to each one.

Because it reads OpenStreetMap, the data is open, there is nothing to bypass, and you can pull a whole city in one run.

### Why use Local Business & POI Extractor?

- **Lead generation** — build a list of every restaurant or salon in a city, with phone numbers and websites.
- **Market and site analysis** — count competitors in a neighbourhood before opening somewhere.
- **Map and directory building** — populate your own listings from open data.
- **Delivery and logistics** — enumerate the venues in a service area with coordinates.
- **Research** — measure amenity density across districts.

Running it on Apify adds scheduling, an API, integrations (Sheets, Slack, Zapier, S3), and run monitoring.

### How to use Local Business & POI Extractor

1. Type a **Location** — a city, district, or neighbourhood.
2. Pick one or more **Categories**.
3. Set **Max results** and click **Start**.

To search a circle instead, give a **latitude**, **longitude**, and **radius** rather than a location.

Results appear in the Output tab as they arrive, and download as JSON, CSV, Excel, or XML.

### Input

| Field | Description |
| --- | --- |
| `location` | Area to search. Add the city or country for anywhere ambiguous. |
| `categories` | What to look for — 22 categories from restaurants to places of worship. |
| `custom_tags` | Any OpenStreetMap tag as `key=value`, e.g. `amenity=cinema`, for anything not in the list. |
| `max_results` | Stops after this many places. |
| `named_only` | Skip unnamed entries such as anonymous parking spaces. On by default. |
| `latitude` + `longitude` + `radius_meters` | Search a circle instead of a named area. |

### Output

```json
{
  "osm_id": 123456,
  "osm_type": "node",
  "osm_url": "https://www.openstreetmap.org/node/123456",
  "name": "Blue Door Cafe",
  "category": "amenity",
  "category_value": "cafe",
  "address": "12 Old Street, EC1V 9BE, London",
  "street": "Old Street",
  "city": "London",
  "postcode": "EC1V 9BE",
  "phone": "+44 20 1234 5678",
  "website": "https://bluedoor.example",
  "opening_hours": "Mo-Fr 07:00-18:00",
  "cuisine": "coffee_shop",
  "wheelchair": "yes",
  "latitude": 51.523,
  "longitude": -0.078
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

Data © [OpenStreetMap contributors](https://www.openstreetmap.org/copyright), available under the [Open Database License (ODbL)](https://opendatacommons.org/licenses/odbl/).

#### Data fields

| Field | Description |
| --- | --- |
| `name`, `name_english`, `brand`, `operator` | What the place is called and who runs it. |
| `category`, `category_value` | What kind of place it is. |
| `address`, `street`, `housenumber`, `city`, `postcode`, `country` | Address, as separate parts and as one line. |
| `latitude`, `longitude` | Exact position. |
| `phone`, `website`, `email`, `facebook`, `instagram` | Contact details, where mapped. |
| `opening_hours` | Opening times in OpenStreetMap's compact format, e.g. `Mo-Fr 07:00-18:00`. |
| `cuisine`, `takeaway`, `delivery`, `outdoor_seating`, `internet_access`, `wheelchair`, `stars` | Details for food, hospitality, and accessibility. |
| `osm_id`, `osm_type`, `osm_url` | The OpenStreetMap entry, so you can check or correct it. |
| `all_tags` | Every tag on the entry, for anything the fields above do not cover. |

### How much does it cost to extract POIs?

You pay a small fee per place returned, plus a tiny start fee per run — see the Pricing tab for the current prices. **Max results** caps how many places, and so how much, a run can cost. You can also set a maximum cost per run; the Actor stops cleanly when it is reached.

Searches that find nothing add no rows, so they cost only the start fee.

### Tips

- **Districts beat whole cities** if you want completeness — several neighbourhood runs return more than one huge query that times out.
- **A named area is searched as a rectangle** — the place's bounding box — so a few results can lie just outside its official boundary. Use latitude, longitude and a radius for an exact circle.
- **Contact details are patchy by nature.** OpenStreetMap is volunteer-maintained, so some places have a phone and website and others only a name. The run's status message tells you how many of your results carry contact details.
- **Combine categories** in one run — restaurants plus cafés plus fast food gives you the whole food scene at once.
- **Use custom tags** for anything niche: `shop=bakery`, `amenity=cinema`, `craft=brewery`.

### FAQ and support

**Where does the data come from?** OpenStreetMap, the open map database maintained by volunteers.

**Is the data complete?** It varies by place. Cities are usually mapped thoroughly; rural areas less so. It is strong on what exists and where, and patchier on phone numbers and opening hours.

**Why did my search return nothing?** Either the area name was not recognised, or nothing of that category is mapped there. The run's status message says which, and any input that could not be used is listed with the reason in the `FAILED_INPUTS` record of the run's key-value store. Try adding the country to the location, widening the category, or turning off "Named places only".

**Why did my run fail?** OpenStreetMap's query service is free and shared, and turns requests away when it is busy. The Actor retries across two public servers for up to about five minutes. If neither answers, or the search is too big to finish, the run fails with a message saying so instead of returning an empty result. Run it again in a few minutes, or try a smaller area.

**Can I use this data commercially?** Yes — OpenStreetMap data is open under the [Open Database License (ODbL)](https://opendatacommons.org/licenses/odbl/). You must credit it as "© OpenStreetMap contributors", and if you publish a derived database you must share it under the same licence. See [OpenStreetMap's copyright page](https://www.openstreetmap.org/copyright) for the details.

Found a bug or want a field that is missing? Open an issue on the Actor's Issues tab.

# Actor input Schema

## `location` (type: `string`):

Area to search — a city, district, or neighbourhood. Add the country or city for anywhere ambiguous, e.g. "Shoreditch, London".

## `categories` (type: `array`):

What kind of places to find. Pick several to combine them in one run.

## `custom_tags` (type: `array`):

Any OpenStreetMap tag as "key=value", e.g. "amenity=cinema" or "shop=bakery". Use this for anything not in the category list.

## `max_results` (type: `integer`):

Stops after this many places.

## `named_only` (type: `boolean`):

Skip entries with no name — things like unnamed parking spaces and benches. Turn off to get everything mapped.

## `latitude` (type: `string`):

Use latitude, longitude and a radius to search a circle instead of a named area. Overrides Location.

## `longitude` (type: `string`):

Longitude of the circle centre.

## `radius_meters` (type: `integer`):

How far around that point to search.

## Actor input object example

```json
{
  "location": "Shoreditch, London",
  "categories": [
    "Restaurants"
  ],
  "custom_tags": [],
  "max_results": 100,
  "named_only": true
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "location": "Shoreditch, London",
    "max_results": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/osm-poi-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "location": "Shoreditch, London",
    "max_results": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/osm-poi-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "location": "Shoreditch, London",
  "max_results": 100
}' |
apify call mina_safwat/osm-poi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mina_safwat/osm-poi-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jaLthePpHvdPtvWef/builds/qq9Am70mFcBEtXPPo/openapi.json
