# Maps Leads Email Enricher (`cancap/maps-leads-email-enricher`) Actor

Enrich Google Maps Scraper output with real, named decision-maker emails — paste Maps results in directly. Crawls each business's own website, finds verified contacts, validates domains via MX, and scores confidence transparently. Zero paid APIs. Built for agencies and sales teams.

- **URL**: https://apify.com/cancap/maps-leads-email-enricher.md
- **Developed by:** [CANCAP](https://apify.com/cancap) (community)
- **Categories:** Lead generation
- **Stats:** 3 total users, 2 monthly users, 87.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 result founds

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/platform/actors/running/actors-in-store#pay-per-event

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

## Maps Leads Email Enricher

Takes Google Maps Scraper's output (or any list of business websites) and finds real, named decision-maker emails for each — not just generic info@ addresses. Built as a companion enrichment step for Maps-based lead generation, reusing the proven crawling/scoring engine from [Decision-Maker Email Finder].

### Why this exists

Google Maps Scraper is the single most popular Actor on the Apify Store (400K+ users), but its most common negative feedback is about missing or generic-only email data, and the extra cost of bolt-on enrichment. This Actor is designed to slot directly after a Maps Scraper run: paste its output in unchanged, get enriched rows back.

### What makes this different from the standalone Email Finder Actor

- **Accepts Maps Scraper's field names directly** (`title`, `website`, `address`, `phone`, `categoryName`, `totalScore`) — no reshaping needed.
- **Preserves every original field** on each output row, so you don't lose any Maps data; enrichment fields are simply added alongside.
- **One best email per lead row**, not every candidate — since each output row maps back to a real Maps listing, returning 10 candidate emails per business would be noise, not signal.
- **Handles duplicate domains correctly** — if multiple Maps listings share a website (e.g. a chain with several locations), the site is crawled only once, but every original lead still gets its own output row with its own address/phone preserved.

### How it works (same engine, different shape)

1. Pull the website/domain from each lead (`website`, falling back to `domain` or `url` if present).
2. Crawl a few likely pages on that business's own site (home, about, team, contact).
3. Extract named contacts and on-page emails; generate likely patterns from real names if no direct email is found; fall back to generic addresses only if nothing better exists.
4. Validate the domain via MX lookup (free, reliable). SMTP verification is available but off by default — see the same honest caveat as the standalone actor: many cloud networks, including Apify's own runtime, block outbound port 25, so this layer is best-effort, not a guarantee.
5. Pick the single best candidate per domain by source priority (found on page > pattern-generated > generic) and emit one enriched row per original input lead.

### Pricing

Same trust-first model as the companion actor: the `email-found` paid event only fires for real finds (found on page or pattern-generated from a confirmed name). Generic fallback emails and "nothing found" rows go through the free default dataset event — you're never charged full price for a result no better than what you'd type yourself.

### What's been tested locally

- All `.actor/*.json` config files validated as well-formed JSON
- `npm install` completes cleanly
- Full end-to-end run against a real live site (github.com), including:
  - A duplicate-domain scenario (two leads, same website, different addresses) — confirmed crawled once, output twice, each preserving its own pass-through fields correctly
  - A missing-website lead — confirmed correctly skipped with all original fields preserved and a clear `source: "skipped_no_website"` marker
- All shared modules carried over from the standalone Email Finder Actor (script-tag stripping fix, DNS-server fix, confidence scoring) re-verified working in this new project

### What hasn't been tested yet

- A real "found_on_page" or "pattern_generated" result end-to-end on this specific actor (we've directly verified the underlying extraction logic works via unit-style tests, and it's the identical code from the standalone actor where this path was confirmed working — but this specific actor hasn't yet produced one in a live run)
- Real-world behavior at larger batch sizes (50-100+ leads in one run) — tested so far only with a handful of leads
- SMTP verification on real Apify infrastructure for this actor specifically (expected to behave the same as the standalone actor: mostly "unknown" due to port 25 being blocked on most cloud networks)

### Local testing

```bash
npm install
## Edit storage/key_value_stores/default/INPUT.json with your test input
APIFY_LOCAL_STORAGE_DIR=./storage npm start
cat storage/datasets/default/*.json
````

### Deploying to Apify

```bash
npm install -g apify-cli
apify login
apify push
```

Or push this folder to GitHub and link the repo in the Apify Console, same as the companion actor.

### A note on responsible use

This Actor only crawls public company websites — no login-walled platforms, no LinkedIn, no scraping Google Maps directly (it expects you've already obtained that data elsewhere, e.g. via Google Maps Scraper, and are enriching it). Names and emails found on public pages may still be considered personal data under GDPR and similar regulations depending on your jurisdiction and use case — use the output responsibly and in line with applicable law.

# Actor input Schema

## `leads` (type: `array`):

Accepts Google Maps Scraper output directly. Only 'website' is required — all other fields are passed through to output unchanged.

## `maxPagesPerDomain` (type: `integer`):

How many pages to check per business (homepage, about, team, contact). Keep low for speed.

## `verifyEmails` (type: `boolean`):

Check that email domain actually accepts mail. Recommended for cleaner data.

## `includeGenericEmails` (type: `boolean`):

If no named email found, return generic addresses as fallback.

## `requestDelayMs` (type: `integer`):

Pause between page requests to avoid rate limiting. 800ms recommended.

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

Optional proxy settings. Not needed for most business websites.

## Actor input object example

```json
{
  "leads": [
    {
      "name": "Corner Restaurant",
      "website": "https://www.cornerrestaurantaustin.com",
      "phone": "+15126084488",
      "address": "110 E 2nd St, Austin, TX",
      "category": "Restaurant",
      "rating": 4.8
    },
    {
      "name": "Ember Kitchen",
      "website": "https://www.emberatx.com",
      "phone": "+15122916846",
      "address": "800 W Cesar Chavez St, Austin, TX",
      "category": "Restaurant",
      "rating": 4.8
    }
  ],
  "maxPagesPerDomain": 5,
  "verifyEmails": false,
  "includeGenericEmails": true,
  "requestDelayMs": 800,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "leads": [
        {
            "name": "Corner Restaurant",
            "website": "https://www.cornerrestaurantaustin.com",
            "phone": "+15126084488",
            "address": "110 E 2nd St, Austin, TX",
            "category": "Restaurant",
            "rating": 4.8
        },
        {
            "name": "Ember Kitchen",
            "website": "https://www.emberatx.com",
            "phone": "+15122916846",
            "address": "800 W Cesar Chavez St, Austin, TX",
            "category": "Restaurant",
            "rating": 4.8
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cancap/maps-leads-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 = { "leads": [
        {
            "name": "Corner Restaurant",
            "website": "https://www.cornerrestaurantaustin.com",
            "phone": "+15126084488",
            "address": "110 E 2nd St, Austin, TX",
            "category": "Restaurant",
            "rating": 4.8,
        },
        {
            "name": "Ember Kitchen",
            "website": "https://www.emberatx.com",
            "phone": "+15122916846",
            "address": "800 W Cesar Chavez St, Austin, TX",
            "category": "Restaurant",
            "rating": 4.8,
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("cancap/maps-leads-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 '{
  "leads": [
    {
      "name": "Corner Restaurant",
      "website": "https://www.cornerrestaurantaustin.com",
      "phone": "+15126084488",
      "address": "110 E 2nd St, Austin, TX",
      "category": "Restaurant",
      "rating": 4.8
    },
    {
      "name": "Ember Kitchen",
      "website": "https://www.emberatx.com",
      "phone": "+15122916846",
      "address": "800 W Cesar Chavez St, Austin, TX",
      "category": "Restaurant",
      "rating": 4.8
    }
  ]
}' |
apify call cancap/maps-leads-email-enricher --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Maps Leads Email Enricher",
        "description": "Enrich Google Maps Scraper output with real, named decision-maker emails — paste Maps results in directly. Crawls each business's own website, finds verified contacts, validates domains via MX, and scores confidence transparently. Zero paid APIs. Built for agencies and sales teams.",
        "version": "0.0",
        "x-build-id": "pDc3bIyYU7Id9pYHb"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/cancap~maps-leads-email-enricher/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-cancap-maps-leads-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/cancap~maps-leads-email-enricher/runs": {
            "post": {
                "operationId": "runs-sync-cancap-maps-leads-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/cancap~maps-leads-email-enricher/run-sync": {
            "post": {
                "operationId": "run-sync-cancap-maps-leads-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": [
                    "leads"
                ],
                "properties": {
                    "leads": {
                        "title": "Leads to enrich (paste Google Maps Scraper output here)",
                        "type": "array",
                        "description": "Accepts Google Maps Scraper output directly. Only 'website' is required — all other fields are passed through to output unchanged."
                    },
                    "maxPagesPerDomain": {
                        "title": "Max pages to crawl per business website",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "How many pages to check per business (homepage, about, team, contact). Keep low for speed.",
                        "default": 5
                    },
                    "verifyEmails": {
                        "title": "Verify emails with MX check?",
                        "type": "boolean",
                        "description": "Check that email domain actually accepts mail. Recommended for cleaner data.",
                        "default": false
                    },
                    "includeGenericEmails": {
                        "title": "Include generic fallback emails (info@, contact@)?",
                        "type": "boolean",
                        "description": "If no named email found, return generic addresses as fallback.",
                        "default": true
                    },
                    "requestDelayMs": {
                        "title": "Delay between requests (ms)",
                        "minimum": 250,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Pause between page requests to avoid rate limiting. 800ms recommended.",
                        "default": 800
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Optional proxy settings. Not needed for most business websites.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
