# Google Maps Leads Scraper Pro (`goldenbios/my-actor-1`) Actor

Extract business leads from Google Maps with phone numbers, websites, verified emails and social profiles. Filter by rating and review count, enrich from business websites with MX-checked emails, dedupe across searches, and get a per-search summary. Built for local lead generation and outreach lists

- **URL**: https://apify.com/goldenbios/my-actor-1.md
- **Developed by:** [Goldenbios](https://apify.com/goldenbios) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 results

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/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 Leads Scraper Pro

Extract business leads from Google Maps — name, category, address, phone, website, rating, and review count for any search — **with contact enrichment included**: email addresses pulled from each business's own website (homepage and contact page), an MX deliverability check on every email domain, and social profile links. Duplicates are removed across the whole run by Place ID, and every search ends with a summary item that accounts honestly for what was found, emitted, skipped, and filtered.

Built for lead generation, local SEO prospecting, agency outreach lists, and market research: type searches like `plumber in Austin, Texas`, get a clean, deduplicated lead list with working contact channels.

### Why this actor?

|  | Google Maps Leads Scraper Pro | Typical contact-details scrapers |
| --- | --- | --- |
| Price | Flat per lead (see the Pricing tab) | $5–10 per 1,000 places, tiered by your plan |
| Email extraction | **Included** — homepage + contact page | Billed as a separate per-lead add-on |
| Email verification | **MX check included**, verdict per email | Billed per verified email |
| Social profiles | **Included** — 7 networks | Billed per profile |
| Extra event fees | **None** — no start fee, no per-email or per-social charges | Actor start fee + per-event charges stack up |
| Deduplication | **Run-wide, by Place ID** — overlapping searches never emit the same business twice | Often per-search only |
| Run summary | Per-search summary: found / emitted / duplicates / filtered + email, phone, website, social coverage | Usually absent |

### What it extracts

#### From Google Maps (no extra cost)

| Field | Description |
| --- | --- |
| `title` | Business name |
| `category` | Primary category (Plumber, Dentist, Restaurant, …) |
| `address` | Full address as listed on Maps |
| `phone` | Phone number, E.164 form when Google provides it |
| `website` | Website exactly as listed on the Maps profile |
| `rating` / `reviewsCount` | Google rating and number of reviews |
| `latitude` / `longitude` | Coordinates |
| `placeId` / `fid` | Google Place ID (ChIJ…) and feature ID — your dedup and join keys |
| `googleMapsUrl` | Canonical Maps link for the place |
| `searchedFrom` | The query or place URL that found this lead |

#### From the business website (enrichment, included)

| Field | Description |
| --- | --- |
| `emails[]` | Addresses found on the homepage and contact page — plain, `mailto:` links, and obfuscated forms (`name [at] domain [dot] com`). Each entry carries its `source` page and its `mxValid` verdict |
| `emailSource` | Where the first email was found: `website` or `contact-page` |
| `socials{}` | First profile URL per network: Facebook, Instagram, LinkedIn, Twitter/X, YouTube, TikTok, WhatsApp (share buttons are skipped, only real profiles) |

### Inputs

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `searchQueries` | string list | — | Searches in "term + location" form, e.g. `plumber in Austin, Texas`. One Maps search returns about 20 places |
| `placeUrls` | request list | — | Individual Google Maps place URLs to resolve into single leads |
| `maxPlacesPerSearch` | integer | 20 | Cap on leads taken from one search |
| `language` | string | `en` | Language code for results (`en`, `fr`, `de`, `es`, `ar`, …) |
| `region` | string | — | Optional 2-letter country code; country-targets Apify Proxy traffic |
| `minRating` | number | — | Only places at or above this rating (places with no rating are excluded when set) |
| `minReviewsCount` | integer | — | Only places with at least this many reviews |
| `onlyWithWebsite` | boolean | false | Skip places with no website |
| `onlyWithPhone` | boolean | false | Skip places with no phone number |
| `scrapeWebsiteForEmails` | boolean | true | Visit each lead's website and extract emails |
| `verifyEmailMx` | boolean | true | MX-check every extracted email's domain |
| `extractSocialLinks` | boolean | true | Extract social profile links during the website visit |
| `maxWebsitePagesPerLead` | integer | 2 | 1 = homepage only, 2 = homepage + contact page |
| `includeSummary` | boolean | true | Emit one summary item per search |
| `proxyConfiguration` | proxy | Apify Proxy RESIDENTIAL | Google blocks datacenter IPs; residential is the prepared default |

### Outputs

Three item types share one dataset, told apart by the `type` field:

- **`lead`** — one per business, fields as in the tables above.
- **`summary`** — one per search: `foundCount`, `emittedCount`, `duplicatesSkipped`, `filteredOutCount`, and coverage counters `withEmailCount`, `withPhoneCount`, `withWebsiteCount`, `withSocialsCount`, plus `stoppedReason` (`resultsExhausted`, `maxPlacesReached`, `searchFailed`).
- **`error`** — one per failed search, with the reason; if every search fails, the run itself is marked failed rather than returning an empty success.

#### `mxValid` — read it correctly

- `true` — the domain publishes MX records and accepts mail.
- `false` — the domain has no MX records; mail to it will bounce.
- `null` — verification was off, or the DNS lookup failed; **no verdict is claimed**. An MX check proves the domain accepts mail — it cannot prove an individual mailbox exists.

### Recipes

**Local trades list with emails.** Queries: `plumber in Austin, Texas`, `electrician in Austin, Texas`, `hvac in Austin, Texas`. Defaults on. Expect roughly 20 leads per query, deduplicated across all three.

**High-quality prospects only.** Add `minRating: 4`, `minReviewsCount: 50`, `onlyWithWebsite: true`. The summary's `filteredOutCount` tells you exactly how much the filters cost you.

**Wide city coverage.** The Maps backend returns about 20 places per query, so split the city: `dentist in Manhattan`, `dentist in Brooklyn`, `dentist in Queens`… Run-wide dedup makes the overlaps free.

**One known business.** Paste its Maps URL into `placeUrls` — full place URLs (with the `/place/<name>/` segment) resolve most reliably.

**Phones only, no enrichment.** Turn off `scrapeWebsiteForEmails` and `extractSocialLinks`, set `onlyWithPhone: true` — fastest, cheapest run shape.

### FAQ

**How many leads does one query return?** About 20 — that is what the Maps search backend returns per query. For more, add more specific queries (neighborhoods, adjacent towns, related terms). Dedup is run-wide, so overlapping queries never double-charge you for the same business.

**Why are some emails missing?** Emails come only from what a business publishes on its own website. Many businesses publish a contact form instead of an address — those leads simply have an empty `emails` list; the summary's `withEmailCount` shows your real coverage per search.

**What does the MX check actually prove?** That the email's domain accepts mail (MX records exist). `mxValid: false` is a hard signal the address cannot receive mail. It does not verify individual mailboxes.

**Do I pay extra for emails or socials?** No. Enrichment is included in the flat per-lead price — no per-email, per-verification, or per-profile event fees, and no actor start fee.

### Honest limits

- One search returns ~20 places; there is no cursor to page deeper into a single query. Coverage comes from more queries, not bigger caps.
- Emails and socials exist only when the business publishes them on a reachable website; a dead or script-only site yields none, and the lead still carries its full Maps data.
- `region` targets the proxy's exit country; it is not a Maps location parameter. Put the location in the query text (`term in City, State`).
- Google occasionally reshapes its payloads; the parser reads typed slots with fallbacks and emits `null` rather than guessing when a field is absent.

# Actor input Schema

## `extractSocialLinks` (type: `boolean`):

Extract social profile links (Facebook, Instagram, LinkedIn, Twitter/X, YouTube, TikTok, WhatsApp) from the business website while visiting it.

## `includeSummary` (type: `boolean`):

Emit one summary item per search: places found, emitted, duplicates skipped, filtered out, and how many emitted leads carry an email, phone, website, or social profile.

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

Language code for the results (e.g. en, fr, de, es, ar).

## `maxPlacesPerSearch` (type: `integer`):

Maximum leads taken from one search. The Maps search backend returns about 20 places per query, so values above 20 rarely add results for a single query.

## `maxWebsitePagesPerLead` (type: `integer`):

Pages fetched per lead website: 1 = homepage only, 2 = homepage plus the contact page (where most published emails live).

## `minRating` (type: `number`):

Only places with at least this Google rating (1-5). Places with no rating are excluded when this is set.

## `minReviewsCount` (type: `integer`):

Only places with at least this many Google reviews.

## `onlyWithPhone` (type: `boolean`):

Skip places that do not list a phone number.

## `onlyWithWebsite` (type: `boolean`):

Skip places that do not list a website.

## `placeUrls` (type: `array`):

Google Maps place URLs to resolve into single leads. Full place URLs (with a /place/<name>/ segment) work best; URLs carrying a feature ID (0x...:0x...) or Place ID (ChIJ...) also resolve.

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

Google blocks requests from datacenter IP addresses (HTTP 403), which is why the prepared default uses Apify Proxy residential proxies. You pay only your own run's proxy usage; traffic is small (one search call per query plus at most two small website pages per lead).

## `region` (type: `string`):

Optional 2-letter country code (e.g. US, FR, MA). When set and Apify Proxy is used, proxy traffic is country-targeted to this region so searches egress from a coherent geography.

## `scrapeWebsiteForEmails` (type: `boolean`):

Visit each lead's website and extract email addresses (including obfuscated forms like name \[at] domain \[dot] com).

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

Searches to run, in 'term + location' form, e.g. 'plumber in Austin, Texas' or 'dentist in Chicago'. Each query is one Google Maps search and returns up to about 20 places. For wider coverage, split an area into neighborhood-level queries.

## `verifyEmailMx` (type: `boolean`):

Check each extracted email's domain for MX records and record the result as mxValid (true = domain accepts mail, false = no MX records, null = could not be checked).

## Actor input object example

```json
{
  "extractSocialLinks": true,
  "includeSummary": true,
  "language": "en",
  "maxPlacesPerSearch": 20,
  "maxWebsitePagesPerLead": 2,
  "onlyWithPhone": false,
  "onlyWithWebsite": false,
  "proxyConfiguration": {
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "useApifyProxy": true
  },
  "region": "",
  "scrapeWebsiteForEmails": true,
  "searchQueries": [],
  "verifyEmailMx": true
}
```

# Actor output Schema

## `dataset` (type: `string`):

Default dataset containing lead items and per-search summary items.

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

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,goldenbios/my-actor-1"
        }
    }
}
```

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/1cPQbKEupiMJElHjL/builds/OQvIYS7d5ZehgBRnG/openapi.json
