# Google Maps Email Scraper - Leads with Verified Emails (`leadproof/google-maps-verified-leads`) Actor

Google Maps email scraper for B2B leads with SMTP-verified email addresses. Filter by review count, dedupe against your CRM export, and pay only for delivered verified leads.

- **URL**: https://apify.com/leadproof/google-maps-verified-leads.md
- **Developed by:** [Lead Proof](https://apify.com/leadproof) (community)
- **Categories:** Lead generation, Business
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $17.00 / 1,000 verified email leads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Maps Business Leads & Verified Emails

Find local businesses on Google Maps and choose how strict the contact-data requirement should be. The Actor can deliver only SMTP-verified emails, any business with a found email, a mixed list that prefers verified email and fills the rest, or fast business-only results.

**You pay only for delivered rows.** The selected delivery mode controls whether website scraping and SMTP verification are required.

### What you get

Each delivered lead:

| Field | Example |
|---|---|
| `business_name` | Summit Chiropractic & Wellness |
| `email` | drsmith@summitchiro.com, or empty in business-only fallback rows |
| `email_status` | `ok`, `catch_all`, `unverified:*`, `not_found`, `not_deliverable`, or `not_requested` |
| `delivery_tier` | `verified_email`, `email`, or `business` |
| `phone` | (208) 555-0142 |
| `website` | summitchiro.com |
| `address`, `city`, `state`, `zip` | 1234 Main St, Boise, ID 83702 |
| `rating`, `reviews` | 4.9, 187 |
| `google_maps_url`, `place_id` | direct Maps link + stable ID |

Ready for CSV export or direct CRM import.

### How to use

1. **Search terms** - the business type(s) you sell to: "dental clinic", "med spa", "HVAC contractor"…
2. **Locations** - cities or states: "Austin, Texas", "Idaho, USA"…
3. **Delivery mode** - choose the speed/quality tradeoff:
   - `verified_email_only` - original behavior; only SMTP-verified emails are delivered.
   - `email_required` - requires a scraped email but skips SMTP verification.
   - `mixed` - prefers verified email, then fills with unknown-email and business-only rows. Known invalid/disposable addresses are omitted. Catch-all addresses require `includeRisky=true` and are never marked mailbox-verified. If no checked address qualifies, the business is returned without an email.
   - `businesses_only` - fastest; returns matching Google Maps businesses without requiring email.
4. **Maximum leads** - the run stops when it delivers this many (up to 1,000 per run).
5. **Minimum reviews** - e.g. 50+ Google reviews filters for established, active businesses with buying power.
6. **Dedup (optional)** - paste emails/domains to exclude, or give a URL to your CRM's CSV export. Email/domain/phone matches are excluded when those identifiers are available.

### Why verified matters

Scraped lead lists can bounce heavily. If deliverability matters most, use `verified_email_only`: every email delivered in that tier passed a real-time SMTP mailbox check. Other modes trade some email certainty for speed and coverage, and label the result clearly in `delivery_tier` / `email_status`.

### Quality report

Every run stores a `SUMMARY` in the key-value store - how many businesses were screened and exactly why the rest were rejected:

Low-yield checks run only after a location's candidate batch finishes, so slower verification results are not discarded because no-email results arrived first. `maxPlaces` is enforced within each batch as well as across locations. `candidates_scheduled`, `candidates_processed`, and `candidates_cancelled` distinguish discovered businesses from completed checks. `exhausted` refers only to the configured queries at their bounded depth, not every business in the region.

For owner-funded searches, use `stopOnLowYield: false` with explicit `maxPlaces`, run timeout and optional `maxVerificationCostUsd` limits. The verification cap can only lower the owner's configured limit. Reaching the target or billing cap can still cancel remaining work.

Broad `restaurant(s)` / `restaurante(s)` queries require a restaurant primary category before website or email work. Hotels and retail shops returned incidentally by Maps are counted as `category_mismatch`. This conservative filter can omit a restaurant whose Maps primary category is different; it does not change other or explicitly mixed category queries.

```json
{
  "delivered": 50,
  "delivery_mode": "mixed",
  "delivered_verified_email": 18,
  "delivered_email": 12,
  "delivered_business": 20,
  "places_found": 740,
  "below_min_reviews": 213,
  "no_website": 147,
  "no_email_found": 188,
  "email_verification_failed": 74,
  "excluded_by_dedupe": 62,
  "duplicate_place": 6
}
```

You see exactly what you paid for - and what you didn't pay for.

### Pricing

Pay per delivered row. The event depends on the row's `delivery_tier`. Screened businesses that fail your filters, dedupe or verification are free.

| Event | Charged for | FREE plan | BRONZE | SILVER | GOLD and above |
|---|---|---|---|---|---|
| `verified-email-lead` | A row with an SMTP-verified email | $0.02 | $0.019 | $0.018 | $0.017 |
| `email-lead` | A row with an unverified email (`email_required` and `mixed` modes) | $0.006 | $0.006 | $0.006 | $0.006 |
| `business-lead` | A business-only row (`businesses_only` and `mixed` modes) | $0.002 | $0.0018 | $0.0016 | $0.0014 |
| Run start | Once per run | $0.00005 | $0.00005 | $0.00005 | $0.00005 |

Example: 100 verified-email leads cost $2.00 on the FREE plan and $1.70 on GOLD. Use *Maximum leads* and the run's maximum total charge to cap spend.

### FAQ

**What counts as a delivered lead?** A unique business row that satisfies the selected delivery mode and passes your filters/dedup. `delivery_tier` tells you whether the row has a verified email, an unverified email, or business data only.

**Can I get leads not already in my CRM?** Yes - that's the dedupe input. Export your contacts to CSV, host it anywhere reachable by URL (e.g. a private S3/Drive link), and the run excludes every match by email, domain, and phone.

**What are catch-all emails?** Domains that accept mail for any address - deliverability can't be confirmed mailbox-by-mailbox. They're excluded by default; enable *Include catch-all emails* to receive them (marked `catch_all`).

**How fresh is the data?** Business data is sourced live from Google Maps. Website/email enrichment, when the selected mode requires it, is also performed at run time. Nothing comes from a stale lead database.

***

*Only need email verification? Try our [Bulk Email Verifier](https://apify.com/leadproof/bulk-email-verifier) - $4.90 per 1,000 checks.*

*Prefer a finished file over running an Actor? The same engine powers our store at [leadproof.co](https://leadproof.co) - configure a list in the browser, pay per delivered lead, and get an import-ready CSV by email.*

### Owner verification setup

Verification modes use `account56/email-verifier` through the owner's secret
`VERIFIER_APIFY_TOKEN`. The direct MillionVerifier API and its credits are no longer used.
`VERIFIER_MAX_COST_USD` bounds provider spending per parent run (default $10).
Concurrent addresses are batched, duplicate addresses are cached, and provider run IDs
are persisted. Provider failures stop verification without claiming an invalid mailbox.
`email_required` and `businesses_only` do not contact the verifier or need its token.

# Actor input Schema

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

What kind of businesses to find, e.g. "dental clinic", "massage therapist", "HVAC contractor".

## `locations` (type: `array`):

Cities, regions or states to search, e.g. "Austin, Texas" or "Idaho, USA". One search per term per location.

## `deliveryMode` (type: `string`):

Choose the quality/speed tradeoff. Verified-only preserves the original behavior. Mixed prefers verified emails, then fills the requested quantity with unverified-email or business-only rows.

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

The run stops once this many results are delivered according to the selected delivery mode. You pay only for delivered rows.

## `minReviews` (type: `integer`):

Only include businesses with at least this many Google reviews — a simple proxy for active, established businesses.

## `includeRisky` (type: `boolean`):

Catch-all domains accept mail for any address. Applies to modes that run SMTP verification (Verified email only and Mixed).

## `collectLinkedin` (type: `boolean`):

Adds any LinkedIn company/profile handles the business links from its own website to each delivered row. Off = delivered columns are unchanged.

## `excludeEmails` (type: `array`):

Leads whose email appears here are skipped — paste emails from your CRM to get only NEW contacts.

## `excludeDomains` (type: `array`):

Leads whose email or website domain appears here are skipped, e.g. "acmeclinic.com".

## `dedupeCsvUrl` (type: `string`):

Public or signed URL to a CSV/TXT export. All emails, domains and phone numbers found in it are excluded from delivery.

## `concurrency` (type: `integer`):

How many candidate websites are scraped in parallel.

## `excludePlaceIds` (type: `array`):

Businesses with these Google Maps place IDs are skipped before any website is scraped. Pass the place_id column of a previous delivery to continue a search without re-checking the same businesses.

## `maxPlaces` (type: `integer`):

Hard cap on how many Google Maps results the run screens in total, across all terms and locations. The run stops with stop_reason "max_places" when it is reached. Leave empty for no cap.

## `stopOnLowYield` (type: `boolean`):

On (default): after finishing a location's candidates, the run may skip later locations when yield is low. It never cancels the current batch for low yield. Off: search all configured locations within the result, screened-business, verification and run limits.

## `maxVerificationCostUsd` (type: `number`):

Optional lower cap for owner-funded email verification. Cannot increase the owner's configured limit. Conservative reservations count against this cap. Separate from this Actor's compute and delivered-row charges.

## Actor input object example

```json
{
  "searchTerms": [
    "dental clinic"
  ],
  "locations": [
    "Boise, Idaho"
  ],
  "deliveryMode": "mixed",
  "maxLeads": 3,
  "minReviews": 5,
  "includeRisky": false,
  "collectLinkedin": false,
  "concurrency": 10,
  "stopOnLowYield": true
}
```

# Actor output Schema

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

One item per delivered business: business_name, category, email, email_status, delivery_tier, phone, website, address, city, state, zip, rating, reviews, google_maps_url, place_id.

## `leadsCsv` (type: `string`):

The same delivered leads as a CSV file, ready for a CRM or spreadsheet import.

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

How many businesses were screened and why the rest were rejected: below_min_reviews, no_website, no_email_found, email_verification_failed, excluded_by_dedupe, duplicate_place.

## `coverage` (type: `string`):

Per-stage counters for the run: places found, sites scraped, verification calls and delivered leads.

# 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 = {
    "searchTerms": [
        "dental clinic"
    ],
    "locations": [
        "Boise, Idaho"
    ],
    "deliveryMode": "mixed",
    "maxLeads": 3,
    "minReviews": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("leadproof/google-maps-verified-leads").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 = {
    "searchTerms": ["dental clinic"],
    "locations": ["Boise, Idaho"],
    "deliveryMode": "mixed",
    "maxLeads": 3,
    "minReviews": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("leadproof/google-maps-verified-leads").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "dental clinic"
  ],
  "locations": [
    "Boise, Idaho"
  ],
  "deliveryMode": "mixed",
  "maxLeads": 3,
  "minReviews": 5
}' |
apify call leadproof/google-maps-verified-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,leadproof/google-maps-verified-leads"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ma1EWOiHUcvP2LGEU/builds/9br1QaAeyC2QQtGbU/openapi.json
