# Places Finder: Overture + OpenStreetMap (Open Data) (`utility-belt-labs/places-finder-open-data`) Actor

Find places (cafes, restaurants, shops) by category and city, merging Overture Maps and OpenStreetMap open data.

- **URL**: https://apify.com/utility-belt-labs/places-finder-open-data.md
- **Developed by:** [Utility Belt Labs](https://apify.com/utility-belt-labs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## Places Finder: Open Data (Overture Maps + OpenStreetMap)

**Find businesses and places by category and city, using only open, legally licensed data.** Give it a category (restaurant, dentist, plumber, cafe...) and a city, bounding box or radius. It returns name, category, address, coordinates, phone, website and email *when an open source lists them*, plus the **source, license, attribution and source ID of every row**.

No Google, no Apple, no scraping of any website, no API key, no proxy. Data comes from:

- **Overture Maps Places**, read directly from Overture's public GeoParquet files on S3 with DuckDB (license: CDLA-Permissive-2.0; some contributing datasets are Apache-2.0 or CC0).
- **OpenStreetMap**, through the public Overpass API (license: ODbL 1.0; the Actor sends a descriptive User-Agent, makes one query per run and backs off when the server is busy).
- **Nominatim** (OpenStreetMap) to turn a place name into an area: one request per run.

### What is different about this Actor

- **Both sources in one run, merged.** The same cafe often exists in both datasets with different gaps (one has the phone, the other the opening hours). Matching places (similar name within about 120 m) become one row with missing fields filled in; the row says which fields came from where (`filledFromOtherSource`) and lists every source ID.
- **License and attribution on every row**, not just in the README. Pick `dataSource: overture` if you need to avoid ODbL share-alike data.
- **Real city boundaries.** A named city is searched inside its actual boundary polygon, not a loose rectangle, so "Boston" does not return half of Cambridge.
- **Survives Overpass outages.** The public Overpass server is often at capacity. The Actor retries with backoff, tries public mirrors, and if OpenStreetMap stays unavailable it still returns the Overture results with a warning.
- Plain-word categories (about 70 built in, with synonyms) that work in both datasets, plus raw OSM tags / Overture categories for anything else.

### Input

| Field | What it does |
|---|---|
| `category` | Plain word: `restaurant`, `cafe`, `dentist`, `plumber`, `electrician`, `lawyer`, `pharmacy`, `hair salon`, `gym`, `hotel`, `car repair`... Unknown words are tried as raw OSM tag values / Overture categories. |
| `location` | City, town or district, e.g. `Boston, Massachusetts, USA`. |
| `boundingBox` | `{south, west, north, east}` in degrees. Overrides `location`. |
| `latitude`, `longitude`, `radiusMeters` | Circle search. With `location` plus `radiusMeters`, the circle is centred on the place. |
| `maxResults` | Default 50, up to 1000. |
| `dataSource` | `both` (default), `overture`, or `osm`. |
| `mergeDuplicates` | Merge the same place found in both sources (default on). |
| `onlyWithPhone`, `onlyWithWebsite`, `onlyWithEmail` | Drop rows where no open source has that field. |
| `sortBy` | Which places to keep when there are more than `maxResults`: most complete contact data first (default) or name A-Z. |
| `minOvertureConfidence` | Overture's 0-1 score that a place exists (default 0.5). It is **not** a quality rating. |
| `osmTags`, `overtureCategories`, `overtureRelease` | Advanced: extra filters like `craft=plumber` / `plumbing`, and pinning an Overture release. |

The search area is limited to about 2 square degrees (a large metro area). This is a city/district tool, not a country-wide extractor.

### Output

```json
{
  "name": "Bonne Chance Cafe",
  "category": "cafe",
  "categoryRaw": "cafe | amenity=cafe",
  "address": "77 Canal St, Boston, MA 02114",
  "latitude": 42.3642025,
  "longitude": -71.0596237,
  "phone": "+16177423115",
  "website": "http://www.bonnechancecafe77.com/",
  "email": "bonnechancecafe77@gmail.com",
  "source": "overture+openstreetmap",
  "license": "CDLA-Permissive-2.0 + ODbL-1.0",
  "attribution": "Overture Maps Foundation, overturemaps.org; ...; © OpenStreetMap contributors, ODbL 1.0 (https://www.openstreetmap.org/copyright)",
  "sourceId": "overture:dee1c7a7-9e94-4207-a724-7e9280b03ce0",
  "sourceIds": ["overture:dee1c7a7-9e94-4207-a724-7e9280b03ce0", "osm:node/4840220309"],
  "sourceUrl": "https://www.openstreetmap.org/node/4840220309",
  "retrievedAt": "2026-10-26T02:42:01Z"
}
```

See `sample-output.json` for real rows. Other fields: `street`, `city`, `region`, `postcode`, `country`, `openingHours` (OSM only), `overtureConfidence`, `contributingDatasets`, `filledFromOtherSource`, `searchArea`. The **Places** view in the Output tab shows the main columns; export as JSON, CSV or Excel. A run summary (search area, Overture release, candidate counts, warnings, attribution text) is stored in the key-value store under `SUMMARY`.

### Honest limits

- **No reviews, no ratings, no photos, no popularity data.** Open data does not have them. `overtureConfidence` only says how likely the place exists.
- **Coverage varies a lot by region.** Overture is strongest in North America and Western Europe; OpenStreetMap is strongest where volunteers are active. Phone, website and especially **email are often missing** (email is rare). Some places are closed or out of date. Always verify before you pitch or ship anything.
- **Category matching is approximate.** Overture and OpenStreetMap classify things differently, and the built-in words are a convenience mapping, not a perfect one.
- **Result caps.** The Actor fetches a limited number of candidates per source before ranking (at least 200, five times `maxResults`, at most 5000). In dense areas with a small `maxResults`, you may not see every match; a warning appears in `SUMMARY`. OpenStreetMap candidates beyond the cap are chosen by the Overpass server, not ranked.
- **Overpass is a shared community service** and can be busy; a run may take a few minutes when it is. Please do not schedule it hundreds of times per hour.

### Licenses and attribution (please read)

- Rows with `source` **overture**: CDLA-Permissive-2.0 (Overture Maps Foundation). Credit "Overture Maps Foundation, overturemaps.org". Some contributing datasets (e.g. Foursquare, Apache-2.0) carry their own notices; see https://docs.overturemaps.org/attribution/.
- Rows with `source` containing **openstreetmap**: © OpenStreetMap contributors, **ODbL 1.0**. You must attribute OpenStreetMap, and if you build and publish a database from the data, ODbL share-alike applies to it. Merged rows contain OSM data and are treated as ODbL-derived. If that does not suit you, use `dataSource: overture`.
- This Actor does not give legal advice; check the licenses for your use case. It is not affiliated with Overture Maps Foundation or the OpenStreetMap Foundation.
- Contact data (phones, emails) in open datasets can be personal data for some sole traders. Follow the marketing, privacy and anti-spam rules (GDPR, CAN-SPAM, TCPA...) that apply to you.

### Use cases

Local lead lists, market and competitor mapping, store-locator and GIS enrichment, "who offers X in this town" lookups for AI agents (call it through the Apify MCP server), and research where license clarity matters.

# Actor input Schema

## `category` (type: `string`):

What to look for, in plain words: restaurant, cafe, dentist, plumber, electrician, lawyer, pharmacy, hair salon, gym, hotel, car repair... About 70 words are built in (with common synonyms like 'coffee shop' or 'attorney'). Any other word is tried as a raw OpenStreetMap tag value and Overture category.

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

A city, town or district, e.g. 'Boston, Massachusetts, USA' or 'Kreuzberg, Berlin'. Looked up once with OpenStreetMap Nominatim; results are limited to the place's real boundary. Ignored if a bounding box or latitude/longitude is given. Add a radius to search a circle around the place's centre instead of its whole area.

## `boundingBox` (type: `object`):

Search a rectangle instead of a named place: {"south": 42.35, "west": -71.08, "north": 42.37, "east": -71.05}. Decimal degrees. Maximum about 2 square degrees (a large metro area).

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

Centre of a radius search, e.g. 42.3601. Use together with Longitude and Radius.

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

Centre of a radius search, e.g. -71.0589.

## `radiusMeters` (type: `integer`):

Search a circle of this radius around the latitude/longitude, or around the centre of the named place. Leave empty to search the whole named place or bounding box.

## `maxResults` (type: `integer`):

Upper limit on places returned.

## `dataSource` (type: `string`):

Both gives the most complete rows. Choose Overture only if you need to avoid ODbL share-alike data, or OpenStreetMap only if you need OSM tags and the opening hours.

## `mergeDuplicates` (type: `boolean`):

When the same place appears in both Overture and OpenStreetMap (similar name within about 120 m), return one row with missing fields filled in from the other source. Each row lists every source ID and license that contributed.

## `onlyWithPhone` (type: `boolean`):

Drop places where no open source lists a phone number.

## `onlyWithWebsite` (type: `boolean`):

Drop places where no open source lists a website.

## `onlyWithEmail` (type: `boolean`):

Drop places where no open source lists an email address. Emails are rare in open data.

## `sortBy` (type: `string`):

Which places to keep when there are more matches than Max results.

## `minOvertureConfidence` (type: `string`):

Overture's own 0-1 score that a place exists (not a rating). Lower values include more closed or doubtful places.

## `osmTags` (type: `array`):

Additional OpenStreetMap filters as key=value, e.g. shop=bakery or craft=plumber. Added to the category.

## `overtureCategories` (type: `array`):

Additional Overture taxonomy names, e.g. plumbing, dental_clinic, pizza_restaurant. A name also matches its subcategories.

## `overtureRelease` (type: `string`):

Pin a release such as 2026-10-21.0 for repeatable results. Leave empty to use the latest release.

## Actor input object example

```json
{
  "category": "cafe",
  "location": "Boston, Massachusetts, USA",
  "maxResults": 50,
  "dataSource": "both",
  "mergeDuplicates": true,
  "onlyWithPhone": false,
  "onlyWithWebsite": false,
  "onlyWithEmail": false,
  "sortBy": "completeness",
  "minOvertureConfidence": "0.5"
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset of places: name, category, address, coordinates, phone, website, email (when present in open data), source, license, attribution and source ID.

## `summary` (type: `string`):

Search area, Overture release used, candidate counts, warnings and the attribution text to keep with the data.

# 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 = {
    "category": "cafe",
    "location": "Boston, Massachusetts, USA",
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("utility-belt-labs/places-finder-open-data").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 = {
    "category": "cafe",
    "location": "Boston, Massachusetts, USA",
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("utility-belt-labs/places-finder-open-data").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 '{
  "category": "cafe",
  "location": "Boston, Massachusetts, USA",
  "maxResults": 50
}' |
apify call utility-belt-labs/places-finder-open-data --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,utility-belt-labs/places-finder-open-data"
        }
    }
}
```

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/MkZgFOQLcskLCw2Fe/builds/QriU2S2Q9tPaNT03Q/openapi.json
