# LeadProof — Google Maps Email Scraper (`based_viber/leadproof`) Actor

Turn a Google Maps search into verified business emails. Crawl, extract, and verify deliverability — pay only per verified-valid contact.

- **URL**: https://apify.com/based\_viber/leadproof.md
- **Developed by:** [Danny Pfledderer](https://apify.com/based_viber) (community)
- **Categories:** Lead generation, E-commerce, Automation
- **Stats:** 2 total users, 0 monthly users, 50.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $25.00 / 1,000 verified contacts

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## LeadProof — Google Maps Email Scraper with Verified Deliverability

Paste a Google Maps search (e.g. `"dentists in Miami"`) or a list of business websites, and get back verified-deliverable contact emails. Maps scraping, site crawling, and email verification run as **one pipeline** — no separate Maps scraper to wire up first.

You pay only when we confirm the email is actually deliverable.

---

### The pricing promise

One charge per verified-deliverable contact (`verified_contact` pay-per-event). **No charge for:**

- pages crawled or businesses processed
- duplicate emails (we deduplicate per business automatically)
- emails the verifier couldn't confirm as deliverable (`risky`, `invalid`, `unknown`)
- vendor / placeholder / SaaS-tooling addresses (filtered before they reach your dataset)
- off-domain emails we couldn't confirm actually belong to the business

In plain English: if we don't confirm it's a real, deliverable email at this business, you don't pay for it.

---

### In our testing

**In one 69-business sample from Fort Lauderdale, FL** (restaurants, spas, salons, dental, local services), compared to a leading existing contact-info actor on the Apify Store:

- **~2× businesses with a found email**
- **3× verified named human contacts** (22 vs. 8)
- **~19% lower cost per verified contact**
- **0 duplicate emails per business** (vs. ~0.9 duplicates/business in the comparison)

Both tools were run on the identical business list and scored the same way; results vary by region and vertical. These numbers describe where LeadProof performs well today on the SMB segment we target — not a guarantee for every input.

---

### Where it's strongest

LeadProof is built for the **local-SMB long tail** — the segment where Google Maps has dense, useful listings and where contact emails actually live on the public website:

- Restaurants, cafes, bars
- Salons, spas, barbershops
- Dental, chiropractic, massage, wellness
- Gyms, studios, fitness
- Local trades (HVAC, plumbing, electricians, landscaping)
- Independent retail and services

We crawl the actual business site (homepage, `/contact`, `/about`, `/team`) and decode common obfuscation patterns (Cloudflare email-protection, "info [at] example") — which is where most SMB B2B contact emails actually live.

### Where it's a weaker fit

**Large professional firms** — enterprise law, big-4 accounting, top-tier consultancy, big medical groups — often gate contacts behind submission forms and don't publish email addresses publicly. LeadProof, like any email scraper, is not the right tool for that segment. We tell you upfront so you can pick the right tool for your use case instead of being disappointed.

---

### How it works

1. **Input** a Google Maps search (`"dentists in Miami"`) or a list of websites you already have.
2. **Maps search** runs against `compass/crawler-google-places` to turn queries into real businesses with names, categories, and websites.
3. **Crawl + extract.** For each business site we visit the homepage and likely contact pages, decode obfuscated addresses, and filter out SaaS/vendor/placeholder emails so they never reach your dataset.
4. **Verify.** Each remaining email runs the gauntlet — syntax → role → disposable → MX → catch-all probe → MillionVerifier API call (with retries on transient failures). Only emails confirmed deliverable trigger a charge.

---

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `searchTerms` | string[] | – | Google Maps queries, e.g. `["dentists in Miami"]`. Include city/region for accurate geolocation. |
| `startUrls` | string[] | – | Business website URLs to enrich directly. Use this when you already have a list. |
| `maxResults` | integer | 100 | Total businesses to process this run. Also caps the Maps source so you don't over-pay for places you won't use. |
| `verifierApiKey` | string (secret) | – | Optional. Bring your own MillionVerifier key — see below. |
| `maxVerifications` | integer | 1000 | Cost-guard cap on verification API calls per run. Ignored when you bring your own key. |

At least one of `searchTerms` or `startUrls` is required. Both can be supplied — Maps results are layered on top of `startUrls`.

---

### Output

Every business produces at least one dataset row, so failures never silently vanish. All rows share the same schema:

```json
{
  "business_name": "Mark Hamburger Law",
  "website": "https://markhamburgerlaw.com",
  "domain": "markhamburgerlaw.com",
  "category": "Attorney",
  "status": "ok",
  "error_detail": null,
  "email": "mark@markhamburgerlaw.com",
  "source_page": "https://markhamburgerlaw.com/contact",
  "found_via": "mailto",
  "bucket": "valid",
  "confidence": 95,
  "reason": "api_deliverable",
  "match": "same_domain",
  "role": false,
  "disposable": false,
  "mx_found": true,
  "catch_all": false,
  "charged": true
}
````

**`status`** — what happened to this business:

- `ok` — contact row; an email was extracted and verification ran
- `no_website` — business had no website to crawl (common from Maps results)
- `unreachable` — DNS / SSL / connection failure
- `http_error` — site responded but with HTTP ≥ 400 (code in `error_detail`)
- `no_emails_found` — site crawled fine but yielded no usable emails
- `verification_skipped_cap` — email was found but `maxVerifications` was reached; re-run with a higher cap or your own key

**`bucket`** — the verification verdict for contact rows:

- `valid` — confirmed deliverable → **charged**
- `risky` — catch-all domain, or off-domain valid lead — *not* charged
- `invalid` — confirmed not deliverable — not charged
- `unknown` — verifier inconclusive or transient outage — not charged

**`match`** — relationship of the email's domain to the business's website:

- `same_domain` — strongest signal (email at the business's own domain)
- `free_provider` — strong signal (gmail / yahoo / outlook etc., common for SMBs)
- `off_domain` — different domain; verified-valid off-domain leads are demoted to `risky` and not charged (wrong-owner protection)

To pull just the billable, verified contacts: `WHERE status = 'ok' AND bucket = 'valid'`.

***

### Bring your own MillionVerifier key (optional)

By default, leave `verifierApiKey` empty: LeadProof uses our verification key and the verification cost is already factored into the per-verified-contact price. No second account, no setup.

For power users who'd rather use their own MillionVerifier credits:

- Paste your key into `verifierApiKey`. It's stored as a secret — masked in the Console, never logged, never echoed into the dataset.
- The `maxVerifications` cap is automatically disabled when you supply your own key — you're paying for the credits.

***

### Tips

- **Include the city, region, or neighborhood in Maps search terms** for accurate geolocation (`"dentists in Miami Beach"`, not just `"dentists"`).
- **Mix `searchTerms` and `startUrls`** when you have both a Maps query and a hand-picked list — they're combined.
- **Re-run with a higher `maxVerifications`** if you see `verification_skipped_cap` rows — those leads were crawled but not verified yet.
- Failures get an **explanation row** in the dataset (`status` and `error_detail`), so you always know what happened — never a silent drop. The difference between "the actor returned 47 contacts" and "the actor returned 47 contacts and explained the other 23 attempts."

# Actor input Schema

## `searchTerms` (type: `array`):

Google Maps queries like "dentists in Miami". Either this or startUrls is required.

## `startUrls` (type: `array`):

Direct list of websites or domains to enrich. Either this or searchTerms is required.

## `maxResults` (type: `integer`):

Maximum number of businesses to process in this run.

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

ISO 3166-1 alpha-2 country code, lowercase (e.g. us, gb, ca, au, de) that anchors the Google Maps search region. Should match the country in your search terms — passing us while searching for "boulangeries à Paris" will give poor results. Default us.

## `verifierApiKey` (type: `string`):

Power-user option. If set, this run uses YOUR MillionVerifier credits instead of LeadProof's built-in verification, and the maxVerifications cap is disabled. Leave empty (default) to use LeadProof's key — already factored into the per-verified-contact PPE price.

## `maxVerifications` (type: `integer`):

Hard cap on verification API calls per run when using LeadProof's built-in key (cost protection). Crawled emails that exceed the cap are pushed to the dataset with status="verification\_skipped\_cap" and never charged — so no leads are lost, you just need to re-run to verify them. IGNORED when you supply your own verifierApiKey.

## Actor input object example

```json
{
  "maxResults": 25,
  "countryCode": "us",
  "maxVerifications": 1000
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("based_viber/leadproof").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("based_viber/leadproof").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 '{}' |
apify call based_viber/leadproof --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "LeadProof — Google Maps Email Scraper",
        "description": "Turn a Google Maps search into verified business emails. Crawl, extract, and verify deliverability — pay only per verified-valid contact.",
        "version": "0.0",
        "x-build-id": "ZZgrz6VzEnq5TNfn0"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/based_viber~leadproof/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-based_viber-leadproof",
                "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/based_viber~leadproof/runs": {
            "post": {
                "operationId": "runs-sync-based_viber-leadproof",
                "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/based_viber~leadproof/run-sync": {
            "post": {
                "operationId": "run-sync-based_viber-leadproof",
                "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",
                "properties": {
                    "searchTerms": {
                        "title": "Google Maps search terms",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Google Maps queries like \"dentists in Miami\". Either this or startUrls is required.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Direct list of websites or domains to enrich. Either this or searchTerms is required.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "Max results",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of businesses to process in this run.",
                        "default": 25
                    },
                    "countryCode": {
                        "title": "Country (Google Maps search region)",
                        "type": "string",
                        "description": "ISO 3166-1 alpha-2 country code, lowercase (e.g. us, gb, ca, au, de) that anchors the Google Maps search region. Should match the country in your search terms — passing us while searching for \"boulangeries à Paris\" will give poor results. Default us.",
                        "default": "us"
                    },
                    "verifierApiKey": {
                        "title": "Your MillionVerifier API key (optional)",
                        "type": "string",
                        "description": "Power-user option. If set, this run uses YOUR MillionVerifier credits instead of LeadProof's built-in verification, and the maxVerifications cap is disabled. Leave empty (default) to use LeadProof's key — already factored into the per-verified-contact PPE price."
                    },
                    "maxVerifications": {
                        "title": "Max verifications per run",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on verification API calls per run when using LeadProof's built-in key (cost protection). Crawled emails that exceed the cap are pushed to the dataset with status=\"verification_skipped_cap\" and never charged — so no leads are lost, you just need to re-run to verify them. IGNORED when you supply your own verifierApiKey.",
                        "default": 1000
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
