# Local Business Scraper with Emails — No API Key (`dev_web_col/local-business-scraper`) Actor

Scrape local businesses in any city: name, address, phone, hours, website — plus emails and socials crawled from each site. Open data, no blocks.

- **URL**: https://apify.com/dev\_web\_col/local-business-scraper.md
- **Developed by:** [Diseño Web de Colombia](https://apify.com/dev_web_col) (community)
- **Categories:** Lead generation, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 business returneds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Local Business Scraper with Emails — No API Key

**Local business data with the one field everybody actually wants: the email address.**

### What is the Local Business Scraper?

This Actor pulls local businesses in any city from OpenStreetMap — name, address, phone, opening hours, website, coordinates and category — and then goes one step further: it crawls each business's own website to find contact emails and social profiles.

No Google API key, no billing account, no quota. OpenStreetMap data is ODbL-licensed, which means you are allowed to redistribute what you extract.

### The email crawl is the difference

Raw OpenStreetMap data is good at some fields and terrible at others. Measured across 600 real points of interest in Miami:

| Field | Coverage in raw OSM |
|---|---|
| name | 96% |
| street address | 77% |
| phone | 44% |
| website | 43% |
| **email** | **1%** |

Email is the field people buy, and it is the one OSM barely has. So this Actor takes the 43% that do have a website and crawls it for contact details. On a real Miami Beach run that took the count from **5 businesses with an email to 70**.

No other OpenStreetMap Actor on the Store does this. There is also failover across Overpass mirrors, because a single mirror returning a 504 — or worse, a 200 with zero results — is common enough to ruin a run.

### What data you get

Business name, category, full address, phone, website, opening hours, latitude and longitude, plus the emails and social profiles crawled from the business site. Every row is keyed by its OpenStreetMap ID.

### Input

Every field is optional unless marked required.

| Field | Type | Description |
|---|---|---|
| `location` | string | Just type it: Miami Beach, Barcelona, Manchester, Bogotá. The actor turns it into map coordinates for you. |
| `categories` | array | What to look for. Pick as many as you need. |
| `enrichContacts` | boolean | Visits each business website and pulls the email and social profiles. This is the whole point: the map data itself has emails for barely 1% of businesses. |
| `requireWebsite` | boolean | Recommended for lead generation — a business with no website cannot be enriched with an email. |
| `requirePhone` | boolean | Drops entries without a phone number. |
| `boundingBox` | string | Overrides the city name. Format: south,west,north,east — for example 25.76,-80.20,25.79,-80.17 |
| `maxResults` | integer | You are charged per business returned. |
| `proxyConfiguration` | object | Optional. The map data needs no proxy at all. A proxy only helps when crawling business websites that block datacenter IPs. |

#### Input sample

```json
{
  "location": "Miami Beach",
  "categories": [
    "restaurant",
    "cafe"
  ]
}
```

### Output sample

One real row from an actual run:

```json
{
  "id": "osm:node:631761812",
  "osmId": "631761812",
  "osmType": "node",
  "name": "TGI Fridays",
  "category": "restaurant",
  "lat": 25.7748183,
  "lon": -80.1320417,
  "address": "500 Ocean Drive Miami Beach",
  "street": "Ocean Drive",
  "houseNumber": "500",
  "city": "Miami Beach",
  "postcode": "33139",
  "country": null,
  "phone": "+1 305-673-8443",
  "website": "https://locations.tgifridays.com/fl/miami-beach/500-ocean-dr.html",
  "email": "contact@meetsoci.com",
  "openingHours": null,
  "brand": "TGI Fridays",
  "cuisine": "american",
  "enrichedEmails": [
    "contact@meetsoci.com"
  ],
  "facebook": "https://www.facebook.com/TGIFridays",
  "instagram": "https://www.instagram.com/tgifridays",
  "linkedin": null,
  "twitter": "https://twitter.com/TGIFridays",
  "enriched": true,
  "osmUrl": "https://www.openstreetmap.org/node/631761812"
}
```

### Who uses this

- **Local lead generation** — restaurants, gyms, salons, clinics, with contact details
- **Agencies** — build a prospect list for a city without paying per lookup
- **Delivery and logistics** — coordinates and opening hours for route planning
- **Market researchers** — density and category mix by neighbourhood
- **Anyone who needs Google Maps data** but not the Google bill

### Honest limits

These are real and none of them is fixable by any tool. They are here so you know what you are buying before you run it.

- **Coverage is what OpenStreetMap has**, and it varies a lot by city. Well-mapped European cities are richer than sparse suburbs. The percentages above are typical, not guaranteed.
- **The email crawl stops after two minutes** so runs always finish inside Apify's checks. On a dense area you may get emails for most sites but not all, and the log tells you exactly how many were crawled.
- **Emails are whatever the business publishes.** No pattern-guessing. Expect info@ and contact@, not named staff.
- **Some businesses have no website**, and those cannot be enriched at all.
- **An empty area is a valid answer.** The Actor warns and finishes successfully rather than failing.

### FAQ

#### Why OpenStreetMap instead of Google Maps?

Three reasons: no API key or billing account, no quota, and the data is ODbL-licensed so you may redistribute it. Google's terms do not allow that. The trade-off is coverage, which is honestly documented above.

#### Do I need a Google API key?

No. Nothing here touches Google at all.

#### How do you find emails when OpenStreetMap does not have them?

By visiting the business's own website and reading its contact pages. That is why the email count went from 5 to 70 on a real Miami Beach run.

#### Can I search a custom area instead of a city?

Yes, pass a bounding box. Otherwise give a city or district name and it is geocoded for you.

#### What categories can I search?

Any OpenStreetMap amenity or shop value — restaurant, cafe, bar, pharmacy, dentist, hotel, gym and hundreds more. Pass several at once.

#### Why did some businesses come back without a phone?

Because OpenStreetMap does not have one for them; measured coverage is about 44%. Use `requirePhone` to drop those rows if you only want complete records.

#### Do I need an account or an API key for the source?

No. This Actor only reads public pages and public endpoints, the same ones any
logged-out visitor sees. You never give it credentials, and nothing is done on
your behalf.

#### Is it legal to scrape this data?

Scraping publicly available information is broadly accepted as legal, and this
Actor only ever touches pages that require no login. That said, what you may do
with the data afterwards is a separate question — personal data in particular is
regulated by GDPR and CCPA. If you plan to process personal data, take advice
first. Apify has a good primer: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

#### How much will a run cost me?

You are charged per result, so the cost scales with what you actually get back.
The pricing is shown on this page above the input form. Start with a small run to
see real numbers before you scale up.

#### Can I export to Excel, CSV or Google Sheets?

Yes. Every run's dataset can be downloaded as CSV, Excel, JSON, XML or HTML from
the **Storage** tab, and Apify integrates directly with Google Sheets, Airtable,
Zapier, Make and Slack.

#### Can I run this on a schedule?

Yes. Open the **Schedules** tab and pick an interval — hourly, daily, weekly.
Each run only costs you what it returns.

#### Can I call it from my own code instead of the console?

Yes. Every Actor on Apify is also an API endpoint. There are official clients for
[Python](https://docs.apify.com/api/client/python/) and
[JavaScript](https://docs.apify.com/api/client/js/), plus a plain REST API. The
**API** tab on this page shows ready-made snippets with your input already filled in.

#### Something came back empty. Is it broken?

Usually not. An empty result normally means the filters were too narrow, or the
source genuinely has nothing to return for that query. This Actor is written to
finish successfully and tell you what happened rather than fail — check the run
log, it says which step returned nothing.

### Related Actors

- **Company Enrichment** — the same email crawling, for company domains
- **Company Signals** — track competitors by domain

### Where the data comes from

The Overpass API over OpenStreetMap data (ODbL licensed), Nominatim for geocoding, and each business's own public website for contact details.

# Actor input Schema

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

Just type it: Miami Beach, Barcelona, Manchester, Bogotá. The actor turns it into map coordinates for you.

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

What to look for. Pick as many as you need.

## `enrichContacts` (type: `boolean`):

Visits each business website and pulls the email and social profiles. This is the whole point: the map data itself has emails for barely 1% of businesses.

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

Recommended for lead generation — a business with no website cannot be enriched with an email.

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

Drops entries without a phone number.

## `boundingBox` (type: `string`):

Overrides the city name. Format: south,west,north,east — for example 25.76,-80.20,25.79,-80.17

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

You are charged per business returned.

## `proxyConfiguration` (type: `object`):

Optional. The map data needs no proxy at all. A proxy only helps when crawling business websites that block datacenter IPs.

## Actor input object example

```json
{
  "location": "Miami Beach",
  "categories": [
    "restaurant",
    "cafe"
  ],
  "enrichContacts": true,
  "requireWebsite": false,
  "requirePhone": false,
  "maxResults": 500,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `businesses` (type: `string`):

One dataset item per business.

# 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": "Miami Beach",
    "categories": [
        "restaurant",
        "cafe"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dev_web_col/local-business-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": "Miami Beach",
    "categories": [
        "restaurant",
        "cafe",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("dev_web_col/local-business-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": "Miami Beach",
  "categories": [
    "restaurant",
    "cafe"
  ]
}' |
apify call dev_web_col/local-business-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=dev_web_col/local-business-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/SWPn84IolH8rlAa01/builds/TRgtcmMeMBqEeKDVb/openapi.json
