# Business Email Scraper (`axiomworks/business-email-extractor`) Actor

Find local businesses by niche and city and get name, address, category, website, public emails and phone numbers. Built on OpenStreetMap plus each business's own website, up to 50 businesses per run. Emails are found for some businesses, not all. No login or API key needed.

- **URL**: https://apify.com/axiomworks/business-email-extractor.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 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.
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 Email Scraper

### What does Business Email Scraper do?

Business Email Scraper finds local businesses for a niche and a city, then collects each business's website, public email addresses and phone numbers. Enter a niche such as "coffee" or "dentist" and a location such as "Austin, TX", and you get one dataset row per business with name, address, coordinates, category, website, emails and phones. Export the result as JSON, CSV or Excel. The input is a niche and a city; the Actor does not accept a list of website URLs.

The business list comes from OpenStreetMap (through the Photon geocoder and the Overpass API), not from Google Maps. The Actor reads the website, phone and email tags that OpenStreetMap contributors have added to each place. When a business has no website tag, it tries to find one with a web search, and then reads the homepage and the `/contact` and `/contact-us` pages for public emails and phone numbers. No login, cookies or API key are needed.

Typical users are agencies, freelancers, sales teams and researchers who want a small, quick list of local businesses to contact. Because the data is OpenStreetMap-based, coverage varies by city and niche (see the FAQ for details).

### What data can you get?

| Field | Description | Example |
|---|---|---|
| `id` | Stable id: OpenStreetMap element type and id | `node/11111850805` |
| `sourceUrl` | Page the row was read from: the business website when found, otherwise its OpenStreetMap page | `https://www.cuppaaustin.com/` |
| `name` | Business name from OpenStreetMap (max 150 characters) | `Cuppa Austin Coffee` |
| `street` | Street name, without house number. Null if unknown | `West Parmer Lane` |
| `houseNumber` | House number from OpenStreetMap. Null if unknown | `9225` |
| `city` | City, or county as fallback. Null if unknown | `Austin` |
| `postcode` | Postal code. Null if unknown | `78717` |
| `country` | Country name. Null if unknown | `United States` |
| `latitude` | Latitude in decimal degrees | `30.4780176` |
| `longitude` | Longitude in decimal degrees | `-97.7664202` |
| `category` | OpenStreetMap category as key / value | `amenity / cafe` |
| `osmUrl` | OpenStreetMap page of the business | `https://www.openstreetmap.org/node/11111850805` |
| `website` | Business website from OpenStreetMap or found by web search. Null if none | `https://www.cuppaaustin.com/` |
| `websiteSource` | How the website was found: `osm` or `search`. Null if no website | `osm` |
| `emails` | Public contact emails, max 10, from OpenStreetMap tags and the website | `["info@cuppaaustin.com"]` |
| `phones` | Public phone numbers, max 5, normalised to E.164 where possible | `["+15123826729"]` |
| `phonesRaw` | The same phone numbers exactly as found | `["+1-512-382-6729"]` |
| `query` | The niche you searched for | `coffee` |
| `location` | The location you searched | `Austin, TX` |
| `scrapedAt` | ISO 8601 UTC timestamp of the run | `2026-09-30T18:09:11.915559+00:00` |

The dataset has three views in the Console: "Businesses" (main columns), "Contacts" (name, website, emails, phones and website source) and "Full data" (every field including coordinates and the OpenStreetMap link).

### How to use Business Email Scraper

1. Open the Actor in Apify Console and go to the Input tab.
2. Type a business niche into "Business niche", for example `coffee`, `pizza`, `plumber` or `dentist`. One or two words work best.
3. Type a city or area into "Location", for example `Austin, TX`.
4. Set "Max results" (1 to 50). Each returned business counts as one result.
5. Decide on the filters: turn on "Only businesses with an email" to keep only rows with a public email, or "Include businesses with no contact info" to also keep rows where nothing was found.
6. Click Start. A small run usually takes under a minute.
7. Open the Output tab, pick a view, and export the dataset as JSON, CSV, Excel, XML or HTML.

### Input

| Field | Type | Default / prefill | Description |
|---|---|---|---|
| `query` | string | prefill `coffee` | The kind of business to find. The search matches business names and OpenStreetMap categories. One or two words work best. Required for the run to do anything. |
| `location` | string | prefill `Austin, TX` | City or area to search. Results are filtered to businesses whose address matches this location. |
| `maxItems` | integer, 1 to 50 | default 10, prefill 5 | Maximum number of businesses to return. |
| `requireEmail` | boolean | default false, prefill true | Only businesses with an email: return and charge only businesses where at least one public email was found. |
| `includeWithoutContact` | boolean | default false | By default only businesses with at least a website, an email or a phone number are returned. Turn on to also return businesses where nothing was found. |
| `proxyConfiguration` | object | prefill Apify Proxy on | Optional. Used for the web search that discovers business websites, which can be rate-limited from datacenter IPs. |

