# Google Maps Email Enricher — Find Business Emails from Maps (`kuldip_parmar/google-maps-email-enricher`) Actor

The missing step between Google Maps Scraper and your cold email tool. Paste your Maps dataset ID and get verified business emails back — crawls homepages + contact pages, scores by confidence, validates MX records. 77%+ hit rate on reachable sites.

- **URL**: https://apify.com/kuldip\_parmar/google-maps-email-enricher.md
- **Developed by:** [kuldip parmar](https://apify.com/kuldip_parmar) (community)
- **Categories:** Lead generation, Other
- **Stats:** 3 total users, 2 monthly users, 71.4% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## 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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Enricher — Find Business Emails from Maps Data

> **The missing step between Google Maps Scraper and your cold email tool.**

Google Maps Scraper gives you business names, addresses, phone numbers, and ratings — but almost never emails. This actor fills that gap. Feed it your Maps scraper output and it returns verified business emails by crawling each company's website automatically.

**77%+ hit rate on reachable sites. Zero setup required. Works with any Google Maps Scraper.**

---

### Why this actor exists

Every user of Google Maps Scraper hits the same wall: *"I have 2,000 businesses — now how do I get their emails?"*

The usual answer is:
- Manually visit each website (impossible at scale)
- Buy a third-party enrichment tool ($300–$800/month)
- Use the Maps contact add-on (40–70% hit rate, no confidence scoring)

This actor does it automatically for a fraction of the cost — and gives you **confidence scores** so you know which emails to trust before you send a single message.

---

### How it works

````

Your Google Maps Scraper output (Dataset ID or CSV)
↓
Visit each business website (homepage)
↓
Crawl /contact, /about, /team pages if no email found
↓
Score every email: verified / likely / possible / low
↓
Validate MX records (optional)
↓
Clean CSV — all original Maps fields + email columns added

````

---

### Quick start (3 steps)

**Step 1** — Run any Google Maps Scraper. Copy the **Dataset ID** from the Output tab.

**Step 2** — Paste the Dataset ID into the **Apify Dataset ID** field below. Click **Run**.

**Step 3** — Download your enriched CSV from the Output tab. Done.

---

### Input options

| Field | Description |
|-------|-------------|
| **Apify Dataset ID** | Dataset ID from any Google Maps Scraper run — the easiest option |
| **CSV URL** | Public URL to a CSV file with business data (must have a `website` column) |
| **Manual list** | JSON array of businesses — useful for testing |
| **Crawl subpages** | Also checks `/contact`, `/about`, `/team` — increases hit rate ~15–20% (default: ON) |
| **Validate MX records** | Confirms the email domain can receive mail (default: ON) |
| **Skip no-website rows** | Omit businesses that have no website (default: OFF) |
| **Proxy configuration** | Residential proxies improve hit rate on sites that block datacenter IPs |

---

### Output columns added to your data

All your original Google Maps columns are preserved. These are added:

| Column | What it means |
|--------|--------------|
| `email` | Best email found for this business |
| `email_confidence` | `verified` / `likely` / `possible` / `low` |
| `email_score` | Internal score (0–100) — higher = more trustworthy |
| `email_alternatives` | Other emails found on the site (comma-separated) |
| `mx_valid` | `true` if the domain has working mail servers |
| `enrichment_status` | `found` / `not_found` / `no_website` / `site_unreachable` |
| `enriched_at` | Timestamp — useful for knowing when data was fresh |

---

### Confidence levels

| Level | What it means | When to use |
|-------|--------------|-------------|
| `verified` | Found on business domain via mailto link, known contact prefix (info@, hello@, contact@) | Send directly |
| `likely` | Found on business domain but from text pattern or generic page | Safe to use, light review |
| `possible` | Found on site but domain mismatch or unclear prefix | Verify before sending |
| `low` | Found but multiple red flags | Manual review only |

---

### Real performance data

Tested across 20 real businesses — agencies, law firms, accountants, dentists, plumbers, gyms:

| Category | Hit rate |
|----------|----------|
| Digital Agencies | 100% |
| Plumbers / Trades | 100% |
| Dental / Local health | 75% |
| Law Firms | 50–80% |
| Accountants | 60–80% |
| Real Estate (independent) | 70% |
| Large brands / enterprise | 20–40% |

**Overall hit rate on reachable sites: 77%**

> Hit rate increases to 80–85% with residential proxies enabled (recommended for runs over 500 businesses).

---

### What makes this better than alternatives

| Feature | This actor | Maps contact add-on | Manual work |
|---------|-----------|--------------------|----|
| Hit rate | 77%+ | 40–70% | 100% |
| Confidence scoring | ✓ | ✗ | ✗ |
| Subpage crawling | ✓ | ✗ | ✓ |
| MX validation | ✓ | ✗ | ✗ |
| False positive filtering | ✓ | Partial | ✓ |
| Works with any Maps scraper | ✓ | Only official | ✓ |
| Cost per 1,000 leads | ~$5 | ~$8–15 | Hours of time |

---

### Frequently asked questions

**Does it work with the official Google Maps Scraper and community versions?**
Yes. It automatically normalises field names from all major Maps scraper variants. If your CSV has a `website` or `url` column, it works.

**Why does it crawl subpages?**
Many businesses only list their email on `/contact` or `/about` — not the homepage. In our testing, 30–40% of emails were found on subpages, not the homepage. Disabling this option is faster but reduces your hit rate noticeably.

**What happens when a business uses a contact form instead of an email?**
The actor records it as `not_found` and still returns the row with all original data. You can filter these out or use them for manual outreach.

**Is this safe to run at high volume?**
Yes. The crawler respects standard web practices, uses proper headers, and rate-limits automatically. For large runs (5,000+ businesses), enable residential proxies and set max concurrency to 20–30.

**Why are some results `site_unreachable`?**
Some sites block datacenter IPs (the default on Apify). Enabling residential proxies in the proxy settings resolves this for most sites.

**Does it find personal Gmail/Outlook emails?**
It filters these out. The actor specifically looks for business emails on the company's own domain. Personal email addresses score very low and are excluded from the best pick.

---

### Pricing

Charged per result row processed (whether email found or not).

| Volume | Estimated cost |
|--------|---------------|
| 1,000 businesses | ~$0.50–1.00 |
| 10,000 businesses | ~$5–10 |
| 100,000 businesses | ~$50–100 |

*Plus standard Apify platform compute costs. Residential proxy usage billed separately by Apify.*

---

### Support & feedback

Found a bug? Have a feature request? Open an issue on [GitHub](https://github.com/kuldipparmar/google-maps-email-enricher).

Response time: within 48 hours on weekdays.

# Actor input Schema

## `searchTerm` (type: `string`):

What type of business are you looking for? Examples: `restaurant`, `dentist`, `plumber`, `digital agency`, `accountant`, `real estate agent`. Use the same terms you would type into Google Maps.
## `location` (type: `string`):

City, region, or country to search in. Be as specific as you need. Examples: `New York USA`, `London UK`, `Sydney Australia`, `Chicago Illinois`.
## `maxResults` (type: `integer`):

How many businesses to scrape from Google Maps. Google Maps shows up to ~120 results per search term. Default is 20 — good for testing. Use 50–100 for production runs.
## `crawlSubpages` (type: `boolean`):

Recommended: ON. Many businesses only list their email on /contact or /about — not the homepage. This option checks those extra pages and increases the email hit rate by 15–20%.
## `validateMx` (type: `boolean`):

Recommended: ON. Checks that each email domain has working mail servers before including it in the output. Filters out dead emails from businesses that no longer operate.
## `skipNoWebsite` (type: `boolean`):

Default: OFF. When ON, businesses that have no website listed on Google Maps are excluded from the output. Turn ON for a cleaner list when you only care about businesses with online presence.
## `skipNoEmail` (type: `boolean`):

Default: OFF. When ON, only rows where an email was successfully found are saved. Useful when you want a clean outreach list with zero empty rows.
## `maxConcurrency` (type: `integer`):

How many business websites to visit at the same time during email extraction. 10 is safe and fast for most runs. Increase to 20–30 for large runs with sufficient memory.
## `proxyConfiguration` (type: `object`):

**Residential proxies strongly recommended.** Google Maps actively blocks datacenter IPs. Without residential proxies, the Maps search step may return 0 results. Residential proxies also improve email extraction hit rate on business websites that block datacenter IPs.

## Actor input object example

```json
{
  "searchTerm": "restaurant",
  "location": "New York USA",
  "maxResults": 20,
  "crawlSubpages": true,
  "validateMx": true,
  "skipNoWebsite": false,
  "skipNoEmail": false,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
````

# 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 = {
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kuldip_parmar/google-maps-email-enricher").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 = { "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    } }

# Run the Actor and wait for it to finish
run = client.actor("kuldip_parmar/google-maps-email-enricher").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 '{
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call kuldip_parmar/google-maps-email-enricher --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Email Enricher — Find Business Emails from Maps",
        "description": "The missing step between Google Maps Scraper and your cold email tool. Paste your Maps dataset ID and get verified business emails back — crawls homepages + contact pages, scores by confidence, validates MX records. 77%+ hit rate on reachable sites.",
        "version": "1.0",
        "x-build-id": "KGkFJKx2AVR6Ay1Ag"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/kuldip_parmar~google-maps-email-enricher/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-kuldip_parmar-google-maps-email-enricher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/kuldip_parmar~google-maps-email-enricher/runs": {
            "post": {
                "operationId": "runs-sync-kuldip_parmar-google-maps-email-enricher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/kuldip_parmar~google-maps-email-enricher/run-sync": {
            "post": {
                "operationId": "run-sync-kuldip_parmar-google-maps-email-enricher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "searchTerm",
                    "location"
                ],
                "properties": {
                    "searchTerm": {
                        "title": "🔍 Search term",
                        "minLength": 1,
                        "type": "string",
                        "description": "What type of business are you looking for? Examples: `restaurant`, `dentist`, `plumber`, `digital agency`, `accountant`, `real estate agent`. Use the same terms you would type into Google Maps."
                    },
                    "location": {
                        "title": "📍 Location",
                        "minLength": 1,
                        "type": "string",
                        "description": "City, region, or country to search in. Be as specific as you need. Examples: `New York USA`, `London UK`, `Sydney Australia`, `Chicago Illinois`."
                    },
                    "maxResults": {
                        "title": "💯 Number of businesses to find",
                        "minimum": 1,
                        "maximum": 120,
                        "type": "integer",
                        "description": "How many businesses to scrape from Google Maps. Google Maps shows up to ~120 results per search term. Default is 20 — good for testing. Use 50–100 for production runs.",
                        "default": 20
                    },
                    "crawlSubpages": {
                        "title": "🔎 Also check Contact & About pages",
                        "type": "boolean",
                        "description": "Recommended: ON. Many businesses only list their email on /contact or /about — not the homepage. This option checks those extra pages and increases the email hit rate by 15–20%.",
                        "default": true
                    },
                    "validateMx": {
                        "title": "✅ Validate email MX records",
                        "type": "boolean",
                        "description": "Recommended: ON. Checks that each email domain has working mail servers before including it in the output. Filters out dead emails from businesses that no longer operate.",
                        "default": true
                    },
                    "skipNoWebsite": {
                        "title": "🚫 Skip businesses with no website",
                        "type": "boolean",
                        "description": "Default: OFF. When ON, businesses that have no website listed on Google Maps are excluded from the output. Turn ON for a cleaner list when you only care about businesses with online presence.",
                        "default": false
                    },
                    "skipNoEmail": {
                        "title": "📧 Only show businesses where email was found",
                        "type": "boolean",
                        "description": "Default: OFF. When ON, only rows where an email was successfully found are saved. Useful when you want a clean outreach list with zero empty rows.",
                        "default": false
                    },
                    "maxConcurrency": {
                        "title": "⚡ Speed — parallel website crawlers",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "How many business websites to visit at the same time during email extraction. 10 is safe and fast for most runs. Increase to 20–30 for large runs with sufficient memory.",
                        "default": 10
                    },
                    "proxyConfiguration": {
                        "title": "🌐 Proxy settings",
                        "type": "object",
                        "description": "**Residential proxies strongly recommended.** Google Maps actively blocks datacenter IPs. Without residential proxies, the Maps search step may return 0 results. Residential proxies also improve email extraction hit rate on business websites that block datacenter IPs."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
