# Google Maps Lead Extractor with email — One-Page HTML Scraper (`christiangulloa/google-maps-lead-extractor`) Actor

Extract B2B leads including emails from Google Maps via Places API (bring your own API key) or single-page HTML. No credentials in source code.

- **URL**: https://apify.com/christiangulloa/google-maps-lead-extractor.md
- **Developed by:** [Christian G. Ulloa](https://apify.com/christiangulloa) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 1,000 actor starts

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Lead with Email Extractor

Extract structured B2B leads **with email addresses** from Google Maps using the official **Places API (New)**, or from a **single static HTML page** (JSON-LD, embedded Maps JSON, custom CSS selectors). Results are pushed to an Apify dataset.

**Unlike most Google Maps Actors published on Apify**, this Actor also scrapes **email addresses** from each business website — most competing Maps scrapers only return phone and website and leave email outreach to you.

**Credentials are never stored in code.** You provide your own [Google Cloud API key](#google-cloud-setup) in the Actor input (secret field).

***

### What does this Actor do?

Two extraction modes:

| Mode | Best for | Credentials needed |
|------|----------|-------------------|
| **Google Places API** (default) | Bulk search — `"plumbers in Austin TX"` | **Google Places API key** |
| **Single page HTML** | JSON-LD business sites, static directories | None (optional proxy) |

The Places API mode returns name, phone, website, address, category, and Google Maps URL. With **email scraping enabled**, it also fetches each business homepage and extracts the best contact email — a step most competing Maps Actors leave to you manually.

**Apify platform advantages:** secret input fields, scheduled runs, API access, proxy rotation, monitoring, CRM integrations.

***

### Google Cloud setup

**You must create your own API key.** This Actor does not ship with Google credentials.

#### Quick steps

1. [Create a Google Cloud project](https://console.cloud.google.com/projectcreate)
2. [Enable billing](https://console.cloud.google.com/billing)
3. Enable **[Places API (New)](https://console.cloud.google.com/apis/library/places.googleapis.com)**
4. Create an **[API key](https://console.cloud.google.com/apis/credentials)** under APIs & Services → Credentials
5. **Restrict the key** to Places API (New) only
6. Paste the key into the Actor input → **Google Places API key** (masked secret)

Full walkthrough with troubleshooting: **[GOOGLE\_CLOUD\_SETUP.md](./GOOGLE_CLOUD_SETUP.md)**

***

### How to use this Actor

1. Open the Actor in Apify Console.
2. Set **Extraction mode** to **Google Places API**.
3. Paste your **Google Places API key** (never commit this to git).
4. Enter a **Search query** (e.g. `coffee shops in Austin TX`).
5. Set **Max results** and run.
6. Download leads from the **Dataset** tab.

#### Local development

```bash
cd Apify/my-actor
pip install -r requirements.txt
## Edit storage/key_value_stores/default/INPUT.json — add googlePlacesApiKey
python -m my_actor
```

Or: `apify run`

***

### Input

| Field | Required | Description |
|-------|----------|-------------|
| `extractionMode` | Yes | `googlePlacesApi` or `singlePageHtml` |
| `googlePlacesApiKey` | Places mode | **Secret** — your GCP API key |
| `searchQuery` | Places mode | e.g. `"dentists in Chicago"` |
| `scrapeEmailsFromWebsites` | No | Fetch homepage email per listing |
| `startUrl` | HTML mode | Single page URL to parse |
| `maxResults` | No (default 50) | Cap on leads (max 2500) |
| `proxyConfiguration` | No | Apify Proxy (HTML mode) |
| `customSelectors` | No | CSS overrides (HTML mode) |

#### Example input (Places API)

```json
{
  "extractionMode": "googlePlacesApi",
  "googlePlacesApiKey": "YOUR_API_KEY_HERE",
  "searchQuery": "plumbers in Austin TX",
  "maxResults": 50,
  "scrapeEmailsFromWebsites": true
}
```

#### Example input (HTML mode)

```json
{
  "extractionMode": "singlePageHtml",
  "startUrl": "https://example.com/directory",
  "maxResults": 20,
  "customSelectors": {
    "item": "article.listing",
    "name": ".business-name"
  }
}
```

***

### Output

```json
{
  "name": "Joe's Plumbing",
  "category": "Plumber",
  "address": "123 Main St, Austin, TX 78701, USA",
  "phone": "+1 512-555-0100",
  "website": "https://joesplumbing.example/",
  "email": "info@joesplumbing.example",
  "rating": null,
  "reviewCount": null,
  "googleMapsUrl": "https://www.google.com/maps/place/?q=place_id:places/ChIJ...",
  "sourceUrl": "plumbers in Austin TX"
}
```

Export as JSON, CSV, or Excel from the Apify Console.

***

### Single-page HTML mode — JavaScript limitation

Google Maps **search** pages (`/maps/search/...`) load listings via **JavaScript**. HTML mode cannot execute JS and usually returns zero leads for search URLs. Use **Places API mode** for Maps bulk search, or HTML mode for place detail URLs / JSON-LD sites.

***

### Pricing / cost estimation

This Actor uses **Pay per event + usage** on the Apify Store. Full setup: **[STORE\_PRICING.md](./STORE_PRICING.md)**.

| Charge | Suggested price | Notes |
|--------|-----------------|--------|
| Actor start | ~$0.00005 / run | Platform event `apify-actor-start` |
| Lead extracted | ~$0.002 / lead | Custom event `lead-extracted` |
| Apify compute | varies | Runtime + memory |
| Google Places API | your GCP bill | BYO API key |

Set **max total charge per run** in Apify Console to cap spend.

***

### FAQ

**Where do I get an API key?** See [GOOGLE\_CLOUD\_SETUP.md](./GOOGLE_CLOUD_SETUP.md).

**Is my API key safe?** Apify marks `googlePlacesApiKey` as a secret in the input UI. Do not paste keys into public GitHub issues or README files.

**Can I use the local CLI instead?** Yes — `localScraper/extract.py` with `export PLACES_API_KEY=...`.

***

### License and responsibility

Comply with [Google Maps Platform Terms](https://cloud.google.com/maps-platform/terms) and applicable privacy/telemarketing laws.

# Actor input Schema

## `extractionMode` (type: `string`):

Use Google Places API for bulk business search by category and location. Use single-page HTML for JSON-LD business sites or static directory pages.

## `googlePlacesApiKey` (type: `string`):

Your Google Maps Platform API key. Stored as a secret in Apify Console — never hard-coded in this Actor.

## `searchQuery` (type: `string`):

Free-text Google Maps search (Places API Text Search). Examples: "plumbers in Austin TX", "dentists 90210".

## `scrapeEmailsFromWebsites` (type: `boolean`):

Fetches each listing's website and extracts a contact email (JSON-LD, mailto, obfuscated patterns). Most Google Maps Actors on Apify do not include email — this is the key differentiator. Adds one HTTP request per business with a website.

## `startUrl` (type: `string`):

The single page URL to fetch and parse (JSON-LD, embedded Maps JSON, or custom CSS selectors).

## `maxResults` (type: `integer`):

Maximum number of lead records to return.

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

Optional Apify Proxy (mainly used in single-page HTML mode to reduce blocking).

## `customSelectors` (type: `object`):

Optional CSS selector overrides for single-page HTML mode. Keys: item, name, category, address, phone, website, email, rating, reviewCount, link.

## Actor input object example

```json
{
  "extractionMode": "googlePlacesApi",
  "searchQuery": "coffee shops in Austin TX",
  "scrapeEmailsFromWebsites": true,
  "startUrl": "https://www.google.com/maps/place/Starbucks/@30.2672,-97.7431,17z",
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "searchQuery": "coffee shops in Austin TX",
    "startUrl": "https://www.google.com/maps/place/Starbucks/@30.2672,-97.7431,17z",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("christiangulloa/google-maps-lead-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 = {
    "searchQuery": "coffee shops in Austin TX",
    "startUrl": "https://www.google.com/maps/place/Starbucks/@30.2672,-97.7431,17z",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("christiangulloa/google-maps-lead-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 '{
  "searchQuery": "coffee shops in Austin TX",
  "startUrl": "https://www.google.com/maps/place/Starbucks/@30.2672,-97.7431,17z",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call christiangulloa/google-maps-lead-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,christiangulloa/google-maps-lead-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/XXKTGLSooqmE8mrvG/builds/1IZ7ttor1wTFysrQT/openapi.json