If `query` or `location` is empty, the run fails right away with a clear message ("input 'query' is required" or "input 'location' is required").

Complete input example:

```json
{
  "query": "coffee",
  "location": "Austin, TX",
  "maxItems": 20,
  "requireEmail": true,
  "includeWithoutContact": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

### Output

These are 2 of the items from a real run with `query` set to `coffee`, `location` set to `Austin, TX` and `maxItems` set to 5:

```json
[
  {
    "id": "node/11111850805",
    "sourceUrl": "https://www.cuppaaustin.com/",
    "name": "Cuppa Austin Coffee",
    "street": "West Parmer Lane",
    "houseNumber": "9225",
    "city": "Austin",
    "postcode": "78717",
    "country": "United States",
    "latitude": 30.4780176,
    "longitude": -97.7664202,
    "category": "amenity / cafe",
    "osmUrl": "https://www.openstreetmap.org/node/11111850805",
    "website": "https://www.cuppaaustin.com/",
    "websiteSource": "osm",
    "emails": ["info@cuppaaustin.com"],
    "phones": ["+15123826729"],
    "phonesRaw": ["+1-512-382-6729"],
    "query": "coffee",
    "location": "Austin, TX",
    "scrapedAt": "2026-09-30T18:09:11.915559+00:00"
  },
  {
    "id": "way/42874326",
    "sourceUrl": "https://joscoffee.com/red-river",
    "name": "Jo's Coffee Red River",
    "street": "East 41st Street",
    "houseNumber": "1000",
    "city": "Austin",
    "postcode": "78751",
    "country": "United States",
    "latitude": 30.2998339,
    "longitude": -97.7219121,
    "category": "amenity / cafe",
    "osmUrl": "https://www.openstreetmap.org/way/42874326",
    "website": "https://joscoffee.com/red-river",
    "websiteSource": "osm",
    "emails": ["info@joscoffee.com", "catering@joscoffeetx.com", "redriver@joscoffeetx.com"],
    "phones": ["+15123835211"],
    "phonesRaw": ["+1 512 383 5211"],
    "query": "coffee",
    "location": "Austin, TX",
    "scrapedAt": "2026-09-30T18:09:11.915559+00:00"
  }
]
```

When a business has no website, email or phone that could be verified, those fields are null or empty arrays. That is normal: the Actor never guesses or fabricates contact details. `websiteSource` is `osm` when the website came from the OpenStreetMap listing and `search` when it was discovered by web search.

### How much does it cost?

The Actor uses pay-per-event pricing: you are charged for each business that is returned in the dataset, and businesses that are skipped are not charged. Turn on "Only businesses with an email" to pay only for rows that have an email. Apify's free plan includes monthly platform credit that covers small runs and testing. See the Pricing tab of the Actor page for the current per-result price. A run of a few results typically finishes in around 30 seconds to a couple of minutes.

### Use with the API

Python, using the `apify-client` package:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("axiomworks/business-email-extractor").call(run_input={
    "query": "coffee",
    "location": "Austin, TX",
    "maxItems": 10,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["emails"])
```

