# Google Maps Email Extractor — Company Emails & Socials (`fabrikit/google-maps-email-extractor`) Actor

Find businesses on Google Maps and enrich each one with the company e-mails, phone numbers, WhatsApp and social profiles published on its own website. Role mailboxes only (info@, sales@...), personal addresses filtered out. No browser, no API key.

- **URL**: https://apify.com/fabrikit/google-maps-email-extractor.md
- **Developed by:** [Fabrikit](https://apify.com/fabrikit) (community)
- **Categories:** Lead generation, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 place saveds

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 Email Extractor — Company Emails, Phones & Social Profiles

**Google Maps Email Extractor finds businesses on Google Maps and pulls their contact details from their own websites**: company e-mail addresses (info@, contact@, sales@, hello@…), the phone numbers and WhatsApp the business publishes, its Facebook, Instagram, LinkedIn, X, YouTube and TikTok pages, whether the site has a contact form and which platform it runs on. Search any category in any city, region or country and get one clean lead per business, ready for a CRM or an outreach tool. No browser, no Google API key, pay per result.

It is built on our [Google Maps Places Scraper](https://apify.com/fabrikit/google-maps-places-scraper), which returns the Google Maps listing only (name, address, phone, website, rating, hours). Use that one when you do not need e-mails; use this one when you want each listing enriched with what the business website says.

### What you get

Every row has the full Google Maps listing plus these website fields:

| Field | Example | Notes |
|---|---|---|
| `emails`, `primaryEmail` | `["info@denvercrowd.com"]` | company mailboxes found on the site, most reliable first (mailto links before plain text) |
| `personalEmailsDropped` | `1` | how many person-looking addresses were left out (see Privacy) |
| `websitePhones` | `["(720) 723-1837"]` | phones published on the site (`tel:` links first; fax and suite numbers removed), up to 5 |
| `whatsapp` | `+5699…` | from `wa.me` / `api.whatsapp.com` links |
| `facebook`, `instagram`, `linkedin`, `twitter`, `youtube`, `tiktok` | `https://www.linkedin.com/company/denver-crowd/` | company pages only; LinkedIn `/in/` people profiles are never kept |
| `hasContactForm` | `true` | a message form or a known form embed (Contact Form 7, HubSpot, Typeform…) |
| `websiteTitle`, `websiteDescription`, `websiteLanguage`, `websitePlatform` | `Duda`, `WordPress`, `Wix`… | handy for agencies selling web or marketing services |
| `websiteFinalUrl`, `websitePagesCrawled`, `contactPageUrl` | `https://www.denvercrowd.com/`, `4` | what was actually read |
| `websiteCrawled`, `websiteCrawlStatus` | `true`, `ok` | `no-website`, `blocked`, `timeout`, `unreachable`, `not-html`, `social-profile`, `http-404`… when nothing could be read |

Google Maps fields: `placeId`, `cid`, `name`, `category`, `categories`, `address`, `street`, `neighborhood`, `city`, `postalCode`, `state`, `countryCode`, `lat`, `lng`, `plusCode`, `phone`, `phoneInternational`, `phoneUnformatted`, `website`, `domain`, `rating`, `reviewsCount`, `description`, `openingHours`, `permanentlyClosed`, `temporarilyClosed`, `timezone`, `imageUrl`, `googleMapsUrl`, `searchString`, `searchLocation`, `rank`, `scrapedAt`.

### Use cases

- **B2B outreach lists** — "dentists in Madrid", "roofing contractors in Texas", "hoteles en Cusco": one run gives the listing, the generic mailbox and the social pages of every business in the area.
- **Agency prospecting** — filter by `websitePlatform` (Wix, GoDaddy, no website at all) or `hasContactForm: false` to find businesses that need a better site.
- **CRM enrichment** — feed the e-mails, phones and social URLs into HubSpot, Pipedrive, Airtable or Google Sheets through the Apify integrations.
- **Market mapping** — count businesses by category, rating and digital presence (website, Instagram, WhatsApp) per neighbourhood or city.
- **AI agents** — let an assistant call this Actor through MCP to "find 20 coffee roasters in Lisbon with an e-mail".

### How to use

1. Type one or more **Search terms** (`marketing agency`, `veterinarian`) and a **Location** (`Denver, Colorado`, `Providencia, Santiago, Chile`, `Portugal`).
2. Set **Max places per search term**. Start with 10–50; the whole area is scanned tile by tile when you ask for more.
3. Leave **Read each business website for contacts** on. Optionally raise **Pages per website** (default 5: home + 4 contact-looking pages) or turn on **Save only places with an e-mail**.
4. Run it and export JSON, CSV or Excel, or read the dataset through the API.

#### Input example: e-mail leads only, Spanish-speaking market

```json
{
  "searchStrings": ["clínica dental", "centro de estética"],
  "location": "Las Condes, Santiago, Chile",
  "language": "es",
  "maxItemsPerSearch": 100,
  "onlyWithEmail": true,
  "maxPagesPerWebsite": 5
}
```

#### Input example: Google Maps data plus home page only

```json
{
  "searchStrings": ["plumber"],
  "location": "Manchester, UK",
  "maxItemsPerSearch": 200,
  "maxPagesPerWebsite": 1,
  "minRating": 4
}
```

#### Input example: listing only, no website crawl

```json
{
  "searchStrings": ["hotel"],
  "location": "Cusco, Peru",
  "maxItemsPerSearch": 300,
  "enrichWithWebsite": false
}
```

Other options: a circle (`latitude`, `longitude`, `radiusKm`) or Google Maps search URLs instead of a location, `categoryFilter`, `onlyWithPhone`, `onlyWithWebsite`, `skipClosedPlaces`, `countryCode`, `splitArea` (deep area scan) and `proxyConfiguration`.

### Output example

A real record from a local test run on 19 October 2026 (image URL shortened):

```json
{
  "placeId": "ChIJAQCpKSd5bIcRO3lEMa7ttDc",
  "name": "Crowd Digital Marketing",
  "category": "Marketing agency",
  "address": "2412 Stout St, Denver, CO 80205",
  "city": "Denver",
  "postalCode": "80205",
  "state": "Colorado",
  "countryCode": "US",
  "lat": 39.7534302,
  "lng": -104.9828704,
  "phone": "(720) 723-1837",
  "phoneUnformatted": "+17207231837",
  "website": "http://www.denvercrowd.com/",
  "domain": "denvercrowd.com",
  "rating": 4.9,
  "reviewsCount": 30,
  "openingHours": [{ "day": "Monday", "hours": "8 AM–6 PM" }, { "day": "Saturday", "hours": "Closed" }],
  "googleMapsUrl": "https://www.google.com/maps/search/?api=1&query=Crowd%20Digital%20Marketing&query_place_id=ChIJAQCpKSd5bIcRO3lEMa7ttDc",
  "emails": ["info@denvercrowd.com"],
  "primaryEmail": "info@denvercrowd.com",
  "personalEmailsDropped": 1,
  "websitePhones": ["(720) 723-1837"],
  "whatsapp": null,
  "facebook": "https://www.facebook.com/DenverCrowd",
  "instagram": "https://www.instagram.com/denvercrowd/",
  "linkedin": "https://www.linkedin.com/company/denver-crowd/",
  "twitter": null,
  "youtube": null,
  "tiktok": null,
  "hasContactForm": true,
  "websiteTitle": "Crowd Digital Marketing",
  "websiteDescription": "Our Crowd elevates website design & development for businesses, brands and non-profits…",
  "websiteLanguage": "en",
  "websitePlatform": "Duda",
  "websiteFinalUrl": "https://www.denvercrowd.com/",
  "websitePagesCrawled": 4,
  "websiteCrawled": true,
  "websiteCrawlStatus": "ok",
  "searchString": "marketing agency",
  "searchLocation": "Denver, Colorado",
  "rank": 2,
  "scrapedAt": "2026-10-19T19:36:42.386Z"
}
```

In that test (10 marketing agencies in Denver, 4 pages per site) 9 of 10 websites answered, 7 of 10 businesses came back with a company e-mail, all 9 had at least one social page, and the run took about 30 seconds. A `SUMMARY` record in the key-value store lists places, websites read, e-mails found, personal addresses dropped, proxy used and errors.

### Pricing

Pay per event, proxy included:

| Event | When it is charged |
|---|---|
| `place-result` | every place saved to the dataset |
| `website-contacts` | only places whose website answered at least one page and was read for contacts |

Duplicates, places outside the area, filtered places and websites that were down or blocked are not charged. With `onlyWithEmail` on, places without an e-mail are not saved and not charged at all. Set a maximum cost per run and the Actor stops cleanly when it is reached. See the Pricing tab for current prices; paid Apify plans get lower rates.

### How it compares

- **Google Maps scrapers "with contact details" in the Store**: this Actor returns role mailboxes only, with personal addresses filtered out by default.
- **[Google Maps Places Scraper](https://apify.com/fabrikit/google-maps-places-scraper)** (ours): same listing data, no website crawl. Pick it when you only need the Maps data.
- **Google Places API**: no e-mails or social links, needs a billing account and a key.
- **Limits**: only what the business publishes on its own website is returned. Single-page JavaScript sites that render nothing without a browser, sites behind an anti-bot wall and sites whose "website" is a Facebook page come back with `websiteCrawlStatus` explaining why (`blocked`, `social-profile`…) and without the add-on charge. In the Denver test 1 site of 19 was blocked.

### Privacy

The Actor is built for business data. E-mail addresses that look like a private person (`first.last@`, `jsmith@`, `maria@`) are detected and dropped by default (`personalEmailsDropped` tells you how many); only role and company mailboxes are kept. LinkedIn people profiles and Facebook personal profiles are never saved; reviews, reviewer names and owner accounts are not extracted. A listing named after a person (a doctor's practice, a lawyer) is still a business on Google Maps, but its personal mailboxes are filtered like any other. If you have a lawful basis to keep every address, set `excludePersonalEmails: false`. Comply with GDPR, CCPA, Chile's Ley 21.719 and anti-spam rules (CAN-SPAM, PECR) in how you contact the businesses.

### Integrations

Run it from the Apify API, the JavaScript or Python client, or on a schedule in Apify Console. Send results to n8n, Make, Zapier, Google Sheets, Airtable, HubSpot or any webhook. AI agents (Claude, ChatGPT, Cursor and other MCP clients) can discover and run it through the Apify MCP server.

### FAQ

**Is it legal to extract e-mails from Google Maps and websites?** The Actor reads public listings and public web pages, keeps company contact data and filters out personal addresses by default. Whether you may e-mail a business depends on your country's marketing laws; this is not legal advice.

**Do I need a proxy?** No setup needed. Apify datacenter proxy is used by default for Google and for the websites; Google requests switch to residential automatically if Google blocks the datacenter IPs. Websites always use the datacenter proxy: a blocked site is reported, not retried on expensive bandwidth.

**Why is `emails` empty for a business with a website?** The site publishes no address (contact form only — check `hasContactForm`), hides it behind JavaScript, or every address looked personal (`personalEmailsDropped` > 0). Raising `maxPagesPerWebsite` helps on big sites.

**How many pages does it read per site?** The home page plus up to `maxPagesPerWebsite - 1` pages whose link looks like contact, about, imprint/legal, location or support, in 15+ languages. 3–5 pages find most e-mails.

**Can it return reviews or owner names?** No. See Privacy.

**How many places can one run return?** The same as the places scraper: the area is split into tiles until Google shows nothing new, so a big city gives thousands of places per category. Each one adds a website crawl, so plan the run time accordingly (about 6 websites are read in parallel).

### Changelog

- **2026-10-19** — First version: Google Maps search with deep area scan, website crawl (home + contact-looking pages), company e-mails with personal-address filter, phones, WhatsApp, six social networks, contact form and platform detection, `onlyWithEmail` mode, two pay-per-event prices.

### En español

**Google Maps Email Extractor** busca negocios en Google Maps y completa cada ficha con los datos de contacto que la empresa publica en su propio sitio web: correos genéricos de la empresa (info@, contacto@, ventas@…), teléfonos y WhatsApp, páginas de Facebook, Instagram, LinkedIn, X, YouTube y TikTok, si tiene formulario de contacto y con qué plataforma está hecho el sitio. Sirve para armar listas B2B por rubro y ciudad ("clínica dental en Las Condes", "ferretería en Montevideo"), enriquecer un CRM o detectar negocios con sitio débil. Por defecto descarta los correos que parecen de una persona natural (nombre.apellido@, jperez@) y nunca guarda perfiles personales de LinkedIn ni reseñas, en línea con la Ley 21.719 y el RGPD. Se cobra por cada lugar guardado y por cada sitio web leído con éxito. Consulta la pestaña Pricing para ver los precios actuales; los planes de pago de Apify tienen tarifas más bajas. Si solo necesitas los datos de Google Maps sin correos, usa nuestro [Google Maps Places Scraper](https://apify.com/fabrikit/google-maps-places-scraper).

# Actor input Schema

## `searchStrings` (type: `array`):

Business types or names to look up on Google Maps, one per line, written like a Maps search (`marketing agency`, `dentist`, `roofing contractor`). Each term is searched across the whole **Location**; do not put the city here.

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

City, district, region, postal code or country (`Denver, Colorado`, `Shoreditch, London`, `28001, Spain`, `Uruguay`). The actor geocodes it and covers the area tile by tile. Leave empty to let Google choose the area.

## `maxItemsPerSearch` (type: `integer`):

Stop a search term after this many places (after filters). `0` = everything Google lists in the area. Every saved place is one `place-result` event; the website of each one is read as well when enrichment is on, so start small and scale up.

## `enrichWithWebsite` (type: `boolean`):

For every place that lists a website, fetch its home page plus a few contact / about / imprint pages and extract company e-mails, phone numbers, WhatsApp, social profiles, contact-form presence and site platform. Turn off to get Google Maps data only (no `website-contacts` charge).

## `maxPagesPerWebsite` (type: `integer`):

How many pages to read per site: the home page plus up to this many minus one contact-looking pages (`/contact`, `/about`, `/impressum`...). 3–5 finds most e-mails; 1 reads the home page only.

## `excludePersonalEmails` (type: `boolean`):

Keep company mailboxes (info@, contact@, sales@, hello@, office@, the business name...) and discard addresses shaped like a person's (`first.last@`, `maria@`, `j.smith@`). Keeps the output GDPR / Ley 21.719 friendly. Set to false to keep every address found.

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

Skip (and do not charge) places whose website showed no company e-mail. The actor keeps scanning the area until it has the requested number of places with an e-mail or runs out of places. Implies website enrichment.

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

Instead of terms + location you can paste Maps search URLs such as `https://www.google.com/maps/search/plumber/@39.7392,-104.9903,12z`; the term and the visible map area are read from the URL. `/maps/place/` URLs are not supported.

## `latitude` (type: `number`):

Search a circle around a point instead of a named location (e.g. `39.7392`). Requires longitude; overrides Location.

## `longitude` (type: `number`):

Longitude of the circle center (e.g. `-104.9903`).

## `radiusKm` (type: `number`):

Radius of the circle around latitude/longitude.

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

Skip places that have no website on Google Maps (nothing to enrich). On automatically when **Save only places with an e-mail** is on.

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

Skip places without a phone number on Google Maps.

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

Keep places rated at least this many stars (1–5). Unrated places are dropped when set.

## `categoryFilter` (type: `array`):

Keep only places whose Google category contains one of these words (accent- and case-insensitive), e.g. `agency` keeps "Marketing agency" and drops "Print shop". Use the same language as **Language**.

## `skipClosedPlaces` (type: `boolean`):

Drop businesses Google marks as permanently closed.

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

Language for Google's category names, opening hours and descriptions, and for the Accept-Language header sent to business websites.

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

Two-letter code (`us`, `cl`, `de`). Disambiguates place names shared by several countries and sets the country of the residential proxy fallback for Google requests.

## `splitArea` (type: `boolean`):

Google only lists the most prominent places of a map view; when on, dense parts of the area are split into smaller tiles and searched again until the limit is met. Turn off for one quick pass.

## `onlyInsideArea` (type: `boolean`):

Discard places that fall outside the location boundaries (Google pads result lists with neighbours).

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

Apify datacenter proxy by default, used for Google and for the business websites. If Google blocks it, Google requests move to Apify RESIDENTIAL automatically; websites always stay on this proxy (residential bandwidth would cost more than the contacts event).

## Actor input object example

```json
{
  "searchStrings": [
    "marketing agency"
  ],
  "location": "Denver, Colorado",
  "maxItemsPerSearch": 10,
  "enrichWithWebsite": true,
  "maxPagesPerWebsite": 5,
  "excludePersonalEmails": true,
  "onlyWithEmail": false,
  "radiusKm": 5,
  "onlyWithWebsite": false,
  "onlyWithPhone": false,
  "skipClosedPlaces": true,
  "language": "en",
  "countryCode": "",
  "splitArea": true,
  "onlyInsideArea": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All places saved during the run, with their website contacts

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

Counts per search, websites read, e-mails found, proxy used and errors

# 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 = {
    "searchStrings": [
        "marketing agency"
    ],
    "location": "Denver, Colorado",
    "maxItemsPerSearch": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fabrikit/google-maps-email-extractor").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 = {
    "searchStrings": ["marketing agency"],
    "location": "Denver, Colorado",
    "maxItemsPerSearch": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("fabrikit/google-maps-email-extractor").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 '{
  "searchStrings": [
    "marketing agency"
  ],
  "location": "Denver, Colorado",
  "maxItemsPerSearch": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call fabrikit/google-maps-email-extractor --silent --output-dataset

```

## MCP server setup

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

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/1x01JcoxjYHlIJBmL/builds/GUPqKuwb2zGq4QmJW/openapi.json
