# Google Maps Leads Scraper – Email & Contact Extractor (`inovaflow/google-maps-leads-scraper`) Actor

Search Google Maps by keyword and location and get enriched business leads: name, category, address, phone, rating, plus emails, phone numbers and social profiles pulled from each business website. No login, CSV & CRM ready.

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

## Pricing

from $3.00 / 1,000 leads

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

If you sell to local businesses, your best prospect list is already on Google Maps — every dentist, gym, roofer, café and law firm in a city, with a phone number and a website. What Google Maps will not give you is the **email address**. **Google Maps Leads Scraper** does: type a search the way a customer would (`dentists in Boston`), and get every business back as a ready-to-contact lead — name, category, address, phone, rating and reviews **plus the emails, phone numbers and social profiles extracted from its website**.

- **Agencies & freelancers** — build a list of every restaurant / salon / clinic in town with an email to pitch.
- **Sales teams (SDRs)** — territory prospecting by category and city, straight into your CRM.
- **Local marketers** — outreach lists for events, partnerships and directories.
- **Founders & researchers** — market maps of a niche in any city, with reachability built in.

### What does Google Maps Leads Scraper do?

It is a **Google Maps email scraper and contact extractor**: it runs your searches on Google Maps, collects the matching businesses, then visits each business website (homepage plus contact / about / imprint pages) and pulls out **email addresses, additional phone numbers and Facebook, Instagram, LinkedIn, X, YouTube, TikTok and WhatsApp links**. Every place becomes one enriched lead with a **lead score** and a **contact status**, so you can sort by "most reachable first". No Google login, no API key, no browser extension.

### Why use this Google Maps leads scraper?

- **Leads, not raw place JSON.** Emails and socials are the point — they are included in every run, not sold as add-ons.
- **Fair pricing you can predict.** A small per-lead price, and the contact enrichment fee applies **only when a website actually yielded an email or social profile**. Duplicates, filtered-out places and unreachable sites cost nothing.
- **Clean, deduplicated output.** The same business found by three searches appears once. Sponsored results are flagged.
- **Filters that save money:** only places with a website, only places with an email, minimum rating, minimum reviews, skip closed businesses.
- **CRM-ready.** Download CSV / Excel / JSON, or grab the auto-generated `LEADS.csv` — one row per lead with the primary email up front.
- **Runs anywhere.** Schedule weekly territory refreshes, call it from the API, from Zapier / Make / n8n, or from an AI agent through MCP.

### What data does it extract?

| Field | Description |
| --- | --- |
| `name`, `category`, `categories` | Business name and Google Maps categories |
| `address`, `street`, `city`, `postalCode`, `state`, `countryCode` | Structured address |
| `phone`, `phoneE164` | Phone number as shown on Maps and in international format |
| `website`, `domain` | Business website |
| `emails`, `primaryEmail` | Email addresses found on the website (same-domain, role addresses like `info@` first) |
| `phonesFromWebsite` | Additional phone numbers found on the website |
| `socials` | `facebook`, `instagram`, `linkedin`, `twitter`, `youtube`, `tiktok`, `pinterest`, `whatsapp` profile links |
| `rating`, `reviewsCount` | Google rating and number of reviews (count is returned for most places) |
| `openStatus`, `openingHours`, `permanentlyClosed`, `temporarilyClosed` | Opening information |
| `lat`, `lng`, `placeId`, `cid`, `googleMapsUrl` | Location and stable Google identifiers |
| `leadScore` | 0–100 reachability score (email, phone, website, socials, reputation) |
| `contactStatus` | `ok`, `no_contacts`, `no_website`, `unreachable` |
| `isSponsored`, `query`, `scrapedAt` | Provenance |

### How to scrape Google Maps leads with emails

