# Local Business Lead Extractor (`rowcrate/local-business-lead-extractor`) Actor

Businesses in any city with website, phone and a verified business email. Deduped, consumer mailboxes removed, source URL on every row.

- **URL**: https://apify.com/rowcrate/local-business-lead-extractor.md
- **Developed by:** [Nicolas](https://apify.com/rowcrate) (community)
- **Categories:** Lead generation, Business
- **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 rows

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?

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 Lead Extractor

Every business of a given type in a given city — with the website, the phone, and a
**business email that actually receives mail**.

Type a city and a category. Get a spreadsheet you can send a campaign from.

### What people use it for

**Building an outreach list for a niche.** Dentists in Houston, gyms in Manchester,
accountants in São Paulo. The list is built the day you run it, not bought from a broker
who assembled it eighteen months ago.

**Checking a market before entering it.** How many roofers are there in this metro, how
many have a website at all, how many look like real businesses rather than one-person
listings. That is a market-size answer you can get in four minutes.

**Filling in what your CRM is missing.** You already have the company names; this gives you
the domain, the phone and the published email for each one.

**Territory planning.** Every row carries latitude and longitude, so it maps directly.

### What you get back

| name | domain | email | email\_status | phone | city | state |
|---|---|---|---|---|---|---|
| Northgate Dental Group | northgatedental.com | frontdesk@northgatedental.com | found\_on\_site | +17135550142 | Houston | TX |
| Bayou Family Dentistry | bayoufamilydentistry.com | info@bayoufamilydentistry.com | from\_osm | +17135550177 | Houston | TX |
| Heights Orthodontics | heightsortho.com | | not\_found | +17135550199 | Houston | TX |

**`email_status` is the column that makes this different.** It is never blank, so you always
know *why* a row has no address instead of guessing:

| Value | Meaning |
|---|---|
| `found_on_site` | read from the company's own website |
| `from_osm` | the business published it in the directory itself |
| `not_found` | the site has no public address |
| `consumer_mailbox_out_of_scope` | it was a personal Gmail/Hotmail — removed on purpose |
| `no_mx_record` | the domain cannot receive mail at all |
| `disposable_domain` | a throwaway address |

Also included: `street`, `postcode`, `country`, `category`, `latitude`, `longitude`,
`osm_type`, `osm_id`, plus `source_url`, `collected_at`, `collection_method` and
`record_hash` on every row.

Download as CSV, JSON, Excel or XML, or pull it from the Apify API.

### Settings

| Setting | Default | What it does |
|---|---|---|
| **City or region** | — | The place name, as locals write it. |
| **Size of the area** | City or town | Change it only if you typed a state or a country. |
| **State** | — | Only needed when the city name repeats — there are Houstons in several states. |
| **Type of business** | dentist | Pick from the list or use a raw OpenStreetMap tag like `shop=bakery`. |
| **Only businesses with a reachable email** | Off | On gives you fewer rows and every one is usable. |
| **Look for the email on each company site** | On | This is what turns a directory dump into a usable list. |
| **Check the domain can receive mail** | Off | Adds a DNS check. Worth it right before a send. |
| **Max businesses** | 500 | Your cost dial. |

### What it costs

| Event | Price |
|---|---|
| Run started | $0.01 |
| Business row | $0.002 |
| Business email found | $0.004 |

500 businesses with ~40% carrying an email costs about **$1.81**. You pay more for the rows
that are actually actionable, and almost nothing for the rest.

### Good to know

- **Business records only.** Personal consumer mailboxes are deleted from the output on
  purpose, not delivered and flagged. GDPR and LGPD are not optional.
- **Emails come from each company's own website** — the homepage and contact page they
  publish for exactly this purpose. Nothing behind a login.
- **Rate limited on purpose**, and `robots.txt` respected. A site that asks crawlers to stay
  out is skipped, and you are told which one.
- **Coverage varies by city.** Expect roughly 30–60% of businesses to carry a findable
  email. If a niche comes back thin, that is the market, not the actor — and the
  `email_status` column shows you exactly where it thinned out.

### Data source and attribution

Business locations come from **OpenStreetMap** via the public Overpass API. OpenStreetMap
data is licensed under the ODbL, so every delivery includes:

> Contains data from OpenStreetMap, © OpenStreetMap contributors (ODbL)

### Questions?

Open an issue and I answer within 12 hours. If you want this on a schedule, delivered as a
file to your inbox or a Google Sheet, that is what I do — **rowcrate.com**.

# Actor input Schema

## `area` (type: `string`):

The place to search in, spelled the way locals write it - for example Houston, Manchester, or Sao Paulo. Use the plain name, no state or country after it; that goes in the two fields below.

## `adminLevel` (type: `string`):

How big a boundary the name refers to. City is right almost every time. Pick a bigger one only if you typed a state or a country above.

## `filterState` (type: `string`):

There are Houstons in several states. Put the state code here - TX, MO - and anything from elsewhere is dropped. Leave empty if the name is unique.

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

What kind of business to collect. Pick one from the list, or type a raw OpenStreetMap tag like shop=bakery if what you want is not here.

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

On: you get fewer rows, and every one of them has a business email you can actually write to. Off: you get everything, and a column telling you why each blank is blank. Turn this on if the list is for outreach.

## `enrichEmail` (type: `boolean`):

Most directory data has a phone and a website but no email. With this on, each company's own homepage and contact page are read to find a published business address. This is what makes the list usable, and it is what takes most of the run time.

## `checkMx` (type: `boolean`):

Adds a DNS lookup per domain to drop addresses at domains with no mail server. Slower, and worth it right before a send.

## `maxRecords` (type: `integer`):

Stops after this many. This is your cost dial - start small to check the shape of the data, then raise it.

## Actor input object example

```json
{
  "area": "Houston",
  "adminLevel": "8",
  "filterState": "TX",
  "category": "dentist",
  "onlyWithEmail": false,
  "enrichEmail": true,
  "checkMx": false,
  "maxRecords": 500
}
```

# Actor output Schema

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

One row per business: name, domain, business email, phone and address, with an email\_status column explaining every blank.

## `runSummary` (type: `string`):

Row count, request count, and the error categories that came up. Read this first when a run looks off.

## `skipped` (type: `string`):

Targets that returned nothing and why. Showing the gap is what makes the rest of the file trustworthy.

# 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 = {
    "area": "Houston",
    "category": "dentist"
};

// Run the Actor and wait for it to finish
const run = await client.actor("rowcrate/local-business-lead-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 = {
    "area": "Houston",
    "category": "dentist",
}

# Run the Actor and wait for it to finish
run = client.actor("rowcrate/local-business-lead-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 '{
  "area": "Houston",
  "category": "dentist"
}' |
apify call rowcrate/local-business-lead-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rowcrate/local-business-lead-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/wqOBZ0ldhcR0Jpw3z/builds/Ahqsc2aOtjrXBn9KC/openapi.json
