# Google Maps · Emails, Phones & Socials by Search (`corent1robert/google-maps-search-scraper`) Actor

Paste business name + address. We match the Maps pin and fill phone, website, published email and socials. Never invented. No login.

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

## Pricing

from $1.05 / 1,000 place with emails

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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?

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

## Google Maps · Emails & Phones by Search

Paste **business name + street + postcode + city**. Maps matches that pin. You get **one row**: name, address, **phone**, **website**, a **published email**, and **social profiles** from the business website when they exist.

**No login. No API key. We never invent a mailbox, phone, or social URL.**

### Standby lookup (HTTP)

Console **Start** is unchanged: paste name + address lines, run, download the dataset.

Need **one Maps pin** in n8n, Make, or your own app? Use the **Standby** tab hostname. Authenticate with `Authorization: Bearer <APIFY_TOKEN>` (or `?token=`).

| Method | Path | Request | Response |
|--------|------|---------|----------|
| `GET` / `POST` | `/lookup` | `query` **or** `queries` (max **1** phrase) | `{ items, count, failed, budgetExhausted, cap }` |
| `GET` | `/` | Header `x-apify-container-server-readiness-probe` | `OK` |

Hard cap: **1 query**, **1 place row**. Website enrichment is **off** so the lookup stays under 5 minutes. Bulk scrapes and website emails belong on **Start**. Same PPE as a dataset row. First byte timeout: 5 minutes.

```bash
curl -H "Authorization: Bearer $APIFY_TOKEN" \
  --get --data-urlencode "query=Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps" \
  "https://<user>--google-maps-search-scraper.apify.actor/lookup"
```

Standby idle **60 s** (Console → Actor → Standby). Keep the 5-minute first-byte timeout.

### Who is this for?