1. Open the Actor and click **Try for free**.
2. Under **What to search on Google Maps** type one search per line, e.g. `plumbers in Denver`, `wedding photographers in Austin`. Or type only the trade (`plumbers`) and fill **Location** (`Denver, CO`).
3. Set **Max leads per search** (default 50). Turn on **Only leads with an email address** if you pay only for emailable leads.
4. Click **Start**. Leads stream into the **Output** tab as they are found; a 50-lead search with contact extraction takes about a minute.
5. Export as **CSV, Excel, JSON** or open `LEADS.csv` and import it into HubSpot, Pipedrive, Lemlist, Instantly or Google Sheets.

#### How to get more than 100 leads for one search

Google Maps shows roughly 100–200 results per search. To cover a whole city, split the search by neighbourhood or ZIP code (`dentists in Back Bay Boston`, `dentists in 02116`) — duplicates across searches are removed automatically.

### How much does it cost to scrape Google Maps leads?

Pay-per-event, no subscription: **$0.003 per lead delivered** plus **$0.002 when the business website yielded at least one email or social profile**, and a small run-start fee. So 1,000 fully enriched leads cost at most **$5** — and typically less, because places without contacts are charged only the base price. Places you filter out, duplicates and failed searches are free. Apify's free plan is enough for a few hundred leads a month.

### Input

Only **What to search on Google Maps** is required. Everything else has sensible defaults — see the **Input** tab. Example:

```json
{
    "searchQueries": ["dentists in Boston", "orthodontists in Boston"],
    "maxPlacesPerQuery": 100,
    "onlyWithEmail": true,
    "minRating": 4
}
```

### Output

One dataset item per business:

```json
{
    "name": "Seaport Dental Associates Boston",
    "category": "Dentist",
    "address": "451 D St #200, Boston, MA 02210",
    "city": "Boston",
    "postalCode": "02210",
    "state": "Massachusetts",
    "countryCode": "US",
    "phone": "(617) 737-6453",
    "phoneE164": "+16177376453",
    "website": "http://www.seaportdental.com/",
    "emails": ["info@seaportdental.com"],
    "primaryEmail": "info@seaportdental.com",
    "phonesFromWebsite": ["(617) 737-6453"],
    "socials": { "facebook": "https://www.facebook.com/seaportdental", "instagram": "https://www.instagram.com/seaportdental/", "linkedin": null, "twitter": null, "youtube": null, "tiktok": null, "pinterest": null, "whatsapp": null },
    "rating": 4.9,
    "reviewsCount": 812,
    "openStatus": "Open · Closes 7 PM",
    "lat": 42.3451947,
    "lng": -71.0418677,
    "placeId": "ChIJZ7rb8YN644kR7va5qlnVulk",
    "googleMapsUrl": "https://www.google.com/maps/place/?q=place_id:ChIJZ7rb8YN644kR7va5qlnVulk",
    "leadScore": 95,
    "contactStatus": "ok",
    "isSponsored": false,
    "query": "dentists in Boston"
}
```

The key-value store also holds **`LEADS.csv`** (spreadsheet / CRM import) and **`OUTPUT`** (run summary: leads delivered, with email, with any contact, filtered, duplicates).

### Tips

- **Be specific in the search.** `emergency plumber in Denver` and `plumbers in Denver` return different sets — run both and let deduplication merge them.
- **Use `onlyWithEmail` for cold email**, `onlyWithWebsite` for web-design or SEO pitches (places *without* a website are also a segment: turn `enrichContacts` off and filter `website = null` in your sheet).
- `leadScore` ≥ 60 usually means email + phone + website — start there.
- **Language / country** change how Google labels categories and formats addresses; they do not restrict where you can search.

### FAQ

#### Does it need my Google account?

No. It reads public Google Maps listings and public business websites only.

#### Where do the emails come from?

From the business's own website — `mailto:` links, contact pages, imprint/legal pages and structured data. Generic role addresses (`info@`, `office@`) are listed first; addresses from other domains (e.g. a web agency's) are kept but ranked lower.

#### Why is `reviewsCount` sometimes empty?

