# Google Maps Email Extractor & Business Leads (`dataforge_labs/google-maps-leads-verified-emails`) Actor

Find Google Maps businesses and public website emails with source URLs, phone numbers, deduplication, role-address ranking, and honest syntax and MX-domain checks.

- **URL**: https://apify.com/dataforge\_labs/google-maps-leads-verified-emails.md
- **Developed by:** [Ula Ula](https://apify.com/dataforge_labs) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 3 total users, 1 monthly users, 79.5% 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/platform/actors/running/actors-in-store#pay-per-usage

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

## Google Maps Email Extractor & Business Leads

Turn Google Maps searches into a clean business lead list with public website
emails, phone numbers, addresses, ratings, and source evidence. Enter a business
category and location, run the Actor, and download the results as Excel, CSV,
JSON, or through the Apify API.

Unlike email tools that return an address without context, this Google Maps
email extractor records the exact public page where every email was found. It
also checks email syntax and the domain's MX records without pretending that an
individual mailbox was confirmed.

### What you get

- One deduplicated business record per Google Place ID
- Business name, category, address, city, coordinates, phone, website, rating,
  review count, and Google Maps URL
- A preferred public email plus every other email found on the business website
- Source URL, page type, extraction method, and extraction timestamp for each
  email
- Syntax, disposable-domain, role-address, and MX-domain classification
- A run summary with coverage, email hit rate, errors, nested run ID, and
  observed upstream cost

### Common use cases

#### Build local business lead lists

Find dentists, roofers, restaurants, real estate agencies, accountants, gyms,
clinics, contractors, or any other local business category in a city or region.

#### Enrich CRM and sales research

Add public company websites, phone numbers, and role-based addresses such as
`info@`, `sales@`, or `contact@` to an existing prospecting workflow.

#### Research markets and directories

Compare business density, categories, ratings, and contact coverage across
locations without manually copying Google Maps results.

#### Create auditable data pipelines

Use source URLs and extraction metadata to review where an email came from
before importing it into a CRM or another business process.

### Quick start

Use a focused query and location:

```json
{
  "searchQueries": ["dentists", "orthodontists"],
  "locationQuery": "Austin, Texas, USA",
  "countryCode": "US",
  "language": "en",
  "maxLeads": 100,
  "maxPagesPerSite": 3,
  "requireEmail": true,
  "requireWebsite": true,
  "maxUpstreamChargeUsd": 3
}
```

For your first test, set `maxLeads` to `5` or `10`. Increase it after reviewing
the output and observed cost.

### Example result

```json
{
  "place_id": "ChIJ...",
  "name": "Example Dental",
  "category": "Dentist",
  "address": "100 Main Street, Austin, TX",
  "phone": "+1 512-555-0100",
  "website": "https://example-dental.com/",
  "google_maps_url": "https://www.google.com/maps/place/...",
  "rating": 4.8,
  "reviews_count": 142,
  "email": "contact@example-dental.com",
  "email_status": "domain_deliverable",
  "emails": [
    {
      "email": "contact@example-dental.com",
      "domain": "example-dental.com",
      "source_url": "https://example-dental.com/contact",
      "page_type": "contact",
      "extraction_method": "mailto",
      "is_role_address": true,
      "mx_records": ["mx.example-dental.com"],
      "verification_status": "domain_deliverable",
      "mailbox_confirmed": false
    }
  ]
}
```

The default dataset contains the lead records. The `OUTPUT` record contains the
run summary.

### What “verified email” means here

This Actor uses honest domain-level verification:

- `domain_deliverable` — valid syntax and MX records were found for the domain
- `unknown` — DNS could not be checked reliably
- `invalid` — invalid syntax, disposable domain, missing domain, or no MX
- `catch_all_unknown` — reserved for an explicit catch-all signal

An MX record proves that a domain can receive email. It does **not** prove that a
specific mailbox exists. `mailbox_confirmed` is therefore always `false`. The
Actor never sends email and never performs SMTP mailbox probes.

### How the Google Maps lead scraper works

1. A replaceable upstream Actor retrieves public Google Maps business records.
2. Results are normalized and deduplicated by Google Place ID.
3. Business websites are deduplicated by registrable domain, so branches that
   share a website do not trigger duplicate crawls.
4. A bounded crawler checks the homepage and selected contact, about, or team
   pages.
5. Public emails are extracted from visible text, `mailto` links, JSON-LD,
   contact forms, and Cloudflare email protection.
6. Emails are normalized, classified, checked for MX records, and ranked.
7. Leads and an auditable run summary are written to Apify storage.

The website crawler respects `robots.txt` by default. It blocks localhost,
private, link-local, and other non-public destinations before requests and
after redirects. It also limits response size, redirects, content types,
timeouts, pages per domain, and concurrency. HTML is not retained.

### Important inputs

- `searchQueries` — business categories or keyword searches
- `locationQuery` — city, region, postal code, or country
- `maxLeads` — maximum unique Google Place IDs to process
- `maxPagesPerSite` — homepage plus selected contact pages, from 1 to 5
- `requireEmail` — output only leads with a usable public email
- `requireWebsite` — discard businesses without a website
- `requirePhone` — discard businesses without a published phone number
- `respectRobotsTxt` — respect website crawler directives
- `maxUpstreamChargeUsd` — spending ceiling for the nested Maps Actor
- `upstreamActorId` — replace the default Google Maps data provider

### Use from JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor(
  'dataforge_labs/google-maps-leads-verified-emails'
).call({
  searchQueries: ['roofers'],
  locationQuery: 'Phoenix, Arizona, USA',
  maxLeads: 25,
  requireEmail: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use from Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor(
    "dataforge_labs/google-maps-leads-verified-emails"
).call(run_input={
    "searchQueries": ["HVAC contractors"],
    "locationQuery": "Denver, Colorado, USA",
    "maxLeads": 25,
    "requireEmail": True,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

You can also save the configuration as an Apify Task, run it on a schedule, or
connect it to Make, Zapier, n8n, Google Sheets, webhooks, and the Apify API.

### Pricing and upstream costs

This Actor currently uses pay-per-platform-usage pricing. The caller also pays
for the nested Google Maps upstream Actor and any applicable platform compute or
proxy usage. These are separate charges.

Use `maxUpstreamChargeUsd` to cap supported pay-per-event upstream charges.
Start with a small `maxLeads` value and review the run's Usage tab before scaling
up. Provider pricing and Google Maps behavior can change over time.

### Responsible use

Public business contact data can still be personal data. You are responsible
for complying with applicable privacy, marketing, Google, and website terms,
including GDPR, UK GDPR, ePrivacy/PECR, CCPA/CPRA, and local rules.

This Actor does not send messages and should not be used for unsolicited mass
messaging. Reviews, reviewer profiles, personal employee leads, login-protected
content, and CAPTCHA bypass are deliberately excluded.

### FAQ

#### Does this Actor confirm that every mailbox exists?

No. It validates syntax and checks the email domain's MX records. It does not
send mail or probe SMTP mailboxes.

#### Where do the emails come from?

They come from public pages on each business's own website. Every email includes
the source page and extraction method.

#### Can I search multiple categories?

Yes. Add multiple values to `searchQueries`. A single `locationQuery` applies
to all searches in the run.

#### Why are some businesses missing an email?

The business may not publish one, may block crawling through `robots.txt`, may
use an unsupported page format, or may not have a website. Set
`requireEmail: false` to keep businesses without an email.

#### Are results deduplicated?

Yes. Businesses are deduplicated by Place ID. Websites are crawled once per
registrable domain while separate branch Place IDs remain separate leads.

#### Can I export the leads?

Yes. Apify datasets can be downloaded as CSV, Excel, JSON, XML, RSS, or HTML and
accessed through the API.

### Start with a small lead search

Run 5–10 results for one category and city, review the source evidence, then
scale the same input into a repeatable lead-generation workflow.

# Actor input Schema

## `searchQueries` (type: `array`):

Business categories or keyword searches.

## `locationQuery` (type: `string`):

City, region, postal code, or country used for every search.

## `countryCode` (type: `string`):

Two-letter country code.

## `language` (type: `string`):

Language code used by the Maps upstream.

## `maxLeads` (type: `integer`):

Maximum number of unique Google Place IDs to process.

## `maxPagesPerSite` (type: `integer`):

Homepage plus selected contact/about/team pages.

## `maxConcurrentSites` (type: `integer`):

Maximum number of business websites crawled in parallel.

## `requestTimeoutSecs` (type: `number`):

Timeout applied to each website request.

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

Discard places where no usable public email was found.

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

Discard Maps places that do not publish a website.

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

Discard Maps places that do not publish a phone number.

## `respectRobotsTxt` (type: `boolean`):

Skip website pages disallowed for this crawler.

## `maxUpstreamChargeUsd` (type: `number`):

PPE ceiling for the nested Google Maps Actor run.

## `upstreamActorId` (type: `string`):

Replaceable provider of Google Maps place records.

## `upstreamInputOverrides` (type: `object`):

Vendor-specific values merged over generated upstream input.

## Actor input object example

```json
{
  "searchQueries": [
    "dentists"
  ],
  "locationQuery": "Austin, Texas, USA",
  "countryCode": "US",
  "language": "en",
  "maxLeads": 6,
  "maxPagesPerSite": 2,
  "maxConcurrentSites": 10,
  "requestTimeoutSecs": 12,
  "requireEmail": true,
  "requireWebsite": true,
  "requirePhone": false,
  "respectRobotsTxt": true,
  "maxUpstreamChargeUsd": 1.5,
  "upstreamActorId": "compass/crawler-google-places",
  "upstreamInputOverrides": {}
}
```

# Actor output Schema

## `leads` (type: `string`):

No description

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

No description

# 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 = {
    "searchQueries": [
        "dentists"
    ],
    "locationQuery": "Austin, Texas, USA",
    "maxLeads": 6,
    "maxPagesPerSite": 2,
    "requireEmail": false,
    "requireWebsite": false,
    "maxUpstreamChargeUsd": 1.5
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataforge_labs/google-maps-leads-verified-emails").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 = {
    "searchQueries": ["dentists"],
    "locationQuery": "Austin, Texas, USA",
    "maxLeads": 6,
    "maxPagesPerSite": 2,
    "requireEmail": False,
    "requireWebsite": False,
    "maxUpstreamChargeUsd": 1.5,
}

# Run the Actor and wait for it to finish
run = client.actor("dataforge_labs/google-maps-leads-verified-emails").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 '{
  "searchQueries": [
    "dentists"
  ],
  "locationQuery": "Austin, Texas, USA",
  "maxLeads": 6,
  "maxPagesPerSite": 2,
  "requireEmail": false,
  "requireWebsite": false,
  "maxUpstreamChargeUsd": 1.5
}' |
apify call dataforge_labs/google-maps-leads-verified-emails --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=dataforge_labs/google-maps-leads-verified-emails",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Qx0Fu8J37d7Kmlg1d/builds/cClgLtrLCTJbiVbEU/openapi.json
