# Business Places & Leads Extractor: Google Maps Alternative (`nat-labs/business-places-leads`) Actor

Every business in a city, region or country by category: name, address, coordinates, phone, website, email, socials. From Overture Maps open data: no blocks, no proxy, whole cities in minutes. Exact boundaries, lead filters, new-business alerts. $0.40 per 1,000 + $0.002 per location.

- **URL**: https://apify.com/nat-labs/business-places-leads.md
- **Developed by:** [Nat | Data Tools](https://apify.com/nat-labs) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / 1,000 places

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Business Places & Leads Extractor: Google Maps Alternative

Get **every business of a type in a city, region or whole country** as clean JSON, CSV or Excel: name, category, full address, coordinates, **phone, website, email and social profiles**. Dentists in Berlin, plumbers in Texas, hotels in Spain, restaurants without a website in Manchester. Data comes from **Overture Maps**, the open map dataset built by Amazon, Meta, Microsoft, TomTom and others. Nothing is scraped, so there are no blocks, CAPTCHAs or proxies.

**$0.40 per 1,000 places** plus $0.002 per location searched. No compute or proxy bill on top. Whole cities come back in about a minute.

### Why this business leads tool

| | This Actor | Google Maps scrapers |
|---|---|---|
| Price | **$0.40 / 1,000 places** (down to $0.25 on higher plans), platform usage included | $2–7 / 1,000 places, often plus start fees and proxy costs |
| Speed | A whole city and category in **about a minute**, e.g. all ~3,600 Berlin dentists in 15 s, all ~62,000 in Germany in 3.5 minutes | Scrolls a map: hours for a big city, and capped at ~120 results per search |
| Coverage | **Every** matching place inside the area, including small businesses that rank low on a map | Only what the map search shows for each zoom level and query |
| Reliability | Reads an open dataset: **no blocks, no CAPTCHAs, no proxies** | Breaks when Google changes the page; needs residential proxies |
| Area | **Exact city / region / country boundaries**, bounding boxes, or a radius around a point | One search query and map viewport at a time |
| Leads | Filters for **has website / has phone / has email / has social**, and **no website** (leads for web agencies) | Filter afterwards in a spreadsheet |
| Alerts | **New-business monitoring**: only places not delivered in earlier runs | Re-download everything |
| Licence | **Open data with a commercial licence** (CDLA-Permissive-2.0 / Apache-2.0 / CC0), source per record | Google's terms forbid scraping and reuse |

**Honest limits:** no star ratings, reviews, opening hours or photos (Overture doesn't publish them). Data is refreshed with each monthly Overture release, so a business that opened last week may be missing. Use `confidence` and `operatingStatus` to filter stale entries.

### What you can do

- **Lead generation**: every dentist, lawyer, gym, salon, contractor or agency in your sales territory, with phone, website and email.
- **Web design and marketing agencies**: businesses **without a website** in any city, ready for outreach.
- **Market research**: count competitors per city, map coverage gaps, size a market before you open.
- **Sales territories and CRM enrichment**: whole regions or countries, chunked by city.
- **Real estate and site selection**: what's around an address within any radius.
- **New-business alerts**: schedule monthly and get only businesses that appeared since the last run.
- **Enrich further**: send the `website` column to our [Website Contact Scraper](https://apify.com/nat-labs/website-contact-scraper) Actor for more emails, socials and the tech stack.
- **AI agents**: call it from Claude, ChatGPT or Cursor through Apify's AI integrations. Input is lenient: `"dentist"`, `"Italian restaurant"`, `"Austin, TX"`, `"Bavaria"` all work.
- **Your own stack**: run it from the Apify API, the Python or JavaScript client, Make, Zapier, n8n, Google Sheets, Slack, webhooks or a schedule; export JSON, CSV or Excel.

### Quick start

#### 1. One category in one city

```json
{ "locations": ["Berlin"], "categories": ["dentist"] }
```

→ every dental practice inside Berlin's city boundary (about 3,600).

#### 2. Several cities and categories, only leads with a website and phone

```json
{
    "locations": ["Austin, TX", "Dallas, TX", "Houston, TX"],
    "categories": ["plumber", "electrician", "hvac"],
    "requireWebsite": true,
    "requirePhone": true
}
```

#### 3. Businesses without a website (leads for web designers)

```json
{ "locations": ["Manchester, UK"], "categories": ["restaurant", "hair salon", "beauty salon"], "withoutWebsite": true, "requirePhone": true }
```

#### 4. Radius around a point

```json
{ "latitude": "40.7484", "longitude": "-73.9857", "radiusKm": 2, "categories": ["coffee"] }
```

#### 5. Monthly new-business alerts

```json
{ "locations": ["Bavaria"], "categories": ["restaurant"], "onlyNew": true, "monitorName": "bavaria-restaurants" }
```

The first run delivers everything and remembers it; each later run delivers only places that were not delivered before.

#### Locations

- City, county, region or country names in English or the local language: `"Munich"`, `"München"`, `"Île-de-France"`, `"Japan"`.
- Add a region or country when a name exists in several places: `"Springfield, IL"`, `"Birmingham, UK"`, `"Paris, TX"`. The log shows which place was picked and the alternatives.
- `bbox`: `"west,south,east,north"` in degrees.
- `latitude` + `longitude` + `radiusKm`.

#### Categories

Plain words work: `dentist`, `lawyer`, `plumber`, `gym`, `hotel`, `coffee`, `car dealer`, `real estate`, `vet`, `pharmacy`, `restaurant`, `italian restaurant`, `hair salon`, `accountant`, `daycare`. You can also use any of the ~2,000 Overture category names (`dental_clinic`, `attorney_or_law_firm`, `hvac_service`…). A parent category includes all its sub-categories, so `health_care` returns clinics, dentists, pharmacies and more. Leave categories empty to get every place in the area.

### Output

```json
{
    "name": "Zahnarztpraxis Dr. Muster",
    "category": "dental_clinic",
    "categoryPath": ["health_care", "outpatient_care_facility", "dental_clinic"],
    "alternateCategories": [],
    "brand": null,
    "street": "Friedrichstraße 123",
    "city": "Berlin",
    "postcode": "10117",
    "region": "BE",
    "countryCode": "DE",
    "address": "Friedrichstraße 123, 10117 Berlin, DE",
    "lat": 52.516275,
    "lng": 13.388012,
    "phone": "+4930123456",
    "phones": ["+4930123456"],
    "website": "https://www.example-zahnarzt.de/",
    "websites": ["https://www.example-zahnarzt.de/"],
    "domain": "example-zahnarzt.de",
    "email": "praxis@example-zahnarzt.de",
    "emails": ["praxis@example-zahnarzt.de"],
    "socials": [{ "platform": "facebook", "url": "https://www.facebook.com/example" }],
    "confidence": 0.94,
    "operatingStatus": "open",
    "mapUrl": "https://www.openstreetmap.org/?mlat=52.516275&mlon=13.388012#map=19/52.516275/13.388012",
    "overtureId": "4cf7e405-0068-4aa9-9941-c01e45559be0",
    "sources": [{ "dataset": "Meta", "license": "CDLA-Permissive-2.0", "licenseUrl": "https://cdla.dev/permissive-2-0/", "recordId": "1234567890", "updatedAt": "2026-09-17T20:01:51.007Z" }],
    "release": "2026-09-23.1",
    "searchArea": "Berlin, DE-BE"
}
```

The **Leads** dataset view gives the same data as flat columns for CSV and Excel. The `STATISTICS` record lists the Overture release, how each location was resolved, places per area and timings.

Typical fill rates (Berlin, 2026-09 release): phone ~85%, website ~70%, social profile ~25%, email ~17%.

### Pricing

Pay per event. **Platform usage is included**: no start fee and no compute bill on top.

| Event | What it is | Price |
|---|---|---|
| Place | One business place delivered | **$0.40 / 1,000** ($0.0004) |
| Location search | One location (city, region, country, box or radius) searched | $0.002 |

Lower place rates apply automatically on higher Apify plans (down to $0.25 / 1,000). **Never charged:** places filtered out by your filters, duplicates across overlapping areas, places skipped in monitoring mode because they were delivered before, and locations that fail.

Examples: 200 dentists in one city = **$0.082**. All ~3,600 Berlin dentists = **$1.44**. All ~62,000 dentists in Germany = **$24.90**; the same list from a Google Maps scraper at $4 / 1,000 would cost about $250 (and hit its result caps long before). A monthly new-business check of one city = $0.002 plus $0.0004 per new place.

The Actor checks your run's **maximum cost** and stops cleanly when it is reached, so you never pay more than you set.

**Free Apify plan:** up to 200 places from up to 3 locations per run (a limit set by the developer, not by Apify). Any paid plan removes it.

### Good to know

- **Monthly data.** Overture publishes a new release every month; the Actor always uses the latest one unless you pin `release`.
- **Confidence.** Each place has a 0–1 score for how sure Overture is that it exists. The default minimum is 0.5; use 0.7 or more for cleaner lists.
- **Exact boundaries.** Named locations use their official boundary polygon, so "Berlin" doesn't include Potsdam. Turn `exactBoundaries` off to use the bounding box instead.
- **Big areas.** A whole country with a broad category can return hundreds of thousands of places. Set `maxResults` or your run's maximum cost to stay in budget.
- **Speed and memory.** The default 2 GB handles a city in 10–20 seconds, a region in under a minute and a whole large country in a few minutes. Don't go below 2 GB for country-wide searches.

### Data source, licence and attribution

Places come from the [Overture Maps Foundation](https://overturemaps.org) places dataset, which combines data from Meta, Microsoft, Foursquare (OS Places), AllThePlaces, BrightQuery and others. Each record carries its `sources` with the licence: **CDLA-Permissive-2.0**, **Apache-2.0** (Foursquare OS Places) or **CC0**. All allow commercial use and redistribution; when you publish the data, credit "Overture Maps Foundation" and keep the source licences. See [Overture attribution](https://docs.overturemaps.org/attribution/).

Location names and boundaries come from Overture's divisions dataset, which includes data © OpenStreetMap contributors under the [ODbL](https://opendatacommons.org/licenses/odbl/). The location lookup table derived from it is available on request under the ODbL.

The Actor does not scrape Google, does not log in anywhere and collects no data about private individuals: places are businesses and public facilities as published by their sources.

### FAQ

**Is this the same data as Google Maps?** No. It's an independent open dataset with similar coverage for businesses (often more small businesses, fewer reviews). There are no ratings, reviews, opening hours or photos.

**Why is it so much cheaper than Google Maps scrapers?** It reads an open dataset directly instead of driving a browser through Google's map with proxies, so each place costs a fraction of a cent to deliver.

**How fresh is it?** As fresh as the latest monthly Overture release (shown in every row as `release`).

**Can I get every business in a country?** Yes: use the country as the location and leave categories empty or broad, and set `maxResults` if you want a cap.

**A location resolved to the wrong place.** Add the region or country (`"Portland, OR"`, `"Paris, FR"`) or set `country`. The log lists the other matches.

**A category isn't recognised.** The error lists the closest category names. You can use any Overture category name directly.

**Something is wrong or missing?** Open an issue in the Issues tab; it's answered within 24 hours.

# Actor input Schema

## `locations` (type: `array`):

Cities, regions or countries, e.g. "Berlin", "Austin, TX", "Manchester, UK", "Bavaria", "France". Add a country or region when a name is ambiguous. Places are limited to the exact city/region boundary.

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

Business types in plain words or Overture category names: "dentist", "italian restaurant", "plumber", "hotel", "car dealer", "health_care". Leave empty for every place. Parent categories include all sub-categories.

## `nameContains` (type: `string`):

Only places whose name contains this text (case-insensitive), e.g. "Starbucks".

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

Stop after this many places. 0 = no limit.

## `maxResultsPerLocation` (type: `integer`):

Limit for each location separately. 0 = no limit.

## `requireWebsite` (type: `boolean`):

Skip places without a website.

## `withoutWebsite` (type: `boolean`):

Leads for web designers and agencies: businesses that have no website listed.

## `requirePhone` (type: `boolean`):

Skip places without a phone number.

## `requireEmail` (type: `boolean`):

Skip places without an email address (about 1 in 6 places has one).

## `requireSocial` (type: `boolean`):

Skip places without a Facebook, Instagram or other social link.

## `minConfidence` (type: `string`):

Overture's confidence that the place exists. 0.5 is a good default; use 0.7+ for cleaner lists, 0 for everything.

## `excludeClosed` (type: `boolean`):

Skip places marked permanently closed.

## `includeAlternateCategories` (type: `boolean`):

Also return places whose secondary (alternate) category matches, e.g. a cafe that is also a bakery.

## `onlyNew` (type: `boolean`):

Deliver only places not delivered in earlier runs with the same monitor name. Schedule it monthly to get businesses that appear in each new Overture release.

## `monitorName` (type: `string`):

Separate memory for each monitor, e.g. "berlin-dentists".

## `bbox` (type: `array`):

Areas as "west,south,east,north" in degrees, e.g. "13.08,52.33,13.76,52.67".

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

Center of a circle search, e.g. "40.7128". Use with longitude and radius.

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

Center of a circle search, e.g. "-74.0060".

## `radiusKm` (type: `integer`):

Radius of the circle search in kilometres (1–500).

## `country` (type: `string`):

ISO country code or name used to pick the right location when names are ambiguous, e.g. "US" or "Germany".

## `exactBoundaries` (type: `boolean`):

Return only places inside the official boundary of a named location. Turn off to use its bounding box (faster, includes neighbouring areas).

## `stayInsideCountry` (type: `boolean`):

Skip places whose address is in another country (useful near borders).

## `release` (type: `string`):

"latest" or a release id such as "2026-09-23.1".

## Actor input object example

```json
{
  "locations": [
    "Berlin"
  ],
  "categories": [
    "dentist"
  ],
  "maxResults": 200,
  "maxResultsPerLocation": 0,
  "requireWebsite": false,
  "withoutWebsite": false,
  "requirePhone": false,
  "requireEmail": false,
  "requireSocial": false,
  "minConfidence": "0.5",
  "excludeClosed": true,
  "includeAlternateCategories": false,
  "onlyNew": false,
  "monitorName": "default",
  "radiusKm": 5,
  "exactBoundaries": true,
  "stayInsideCountry": true,
  "release": "latest"
}
```

# Actor output Schema

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

One row per business place: name, category, address, coordinates, phones, websites, emails, socials, confidence, sources.

## `statistics` (type: `string`):

Overture release used, resolved areas and boundaries, counts per area, timings, attribution.

# 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 = {
    "locations": [
        "Berlin"
    ],
    "categories": [
        "dentist"
    ],
    "maxResults": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("nat-labs/business-places-leads").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 = {
    "locations": ["Berlin"],
    "categories": ["dentist"],
    "maxResults": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("nat-labs/business-places-leads").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 '{
  "locations": [
    "Berlin"
  ],
  "categories": [
    "dentist"
  ],
  "maxResults": 200
}' |
apify call nat-labs/business-places-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nat-labs/business-places-leads"
        }
    }
}
```

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/i34p7BLsHjckhxrqU/builds/WdyelFxo1nd8qgnoi/openapi.json