JavaScript, using the `apify-client` package:

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('axiomworks/business-email-extractor').call({
    query: 'coffee',
    location: 'Austin, TX',
    maxItems: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

cURL, running the Actor synchronously and returning the dataset items:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~business-email-extractor/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "coffee", "location": "Austin, TX", "maxItems": 10}'
```

You can send the results to other tools with Apify integrations: Zapier, Make, n8n, Google Sheets, and webhooks that fire when a run finishes. Schedule the Actor to run for different niches or cities and append the results to a sheet or CRM.

### Use with AI agents (MCP)

You can call Business Email Scraper from any MCP-capable client through Apify's MCP server at mcp.apify.com. The server exposes the tools `search-actors` and `call-actor`, so an agent can find this Actor and run it. To load only this Actor as a tool, use this configuration in Claude Desktop, Cursor, VS Code or another MCP client:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/business-email-extractor"
    }
  }
}
```

Example prompts you could type to an agent:

- "Find 10 coffee shops in Austin, TX and give me their websites and contact emails."
- "Get contact details for plumbers in Denver and list the ones that have a public email address."
- "Search for dentists in Leeds and export their phone numbers and websites to a table."

The Actor has typed input and output schemas, so the agent knows the exact fields (`query`, `location`, `maxItems`, `requireEmail`, `includeWithoutContact`) and the structure of each returned business.

### FAQ

**Where does the data come from, and how complete is it?**
The business list comes from OpenStreetMap, a community-maintained map, plus the business websites themselves. Coverage varies by city and niche. It tends to be good for restaurants, cafes and shops in larger cities, and thinner for some trades, professional services and small towns, because it depends on what volunteers have mapped. This is not a Google Maps scraper. If you need the most complete list of businesses in a niche or city, a Google Maps based tool may find more businesses than this Actor. This Actor is a good fit when you want a quick, low-cost list without a Google account or API key.

**How many results can I get per search?**
Up to 50 per run. The data source returns a limited number of matches per query, and the Actor filters out results that do not match your location or niche, so narrow niches in small towns can return fewer. Run several queries or nearby locations to get more.

**Why does a chain location list several emails?**
For multi-location businesses the website often lists every branch's address. The Actor returns the public emails it finds on the linked site, preferring generic mailboxes and addresses that match the branch, so check which one belongs to the branch you need.

**Why do some businesses have no email?**
Many small businesses do not publish an email address, or only use a contact form. The Actor returns only addresses that are publicly visible on OpenStreetMap or on the website's homepage and contact pages. It does not guess or verify addresses. Third-party addresses such as ordering platforms and placeholder emails are dropped.

**Do I need a proxy?**
The proxy is optional and only affects the web search that finds websites for businesses without an OpenStreetMap website tag. That search can be rate-limited from datacenter IPs, so Apify Proxy is prefilled. The Actor still runs if the proxy is unavailable.

**Are phone numbers international?**
Phone numbers are normalised to E.164 where the country code or a North American 10-digit number makes that possible; `phonesRaw` keeps the original text. Numbers found on websites are matched in US and Canada format only, so businesses outside North America may show OpenStreetMap phone numbers but few website phone numbers.

**Why is my run sometimes slow?**
Photon and Overpass are free shared community services. The Actor makes few requests, retries with backoff when they are busy, and falls back to a mirror Overpass server. A busy service slows the run down rather than failing it.

**How fresh is the data?**
Contact details from OpenStreetMap are as recent as the last edit by a contributor. Website contacts are read live at run time. Schedule runs if you want to refresh a list.

### Is it legal to scrape business contact data?

The Actor collects publicly available business information from OpenStreetMap and public website pages, and it does not log in to anything. You are responsible for how you use the data. Email marketing and cold outreach are regulated in many places (for example CAN-SPAM, GDPR and the ePrivacy rules), and some business contact details can be personal data. Respect privacy and data protection law, honor opt-outs, follow each website's terms, and comply with the OpenStreetMap data license terms. Seek legal advice if you are unsure about your use case.

### Feedback

If a search returns too few results or wrong contacts, open an issue from the Issues tab of this Actor with the niche and location you used. Concrete examples make problems much easier to fix.

# Actor input Schema

## `query` (type: `string`):

What kind of businesses to find, e.g. 'coffee', 'pizza', 'plumber', 'dentist'. One or two words work best; the search matches business names and OpenStreetMap categories. Required.

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

City or area to search, e.g. 'Austin, TX'. Results are filtered to businesses whose address matches this location. Required.

## `maxItems` (type: `integer`):

Maximum number of businesses to return (1-50). Each returned business is one result (min 1, max 50).

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

Return and charge only businesses where at least one public email was found. Default false.

## `includeWithoutContact` (type: `boolean`):

By default only businesses with at least a website, email or phone number are returned. Turn on to also return businesses where nothing could be found.

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

Optional. Used for the web search that discovers business websites, which can be rate-limited from data-center IPs.

## Actor input object example

```json
{
  "query": "coffee",
  "location": "Austin, TX",
  "maxItems": 5,
  "requireEmail": true,
  "includeWithoutContact": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All results in the dataset

# 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 = {
    "query": "coffee",
    "location": "Austin, TX",
    "maxItems": 5,
    "requireEmail": true,
    "includeWithoutContact": false,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/business-email-extractor").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 = {
    "query": "coffee",
    "location": "Austin, TX",
    "maxItems": 5,
    "requireEmail": True,
    "includeWithoutContact": False,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/business-email-extractor").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 '{
  "query": "coffee",
  "location": "Austin, TX",
  "maxItems": 5,
  "requireEmail": true,
  "includeWithoutContact": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call axiomworks/business-email-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/business-email-extractor"
        }
    }
}
```

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/mifAfnyzdW8QxKJJb/builds/G6ImQf1TFmGmRWmbu/openapi.json