| You are… | Typical goal | Suggested setup |
|----------|--------------|-----------------|
| Agency / CRM ops | Enrich a file you already have (name + address) | One lead per row, website crawl on |
| Local outbound / SDR | Fill phone, site, email, socials on known shops | Same: name + street + postcode + city |
| Franchise / network scout | Map a trade in one city (no address list yet) | Use [Leads by Category & City](https://apify.com/corent1robert/google-maps-city-leads)
| Market research | Count shops and see who publishes a site | Overview view, email off if you only need pins |

**What you get by default:** name, address, Maps URL, public phone and website when Maps shows them, rating when visible. On a large France sample (real-estate agencies), about **93%** of rows had a phone and **87%** a website.

**When to keep website crawl on:** Maps almost never shows an inbox or Instagram on the pin. Leave **Find email, phone and socials on the website** on to fetch a public mailbox from the company site, or from the **Facebook page** when that is the only public URL (via [Facebook Pages · Email, Phone & Website](https://apify.com/corent1robert/facebook-page-contact-scraper)). Empty `email` means none was published — we do not guess `contact@domain`.

### Quick start

**A few minutes to your first rows:**

1. Open the Actor in [Apify Console](https://console.apify.com).
2. In **Name + address**, add one business per row. Best match: *name + street + postcode + city* — e.g. *Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps*. For a trade + cities without a name list, use [Leads by Category & City](https://apify.com/corent1robert/google-maps-city-leads). **Free plan: 20 / run.**
3. Keep **Find email, phone and socials on the website** on.
4. Click **Start**. Open the Dataset while it fills.

### Ready-made examples (published tasks)

These land in the **Examples** tab once the Actor is public. Until then, copy the same inputs from `published-tasks/inputs/` in this repo.

| Example | Best for |
|---------|----------|
| Hair salon matched by name + address | First run — pin match, then phone + site + email |
| Plumbers in Lyon | Home services, emails from the website |
| Real-estate agencies in Marseille | B2B agencies, CRM emails |
| Dentists in Paris | Health / local CRM |
| Restaurants in Bordeaux | Hospitality outbound |
| Electricians in Toulouse | Second home-service city |
| Hotels in Nice | Tourism / directory check |
| Car garages in Lille | Auto trade, phones + emails |
| Pharmacies in Nantes | Retail health |
| Lawyers in Paris | Professional services |
| Lyon home services (3 trades) | Multi-search in one run |
| Paris opticians — phones only | Maps phones, no website crawl |

### What it extracts

| Category | Fields |
|----------|--------|
| Search | `searchQuery`, `rankInResults` |
| Identity | `placeName`, `category` |
| Address | `fullAddress`, `streetAddress`, `postalCode`, `city` |
| Contact | `phone`, `phoneSource`, `website`, `email`, `emailSource` |
| Social | `facebookUrl`, `instagramUrl`, `linkedinUrl`, `tiktokUrl`, `youtubeUrl`, `twitterUrl`, `whatsappUrl` |
| Maps | `mapsUrl`, `latitude`, `longitude`, `plusCode` |
| Extra | `rating`, `reviewCount`, `openingSummary`, `openingHoursDetailed`, `permanentlyClosed` |

`emailSource` is `business-website` or `facebook-page` when a mailbox was found. `phoneSource` is `maps`, `business-website`, or `facebook-page`. Social URLs and Google Maps links are **not** treated as a crawlable website — a Facebook page is sent to the Facebook contacts Actor instead.

### Input

| Field | What it does |
|-------|----------------|
| `queries` | One business per row: **name + street + postcode + city** for a pin match. Trade + city still works (up to **3** places). **Free plan: 20 / run.** |
| `enrichFromWebsite` | Look for published email, missing phone, and socials on the business website. If there is no site, read the Facebook page via the Facebook contacts Actor (default on). |

API-only: `maxPlaces` (run ceiling, **0** = no cap), `maxPlacesPerSearch` (1–3), `mapsCountry`, `placeDetailScrape` (off = list cards only), `searchConcurrency` (how many searches run at once, default **8**). Each result is opened by default. Country is inferred from the name + address (France if unclear).

#### Example — match one place (CRM enrich)

```json
{
  "queries": ["Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps"],
  "enrichFromWebsite": true
}
```

#### Example — several trades (prospecting)

```json
{
  "queries": ["Plumber Lyon", "Electrician Lyon", "Locksmith Lyon"],
  "enrichFromWebsite": true
}
```

### Output example

Real pin from the Console default (name + address). This salon has **no crawlable website** on Maps — only a Facebook page — so the mailbox and Instagram come from the Facebook contacts Actor. Never invented.

```json
{
  "searchQuery": "Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps",
  "rankInResults": 1,
  "placeName": "Un Temps Pour Pl'hair Valerie",
  "fullAddress": "25 Rue du Commandant Guilbaud, 85640 Mouchamps",
  "streetAddress": "25 Rue du Commandant Guilbaud",
  "postalCode": "85640",
  "city": "Mouchamps",
  "phone": "02 51 65 74 51",
  "phoneSource": "maps",
  "website": "https://planity.com/un-temps-pour-plhair-85640-mouchamps",
  "email": "untempspourplhair@outlook.fr",
  "emailSource": "facebook-page",
  "category": "Salon de coiffure",
  "rating": "4.9",
  "reviewCount": "28",
  "facebookUrl": "https://fr-fr.facebook.com/untempspourplhair/",
  "instagramUrl": "https://www.instagram.com/untempspourplhair",
  "mapsUrl": "https://www.google.fr/maps/place/Un+Temps+Pour+Pl'hair+Valerie/@46.7790285,-1.0629742,17z",
  "latitude": "46.7790285",
  "longitude": "-1.0629742"
}
```

Download in JSON, CSV, Excel, or HTML from the Dataset tab.

### How it works

1. Open Google Maps for the country inferred from your lines (France if unclear) and run each **name + address** (or trade + city) search — default **8** searches at once.
2. Read up to 3 places per line (each place is opened for phone + website). A precise name + address usually matches **one** pin.
3. If the place has a crawlable website and the crawl is on, fetch the homepage and contact / legal pages.
4. Keep published **email**, **phone** (only if Maps had none), and **social profile URLs**. Prefer `contact@` / `info@` over a personal name. Never invent contacts.
5. After Maps, places still without an email but with a **Facebook page** are sent in one nested run to the Facebook contacts Actor (paid runs: up to **500** pages per nested run). That Actor bills its own events. This Maps Actor needs **Console → Settings → Permissions → Full permissions** to start it.
6. Charge **place-with-email**, **place-with-phone**, or **place-without-phone**, then push the row.

A one-place trial is usually under a minute (Maps, then a Facebook Actor start when the pin has no site). Large CRM lists stay on Maps first (8 tabs); Facebook contacts run once at the end. Raise **Timeout** in Run options for files of thousands of rows (default **1 hour**).

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

Pay per saved place (plus a tiny Actor start). Maps runs in a browser, so **compute** is billed on top of PPE. **Email + socials are one event** — no $8+/1k social add-on. The higher event only fires when a **real mailbox** was found.

| Event | Free / 1k | Bronze | Silver | Gold | Platinum | Diamond |
|-------|-----------|--------|--------|------|----------|---------|
| Place with email (primary, socials included) | **$1.50** | $1.35 | $1.20 | $1.05 | $0.90 | **$0.75** |
| Place with phone, no email | $0.50 | $0.45 | $0.40 | $0.35 | $0.30 | $0.25 |
| Place without phone | $0.20 | $0.18 | $0.16 | $0.14 | $0.12 | $0.10 |
| Actor start | $0.00005 / GB | same | same | same | same | same |

When a Facebook page is used for email, the [Facebook contacts Actor](https://apify.com/corent1robert/facebook-page-contact-scraper) bills its own events on top.

| Scenario | Approx. cost (Free PPE) |
|----------|-------------------------|
| 20 places with phone only | ~$0.01 + start + compute |
| 20 places with email | ~$0.03 + start + compute |
| 1,000 places with phone | **$0.50** + start + compute |
| 1,000 places with email + socials | **$1.50** + start + compute |

A first trial (20 places, website on) is usually a few minutes after Chrome starts. Comparable Maps Actors often list **$4 / 1,000 places** on Free, then extra for contacts and **$8–10 / 1,000** for social profiles. Here those are in the same row price.

#### Is scraping Google Maps free?

On the **Apify Free plan** you get **20 places per run**. After that, upgrade — you pay per saved place (PPE) plus browser compute. No extra fee for an empty `email` beyond the phone / no-phone event.

### Is it legal to scrape Google Maps?

This Actor only reads **public** Maps results, **public** business websites, and **public** Facebook pages. Listings can contain personal data (names, phones, emails). You must have a lawful basis (GDPR / ePrivacy) for your use case — typically B2B outreach to professionals. We do not bypass logins or paid walls, and we do not invent contact details. See [Apify's guide to web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

### Limits

- **3 places per search line.** A precise **name + address** usually matches one pin. Trade + city can return up to 3. Volume = your list × results (then the Free plan 20 / run, or `maxPlaces` via API).
- **Empty `email`** means none was published on the company site **or** the Facebook page. We never guess `contact@domain`.
- **Facebook nested run:** this Actor must be allowed to run other Actors (**Full permissions**). Without that, Maps rows still save; Facebook emails stay empty.
- **Very long lists** (hundreds of rows) may switch the Console list to a JSON editor — that is an Apify Console limit. The run still accepts the array. Increase **Timeout** for thousands of rows.

### FAQ

**Why is email empty?** Maps almost never shows a mailbox on the pin. We only keep an address published on the business website or on the Facebook page. If both are empty, none was published.

**Why is `reviewCount` empty while `rating` is filled?** Maps paints the stars first, then `(28)` / `28 avis`. We wait for that number. If it stays empty, Maps did not show a count.

**Can I search outside France?** Yes. Country is inferred from the name + address (city, postcode, language). Override with API `mapsCountry` if needed.

**How do I export for CRM?** Dataset view **Outreach / CRM** — email, phone, website, Instagram, Facebook, address.

**How should I paste my file?** One lead per row: `NAME STREET POSTCODE CITY`. That is what Maps needs to match the right pin. Trade + city (`Plumber Lyon`) is for prospecting when you do not have addresses yet.

### Local development

```bash
cd google-maps-search-scraper
npm install
npm test
apify run --purge --input-file=./.actor/INPUT.json
```

Default input is in `.actor/INPUT.json` (one salon matched by name + address). Local `apify run` is **not** capped at 20. A local `output.csv` is written in the project folder (UTF-8 BOM, semicolon) for Excel.

If a large `input.json` sits in this folder, a bare `apify run --purge` **merges it** and can start thousands of searches. Always pass `--input-file=./.actor/INPUT.json` for the Console sample, or `--input-file=./input.json` only when you intend that file.

### Also available

**[Google Maps · Leads by Category & City](https://apify.com/corent1robert/google-maps-city-leads)** — trade + cities when you do not have a name list yet.

**[PagesJaunes · Email & Website Scraper from URL](https://apify.com/corent1robert/pagesjaunes-local-leads)** — French directory URLs to emails, phones and SIRET.

### Support

Contact <corentin@outreacher.fr> if you need a custom scraper or a tailored trade mapping.

# Actor input Schema

## `queries` (type: `array`):

Best match: **legal or shop name**, then **street number**, **street**, **postcode**, **city** — the same line you would type in Maps to open that pin.

**Examples:**
• Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps
• ABITHEA FRANCE 6 Boulevard Edouard Herriot 13008 Marseille

Paste a CRM list (one lead per line). Each line becomes a row. For a trade in several cities, use Google Maps · Leads by Category & City.

## `enrichFromWebsite` (type: `boolean`):

When Maps publishes a website, fetch it over HTTP(S). Keep a published mailbox (prefer contact@), fill phone only if Maps has none, and keep Facebook / Instagram / LinkedIn / TikTok / YouTube / X / WhatsApp URLs when they are on the page. If the pin has a Facebook page and still no email, we run [Facebook Pages · Email, Phone & Website](https://apify.com/corent1robert/facebook-page-contact-scraper) for a published mailbox. Never invented. Rows with an email are billed as place-with-email (the Facebook Actor bills its own events on top).

## Actor input object example

```json
{
  "queries": [
    "Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps"
  ],
  "enrichFromWebsite": true
}
```

# Actor output Schema

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

All extracted places — open or download from the Dataset tab.

## `overview` (type: `string`):

Name, city, phone, website, Maps link.

## `outreachCrm` (type: `string`):

Email, phone, website, socials for CRM import.

## `runLog` (type: `string`):

Progress lines while Maps searches run.

# 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 = {
    "queries": [
        "Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps"
    ],
    "enrichFromWebsite": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("corent1robert/google-maps-search-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 = {
    "queries": ["Un Temps pour Pl'Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps"],
    "enrichFromWebsite": True,
}

# Run the Actor and wait for it to finish
run = client.actor("corent1robert/google-maps-search-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 '{
  "queries": [
    "Un Temps pour Pl'\''Hair 25 Rue du Commandant Guilbaud 85640 Mouchamps"
  ],
  "enrichFromWebsite": true
}' |
apify call corent1robert/google-maps-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,corent1robert/google-maps-search-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/VtRKt2bPCFUO5QWEw/builds/hsCJLo9BaXBgwPG6P/openapi.json