Google Maps occasionally returns a slimmer result set without review counts. The Actor re-fetches such pages automatically, so most leads carry the count; the rating itself is always included.

#### Can it scrape reviews or photos?

No — this Actor is optimised for lead generation. Use a dedicated Google Maps reviews scraper for that.

#### Is this legal?

Our Actors are ethical and do not extract private user data. They only extract what businesses have chosen to publish on Google Maps and on their own websites. You are responsible for complying with GDPR, CAN-SPAM and similar laws when you contact the leads; business contact information published for business purposes is generally usable for B2B outreach, but check your local rules.

### Support

Open an issue in the **Issues** tab with your run ID and the search that misbehaved. The **API** tab shows how to call this Actor from code or from any MCP-capable AI agent.

# Actor input Schema

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

One search per line, exactly as you would type it into Google Maps — e.g. `dentists in Boston`, `wedding photographers near Austin TX`, `Bäckerei Berlin Mitte`. Put the place in the query, or set "Location" below once for all of them.

## `location` (type: `string`):

A city, region or address appended to every search that does not already contain one — e.g. `Boston, MA`. Leave blank if your searches already say where.

## `maxPlacesPerQuery` (type: `integer`):

How many places to collect for each search (Google Maps typically exposes 100–200 per query). Duplicates across searches are removed automatically.

## `enrichContacts` (type: `boolean`):

Visits every business website (home + contact/about/imprint pages) and pulls out email addresses, extra phone numbers and Facebook / Instagram / LinkedIn / X / YouTube / TikTok / WhatsApp links. This is what turns a place into a lead.

## `onlyWithEmail` (type: `boolean`):

Deliver (and pay for) only places where at least one email address was found on the website.

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

Skip places that have no website listed on Google Maps.

## `minRating` (type: `integer`):

Skip places rated below this many stars (1–5). Leave empty for no minimum.

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

Skip places with fewer reviews than this. Applied when Google returns the review count for a place (it does so for most, not all).

## `skipClosed` (type: `boolean`):

Leave places that Google marks as permanently or temporarily closed out of your leads.

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

Language of Google Maps results (category names, addresses), e.g. `en`, `de`, `es`, `fr`.

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

Two-letter country code that sets Google's regional defaults (`us`, `de`, `gb`, `cz` …). Searches still find places anywhere in the world.

## `maxContactPages` (type: `integer`):

How many pages of each business website to read when extracting contacts (homepage + contact-like pages).

## `maxConcurrency` (type: `integer`):

How many Google Maps pages and business websites are fetched in parallel. Higher is faster; lower is gentler on small websites.

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

Apify datacenter proxies work well for Google Maps and are the default; switch to residential only if you see blocked requests at very high volume.

## Actor input object example

```json
{
  "searchQueries": [
    "dentists in Boston"
  ],
  "maxPlacesPerQuery": 20,
  "enrichContacts": true,
  "onlyWithEmail": false,
  "onlyWithWebsite": false,
  "skipClosed": true,
  "language": "en",
  "countryCode": "us",
  "maxContactPages": 3,
  "maxConcurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per business with Google Maps details plus emails, phones and social profiles from its website.

## `csv` (type: `string`):

Spreadsheet / CRM-ready CSV of the leads (first 5,000 rows).

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

Counts: leads delivered, with email, with any contact, filtered out, duplicates, pages fetched.

# 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 = {
    "searchQueries": [
        "dentists in Boston"
    ],
    "maxPlacesPerQuery": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/google-maps-leads-scraper").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 = {
    "searchQueries": ["dentists in Boston"],
    "maxPlacesPerQuery": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/google-maps-leads-scraper").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 '{
  "searchQueries": [
    "dentists in Boston"
  ],
  "maxPlacesPerQuery": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call inovaflow/google-maps-leads-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/MY5nQhlHZJWRRb2zX/builds/hJlAPZ9kb12oSL3PC/openapi.json
