# Elite Google Maps Scraper – Fast, Smart Filtering, Cost Control (`datasiphon/elite-gmaps-scraper`) Actor

High-performance Google Maps scraper with pre-filtered search queries, adaptive concurrency, cost estimator, delta mode, and optional email/social enrichment. Reduces runs 40-60% vs Compass actor.

- **URL**: https://apify.com/datasiphon/elite-gmaps-scraper.md
- **Developed by:** [Kashif Ali](https://apify.com/datasiphon) (community)
- **Categories:** Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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 Scraper — Verified Emails, Incremental Mode, CRM Export

**The only Google Maps scraper with email verification, delta/incremental tracking, and one-click CRM export built in.** No API keys, no integrations, no separate enrichment tools.

### Why this scraper?

| Feature | What it means for you |
|---------|----------------------|
| **Email verification built-in** | DNS MX lookup confirms every email can receive mail. Flag or auto-filter disposable/invalid addresses. No bounced emails. |
| **Incremental / delta mode** | Run weekly. Only get new listings. Tracks previously seen places via KV store. No re-scraping the same data. |
| **One-click CRM export** | Pre-formatted rows for HubSpot, Salesforce, or Pipedrive. Download as CSV and import directly. |
| **Email extraction included** | 5 methods (mailto, HTML entities, CloudFlare decoding, JSON-LD, obfuscated patterns). No add-on fees. |
| **No duplicate rows** | Same business across overlapping queries? Deduped automatically. |
| **Clean URLs** | All `utm_*` and tracking parameters stripped from website URLs. |
| **Validated contacts** | TLD whitelist + email format validation + disposable domain rejection. |

### New in v2.0

- **Email verification** — DNS MX lookup checks if each email's domain can receive mail. Mode: flag (mark deliverability) or filter (remove bad emails).
- **Incremental / delta mode** — "New Only" returns only places you haven't seen before. "Flag" marks new vs known on every row. State stored in Apify KV between runs.
- **CRM export** — Select HubSpot, Salesforce, or Pipedrive format. Each row includes `_crmHeaders` and `_crmRow` for one-click CSV import.

### What you can extract

| Field | Description |
|-------|-------------|
| `name` | Business name |
| `address` | Full street address |
| `phone` | Phone number |
| `website` | Business website (UTMs stripped) |
| `emails` | Email addresses from business website |
| `websiteDomain` | Domain extracted from website URL |
| `emailSource` | How the email was found (mailto, jsonld, html, cloudflare) |
| `emailVerification` | Deliverability check result |
| `rating` | Star rating (1.0–5.0) |
| `reviewCount` | Number of reviews |
| `category` | Business category (Plumber, Restaurant, etc.) |
| `coordinates` | Latitude, longitude |
| `hours` | Opening hours by day |
| `placeUrl` | Google Maps place page link |
| `scrapedAt` | ISO timestamp of scrape |
| `_isNew` | Whether listing is new (incremental mode) |
| `_crmRow` | Pre-formatted CRM import row |

### Use cases

- **Local lead generation** — build lists of verified-contacted local businesses
- **Weekly competitor monitoring** — incremental mode catches new businesses in your market
- **CRM pipeline seeding** — export directly to HubSpot/Salesforce/Pipedrive format
- **Market research** — analyze business density and categories by location
- **Real estate / site selection** — understand competitive landscape before opening

### How pricing works

This actor uses **pay-per-event** pricing on the Apify platform:

- **Free tier**: $5/month free compute credits included with every Apify account
- **Emails disabled**: ~1–2 compute units per 100 listings
- **Emails enabled**: ~3–5 compute units per 100 listings
- **Email verification**: adds ~0.1 CU per 100 listings (DNS lookups are fast)
- **Incremental mode**: negligible cost (KV store reads/writes)
- **Typical free-tier capacity**: 500–2,000 listings per month at no cost

No hidden fees. Email verification and incremental mode are included at no extra charge.

### Quick start

1. **Enter queries** — `plumbers in Austin, TX`, `coffee shops San Francisco`
2. **Toggle features** — enable email verification, incremental mode, or CRM format
3. **Set limits** — max results up to 500, concurrency 1–20
4. **Run** — results appear as JSON, CSV, HTML, or Excel

### Input fields

| Field | Default | Description |
|-------|---------|-------------|
| `searchQueries` | — | Search terms on Google Maps (array, required) |
| `maxResults` | 50 | Total listings across ALL queries (1–500) |
| `extractEmails` | true | Visit websites to extract emails |
| `verifyEmails` | off | `off` / `flag` (mark status) / `filter` (remove bad) |
| `incrementalMode` | off | `off` / `flag` (mark new) / `new-only` (only new) |
| `crmFormat` | none | `none` / `hubspot` / `salesforce` / `pipedrive` |
| `extractPhone` | true | Extract phone numbers |
| `extractWebsite` | true | Extract website URLs |
| `extractRating` | true | Extract star rating + review count |
| `extractCoordinates` | true | Extract lat/lng coordinates |
| `extractCategory` | true | Extract business category |
| `extractHours` | false | Extract opening hours |
| `maxConcurrency` | 3 | Parallel pages (1–20) |
| `proxyCountry` | auto | ISO country code for geo-targeting |
| `domain` | google.com | Custom Google domain |

### Sample output

```json
{
  "query": "plumbers in Austin, TX",
  "name": "Austin Plumbing Co",
  "address": "123 Main St, Austin, TX 78701",
  "phone": "+1 512-555-0123",
  "website": "https://www.austinplumbing.com",
  "websiteDomain": "austinplumbing.com",
  "category": "Plumber",
  "rating": 4.5,
  "reviewCount": 127,
  "coordinates": "30.2672, -97.7431",
  "hours": ["Monday: 8:00 AM – 5:00 PM", "Tuesday: 8:00 AM – 5:00 PM"],
  "emails": ["contact@austinplumbing.com"],
  "emailSource": "jsonld+html",
  "emailVerification": "filtered",
  "_isNew": true,
  "_crmRow": "\"Austin Plumbing Co\",\"+1 512-555-0123\",\"https://www.austinplumbing.com\",\"contact@austinplumbing.com\",\"123 Main St, Austin, TX 78701\",\"Plumber\",4.5,127",
  "placeUrl": "https://www.google.com/maps/place/...",
  "scrapedAt": "2026-05-20T12:00:00.000Z"
}
```

### Tips

- **Incremental mode is per-actor** — state is stored in your Apify KV store. Different API tokens have separate state.
- **Email filter mode removes bad emails** — use `verifyEmails: filter` when pushing to your CRM to avoid bounces.
- **CRM export** — download results as CSV. Every row has `_crmHeaders` (copy once as header) and `_crmRow`. Paste into your CRM's import tool.
- **Email extraction costs compute** — each website is fetched via HTTP. Disable for faster runs if you only need listings.
- **Overlapping queries are safe** — dedup handles them automatically.

### FAQ

#### Is scraping Google Maps legal?

Web scraping publicly available data is a well-established practice. Review Google's ToS and consult your legal team.

#### How is email verification different from email extraction?

- **Extraction** finds emails on business websites (always included).
- **Verification** checks if those email domains can receive mail via DNS MX lookup (optional, toggle on/off).

#### Does incremental mode work across different Apify users?

No. State is stored per API token in your private Apify KV store.

#### Can I scrape more than 500 results per query?

Input limit is 500. For larger datasets, run multiple queries with different keywords or location splits.

#### How is this different from compass/crawler-google-places?

| Feature | compass | This scraper |
|---------|---------|-------------|
| Email verification | $2/1K add-on | Included (DNS MX) |
| Delta / incremental | Not available | Included (KV store) |
| CRM-ready export | Not available | HubSpot/SF/Pipedrive |
| Email extraction | $2/1K add-on | Included |
| Deduplication | Not available | Included |
| UTM stripping | Not available | Included |
| TLD validation | Not available | Included |

### Support

Report issues or request features on the [Issues tab](https://github.com/your-repo/gmaps-scraper/issues). Access results programmatically via Apify's API tab.

> **Disclaimer:** This Actor extracts only publicly available information from Google Maps and linked business websites. Results may contain personal data protected by GDPR and other regulations. Ensure you have a legitimate basis for scraping before use.

# Actor input Schema

## `searchStringsArray` (type: `array`):

List of search terms to query on Google Maps (e.g. "concrete contractor"). Each runs independently and results are deduplicated across all terms.

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

Paste Google Maps URLs directly (place pages, saved lists, search-result links, goo.gl/maps short links) to scrape them as-is instead of building a search from terms + location. Matches Compass's startUrls feature. Max ~300 results per URL (same feed-scroll cap as a search).

## `locationArray` (type: `array`):

List of locations (city, state, country). Cross-joined with search terms. Example: \["Austin, TX", "Dallas, TX"]. Leave empty if locations are embedded in search strings.

## `locationCountries` (type: `array`):

Pick one or more countries to search in a single run. Cross-joined with states/cities/zips/search terms below. Real dropdown (copied from Google's own country list) instead of the old free-text field, and multi-select instead of one-country-per-run.

## `locationStates` (type: `array`):

Pick one or more US states/territories to search in a single run. For non-US regions/provinces, use the free-text "Location - Other Regions" field instead (state/province names outside the US aren't a fixed enumerable list the way US states are).

## `locationRegions` (type: `array`):

Free-text state/province/region names for non-US searches (no fixed dropdown list exists globally). Add as many as you want - cross-joined the same way as US States.

## `locationCities` (type: `array`):

Add as many cities as you want to search in one run - cross-joined with countries/states/zips/search terms. No fixed dropdown (cities aren't a small enumerable list globally), but genuinely multi-value now instead of the old single-city field.

## `locationZips` (type: `array`):

Add as many postal/ZIP codes as you want to search in one run.

## `locationLat` (type: `string`):

Latitude for coordinate-based searches (e.g. "41.7727"). Not used in URL — advisory only.

## `locationLng` (type: `string`):

Longitude for coordinate-based searches (e.g. "-88.1467"). Not used in URL — advisory only.

## `maxCrawledPlacesPerSearch` (type: `integer`):

Maximum places to extract per search term.

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

Language for Google Maps UI and results.

## `minRating` (type: `string`):

Filter places by minimum average rating.

## `websiteSelection` (type: `string`):

Pre-filter at search query level. Post-filter applied automatically for accuracy.

## `excludeWebsites` (type: `boolean`):

Skip businesses that have a website. Applied after scraping (post-filter).

## `unclaimedOnly` (type: `boolean`):

Only return businesses that have NOT claimed their Google Maps listing.

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

Exclude permanently or temporarily closed businesses.

## `selectedCategories` (type: `array`):

Pick one or more Google Business categories to search directly (used as search terms when Search Terms above is empty; combined with Search Terms otherwise). Same category list as before (4,000+ categories), now multi-select instead of one-category-per-run.

## `fullAddress` (type: `boolean`):

Navigate each place's detail page to get full address breakdown (street, city, state, zip, country). Adds ~4s per place. When disabled, only the street address from search results is returned.

## `searchMatching` (type: `string`):

Control how search results are matched.

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

Maximum parallel browser contexts. Higher = faster but more memory. Capped at 7.

## `maxCostUsd` (type: `number`):

Abort run if estimated cost exceeds this. 0 = unlimited.

## `extractEmails` (type: `boolean`):

Visit each business website and attempt to extract email addresses.

## `verifyEmails` (type: `string`):

Verify extracted emails via DNS MX lookup.

## `enrichSocialMedia` (type: `object`):

Scrape detailed profile data from discovered social links.

## `extractLeads` (type: `object`):

Extract employee leads from company website.

## `maxReviews` (type: `integer`):

Maximum reviews to extract per place

## `reviewsSort` (type: `string`):

Sort order for reviews (mostRelevant, newest, highestRating, lowestRating)

## `reviewsStartDate` (type: `string`):

Either an absolute date (e.g. 2026-06-01) or a relative date from now (e.g. "30 days", "3 months"). Reviews older than this are dropped after scraping. Leave empty to keep every scraped review. Only meaningful when Max Reviews Per Place is set above 0.

## `maxImages` (type: `integer`):

Maximum images to extract per place

## `incrementalMode` (type: `string`):

Track previously scraped places using Apify KV store.

## `crmFormat` (type: `string`):

CRM export format (json or csv)

## Actor input object example

```json
{
  "searchStringsArray": [],
  "startUrls": [],
  "locationArray": [],
  "locationCountries": [],
  "locationStates": [],
  "locationRegions": [],
  "locationCities": [],
  "locationZips": [],
  "locationLat": "",
  "locationLng": "",
  "maxCrawledPlacesPerSearch": 120,
  "language": "en",
  "minRating": "any",
  "websiteSelection": "all",
  "excludeWebsites": false,
  "unclaimedOnly": false,
  "skipClosedPlaces": true,
  "selectedCategories": [],
  "fullAddress": false,
  "searchMatching": "all",
  "maxConcurrency": 5,
  "maxCostUsd": 0,
  "extractEmails": false,
  "verifyEmails": "off",
  "maxReviews": 0,
  "reviewsSort": "newest",
  "reviewsStartDate": "",
  "maxImages": 0,
  "incrementalMode": "off",
  "crmFormat": "none"
}
```

# Actor output Schema

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

Dataset containing all scraped Google Maps listings

# 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 = {
    "searchStringsArray": [],
    "locationArray": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("datasiphon/elite-gmaps-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 = {
    "searchStringsArray": [],
    "locationArray": [],
}

# Run the Actor and wait for it to finish
run = client.actor("datasiphon/elite-gmaps-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 '{
  "searchStringsArray": [],
  "locationArray": []
}' |
apify call datasiphon/elite-gmaps-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datasiphon/elite-gmaps-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/29EXnzkfATUF1M5LI/builds/p5U0uNKrPCpiAZIpd/openapi.json
