# 📇 Google Maps Contact Scraper (`batus/google-maps-contact-scraper`) Actor

Turn any Google Maps search into a contact list. Emails, phones, websites and social profiles for every business, each with its source and confidence level.

- **URL**: https://apify.com/batus/google-maps-contact-scraper.md
- **Developed by:** [Batuhan Bahadır](https://apify.com/batus) (community)
- **Categories:** Lead generation, E-commerce, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.20 / 1,000 business processeds

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/platform/actors/running/actors-in-store#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 Contact Scraper

**Find publicly available contact details for businesses listed on Google Maps.** Give it a few search terms and a location, and it collects each business's **name, Google Maps URL, website, phone, short address, and social profiles**, then visits the business website to look for **emails 📧, more phone numbers 📞, and social links 🔗** that the business has published online.

### 🔍 What it does

Unlike a general Maps data scraper, this Actor is focused on one job: **contact discovery**. It does not collect ratings, reviews, opening hours, popular times, photos, prices, or menus. What makes it different:

- 🧾 **Transparent provenance** — every contact value carries its exact source page, extraction method, and a confidence level in `contactSources`.
- 🕵️ **Third-party detection** — heuristics separate a business's own contacts from web-agency credits ("Designed by …"), site-builder platform addresses, and generic mailboxes (`noreply@`, `webmaster@`).
- 🎯 **Efficient crawling** — stays on the business's own domain, visits only contact-relevant pages (contact, about, imprint, locations…), and skips blogs, shops, carts, and login pages.
- 🔁 **Deduplication** — a business matched by several search terms becomes one record with all matched terms listed.
- ⚡ **Fast Maps stage** — the Google Maps step reads Google's own search response over plain HTTP instead of driving a headless browser. On an 8-term / 40-business benchmark this measured **about 66% faster and about 57% cheaper per result** than the browser-driven approach it replaces, with equal or better contact coverage. A browser is still used, automatically, whenever the fast path cannot answer.

### 👥 Who is this for

- **Sales & lead generation teams** building targeted outreach lists for a niche and region.
- **Marketing agencies** enriching local-business lists with emails, phones, and social profiles.
- **Researchers & analysts** mapping the online presence of businesses in an area.
- **Business owners** auditing what contact details they expose across Maps and their website.

### 📥 What you give it

Five fields, three of which you will actually touch.

| | Field | What it does | Default |
| --- | --- | --- | --- |
| 🔍 | **Search terms** | The words you would type into Google Maps — `coffee shop`, `dentist`, `plumber`. Add several to widen the list. | — |
| 📍 | **Location** | One area per run: a city, district, region or country. | — |
| 💯 | **Max businesses per search term** | How many businesses to collect for each term. | `50` |
| 📄 | **Max pages per website** | How deep to look inside each business site, homepage included. | `5` |
| 🛡️ | **Proxy** | Automatic Apify Proxy is the cheapest and works out of the box. | Automatic |

#### 🧪 Example input

```json
{
  "searchTerms": ["specialty coffee shop", "roastery"],
  "location": "Portland, Oregon",
  "maxPlacesPerSearch": 50,
  "maxPagesPerWebsite": 5,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### 📤 What you get back

One row per business, ready for your CRM. Download as JSON, CSV, Excel or HTML.

| | Field | What it holds |
| --- | --- | --- |
| 🏢 | `businessName` | Business name from the Google Maps profile |
| 🗺️ | `googleMapsUrl` | Link to the place page on Google Maps |
| 🏷️ | `matchedSearchTerms` | Every search term this business matched |
| 📍 | `address` | Single-line address from Google Maps |
| 🌐 | `website` | Website listed on Google Maps |
| 📞 | `phones` | Phone numbers, deduplicated, E.164 where possible |
| 📧 | `emails` | Email addresses found on the business website |
| 🔗 | `socialLinks` | Facebook, Instagram, LinkedIn, X, YouTube, TikTok, WhatsApp, Telegram |
| 🔎 | `contactSources` | Where each value came from: page URL, extraction method, confidence |
| ✅ | `contactStatus` | `found` · `partial` · `none` · `not_attempted` |
| 🧭 | `websiteCrawlStatus` | `success` · `partial` · `failed` · `skipped_no_website` · `blocked_or_protected` |
| 🕒 | `scrapedAt` | When the record was produced |

#### 🎚️ Confidence levels

| | Level | What earns it |
| --- | --- | --- |
| 🟢 | **high** | `mailto:` / `tel:` links, JSON-LD or schema.org data on the business's own domain |
| 🟡 | **medium** | Meta tags, de-obfuscated "at/dot" text, decoded HTML entities, or a provider-domain address |
| ⚪ | **low** | Plain-text matches, generic mailboxes, site-builder domains, web-agency credits |

The `emails`, `phones` and `socialLinks` columns are built from 🟢 high and 🟡 medium sources. Everything else stays visible in `contactSources`.

#### 🧾 Example record

```json
{
  "businessName": "Roseline Coffee Cafe & Roastery",
  "googleMapsUrl": "https://www.google.com/maps/place/Roseline+Coffee...",
  "matchedSearchTerms": ["specialty coffee shop"],
  "address": "321 NE Davis St, Portland, OR 97232, United States",
  "website": "http://roselinecoffee.com/",
  "phones": ["+15038092890"],
  "emails": [],
  "socialLinks": {
    "facebook": ["https://facebook.com/roselinecoffee"],
    "instagram": ["https://instagram.com/roselinecoffee"],
    "linkedin": [],
    "twitter": ["https://twitter.com/roselinecoffee"],
    "youtube": [], "tiktok": [], "whatsapp": [], "telegram": []
  },
  "contactSources": [
    {
      "type": "facebook",
      "value": "https://facebook.com/roselinecoffee",
      "foundOn": "website",
      "sourceUrl": "https://roselinecoffee.com/",
      "extractionMethod": "html_anchor_link",
      "sourceDomain": "roselinecoffee.com",
      "confidence": "high"
    }
  ],
  "contactStatus": "found",
  "websiteCrawlStatus": "success",
  "scrapedAt": "2026-07-31T20:56:17.011Z"
}
```

### ⚙️ How it works under the hood

1. **Google Maps stage** — searches each term in your location and reads only the in-scope fields (name, Maps URL, website, phone, short address, social buttons) directly from Google's own search response, without driving a browser. Every response is checked for the fields it is supposed to carry; if Google changes its format, the Actor re-learns the request from a real browser session and retries, and falls back to full browser navigation if that does not resolve it.
2. **Website stage** — crawls each business website Cheerio-first (fast, cheap), staying strictly on the same domain and visiting only priority pages up to your page budget. A page is re-rendered with a headless browser only when it is client-side rendered, nearly empty, or protected by a bot challenge.
3. **Extraction layers** — mailto:/tel: links, JSON-LD, schema.org microdata, meta tags, "at/dot" de-obfuscation, HTML-entity decoding, plain-text regex, and social anchors — each tagged with its own method and confidence.

#### 🚧 Errors

Websites that cannot be crawled (timeouts, 4xx/5xx responses, bot protection, DNS errors) are recorded in a separate, run-scoped errors dataset with `businessName`, `googleMapsUrl`, `website`, `errorType`, `errorMessage`, and `timestamp`. Each run writes to its own isolated errors dataset, so runs never mix results.

### 💰 Pricing

This Actor uses **pay-per-event** pricing — you pay for results, not for compute time:

One event, `business-processed`, charged once per unique business in the results — Maps profile read, deduplicated, and its website crawled when it has one. You pay the same whether or not that business turned out to have published contact details, because the work of checking is the same either way.

| Your Apify plan | Price per 1,000 businesses |
| --- | --- |
| Free / Starter | $3.00 |
| Scale | $2.60 |
| Business | $2.20 |
| Enterprise | $1.60 – $1.05 |

Higher plans get progressively lower prices automatically — there is nothing to apply for.

**That is the whole bill.** Compute and proxy usage are covered by this Actor, not added to your invoice — the price per business is what you pay. For reference, a 1,000-business run finishes in about 30 minutes on the default settings.

To keep a first run small, start with a low `maxPlacesPerSearch`, check the output, then scale up. If you switch the proxy to RESIDENTIAL, note that it is only used for the Google Maps step.

### 💡 Tips to get more (and pay less)

- The **default automatic proxy** is the most cost-effective; only switch to **RESIDENTIAL** if Google blocks the Maps stage (few or no results).
- Lower `maxPagesPerWebsite` to reduce compute; the crawler already prioritizes contact-relevant pages.
- **The default memory (4 GB) is the sweet spot.** The Actor scales its crawling concurrency to the memory a run is given, and 4 GB is where Apify grants a full CPU core. Lowering it makes large runs disproportionately slower, because the crawler throttles itself once the CPU is saturated.
- Provide several related search terms to widen coverage; duplicate businesses are merged automatically.

### 📌 Notes

This Actor collects **publicly available** business contact details on a best-effort basis — what you get back is what each business has chosen to publish on Google Maps and its own website.

### ❓ FAQ, disclaimers & support

**What does it collect?** Only publicly available business contact information from Google Maps profiles and business websites. It does not collect ratings, reviews, opening hours, popular times, photos, prices, or menus.

**How complete is the data?** You get what each business has published on Google Maps and its own website — see Notes above.

**Legal note.** This Actor collects publicly available business contact details. You are responsible for using the data in compliance with applicable laws (including data-protection regulations such as the GDPR) and with Google's and the target websites' terms of service. This is not legal advice. Personal data should only be processed where you have a lawful basis to do so.

For questions or problems, use the **Issues** tab. Custom adjustments are possible on request.

# Actor input Schema

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

What to look for, one term per line — the same words you would type into Google Maps, e.g. "coffee shop" or "dentist". Add several related terms to widen the list; a business matched by more than one term is still returned once.

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

One area per run — a city, district, region or country, e.g. "Berlin, Germany" or "Brooklyn, New York". The more specific it is, the more focused your results.

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

How many businesses to collect for each search term. Google returns roughly 200 results per query, so higher values will not find more — add more search terms instead. Start with 10–20 to preview the output.

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

How deep to look inside each business website, counting the homepage. Only contact-relevant pages are visited (contact, about, imprint…), never blogs or shops. 3–5 finds most published details.

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

Leave this on the default automatic Apify Proxy — it is the cheapest option and works for Google Maps. Switch to RESIDENTIAL only if a run comes back with few or no results; residential bandwidth is billed per GB. When selected, it is used for Google Maps only — business websites still use the standard proxy.

## Actor input object example

```json
{
  "searchTerms": [
    "specialty coffee shop",
    "roastery"
  ],
  "location": "Portland, Oregon",
  "maxPlacesPerSearch": 50,
  "maxPagesPerWebsite": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `businesses` (type: `string`):

One record per business with its publicly available contact details.

# 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": [
        "specialty coffee shop"
    ],
    "location": "Portland, Oregon",
    "maxPlacesPerSearch": 50,
    "maxPagesPerWebsite": 5,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("batus/google-maps-contact-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 = {
    "searchTerms": ["specialty coffee shop"],
    "location": "Portland, Oregon",
    "maxPlacesPerSearch": 50,
    "maxPagesPerWebsite": 5,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "specialty coffee shop"
  ],
  "location": "Portland, Oregon",
  "maxPlacesPerSearch": 50,
  "maxPagesPerWebsite": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call batus/google-maps-contact-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=batus/google-maps-contact-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/emn8O4ufZveupZQZT/builds/jWpQbXW78qXnPs7zi/openapi.json
