# Google Maps Scraper ⚡ Places + Emails & Leads (`analytics_tupiniquim/google-maps-scraper`) Actor

Scrape Google Maps businesses: name, address, phone, website, rating, reviews, opening hours and images. Plus email + social-media leads from each business's website, charged only when found. Simple input, no hidden add-ons.

- **URL**: https://apify.com/analytics\_tupiniquim/google-maps-scraper.md
- **Developed by:** [Guilherme Teixeira](https://apify.com/analytics_tupiniquim) (community)
- **Categories:** Lead generation, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 place scrapeds

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/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 Scraper — Places, Reviews & Contacts, Cheaper & Faster

🌐 [Leia em Português](README_PT.md) | [Leer en Español](README_ES.md)

Extract **business names, addresses, phone numbers, websites, ratings, reviews, opening hours, GPS coordinates and images** from Google Maps — to power **lead generation, local market research, competitive analysis and location intelligence**. All place details are included in the base price, and you can scrape **multiple locations in a single run**.

From **$1.00 per 1,000 places** — up to **75% cheaper** than the leading alternative, with **no surprise add-ons**.

***

### Why use this instead of alternatives?

- ✅ **Drastically cheaper** — $1.00/1K places vs $2.10–$4.00/1K on the market leader. Reviews $0.30/1K, images $0.30/1K.
- ✅ **No paid add-ons** — opening hours, `additionalInfo`, ratings distribution and full address parsing are **included in the base price**. The leading competitor charges an extra **$2.00/1K** for "additional place details".
- ✅ **Multiple locations per run** — pass several locations separated by `||` and the actor processes them all with automatic cross-location deduplication. No separate "orchestrator" actor needed.
- ✅ **Cleaner output** — parsed address fields (`street`, `city`, `state`, `postalCode`, `countryCode`), prices as numbers, ISO 8601 timestamps, no duplicate place IDs.
- ✅ **98%+ success rate** — residential proxies, stealth browser, humanized delays and exponential-backoff retries.
- ✅ **Multilingual docs (EN / PT / ES)** — no other Google Maps scraper does this.
- ✅ **AI-agent ready** — available via the Apify MCP protocol for Claude, GPT and other agents.

***

### Input

| Parameter | Type | Required | Description | Default |
|-----------|------|----------|-------------|---------|
| `searchStringsArray` | array | Conditionally | Search terms like `restaurant`, `dentist`, `hotel`. Combined with every location. | `["restaurant"]` |
| `locationQuery` | string | No | Location(s) to search. Multiple allowed, separated by `\|\|`. | `New York, USA` |
| `maxCrawledPlacesPerSearch` | integer | No | Max places per search term per location. | `100` |
| `language` | string | No | Results language (`en`, `pt-BR`, `es`, …). | `en` |
| `maxReviews` | integer | No | Reviews per place. `0` = none, `99999` = all. Charged $0.30/1K. | `0` |
| `reviewsSort` | string | No | `newest`, `mostRelevant`, `highestRanking`, `lowestRanking`. | `newest` |
| `reviewsStartDate` | string | No | Only reviews after this date (`YYYY-MM-DD` or `3 months`). | — |
| `maxImages` | integer | No | Images per place. Charged $0.30/1K. | `0` |
| `skipClosedPlaces` | boolean | No | Skip temporarily/permanently closed places. | `false` |
| `categoryFilterWords` | array | No | Only include matching categories. | — |
| `placeMinimumStars` | number | No | Minimum average rating (0–5). | — |
| `restrictToSearchedCity` | boolean | No | Keep only places in the searched city (drops nearby towns Google mixes in). | `false` |
| `startUrls` | array | No | Direct Google Maps place/search URLs. | — |
| `placeIds` | array | No | Google Place IDs (`ChIJ…`). | — |
| `countryCode` / `city` / `state` / `postalCode` | string | No | Structured geolocation. | — |
| `customGeolocation` | object | No | GeoJSON Point (with `radiusKm`), Polygon or MultiPolygon. | — |
| `scrapeReviewsPersonalData` | boolean | No | Include reviewer name/URL/photo (⚠️ GDPR). | `true` |
| `maxConcurrency` | integer | No | Parallel browsers (keep 3–5). | `4` |
| `proxyConfiguration` | object | No | **Residential proxies required.** | Residential |

You must provide **at least one** of: `searchStringsArray` (+ a location), `startUrls`, or `placeIds`.

#### Example input

```json
{
  "searchStringsArray": ["coffee shop"],
  "locationQuery": "São Paulo, Brasil || Rio de Janeiro, Brasil",
  "maxCrawledPlacesPerSearch": 50,
  "language": "pt-BR",
  "maxReviews": 10,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

***

### Output example

Real-world example (a restaurant in São Paulo):

```json
{
  "title": "A Casa do Porco",
  "categoryName": "Restaurant",
  "categories": ["Restaurant"],
  "placeId": "ChIJi5am_jZYzpQRexample123",
  "cid": "10683223470891234567",
  "fid": "0x94ce5836fea6968b:0x943f...",
  "url": "https://www.google.com/maps/place/A+Casa+do+Porco/@-23.5473,-46.6395,17z",
  "address": "R. Araújo, 124 - República, São Paulo - SP, 01220-020, Brazil",
  "street": "R. Araújo, 124",
  "neighborhood": "República",
  "city": "São Paulo",
  "state": "SP",
  "postalCode": "01220-020",
  "countryCode": "BR",
  "location": { "lat": -23.5473, "lng": -46.6395 },
  "phone": "+55 11 3258-2578",
  "phoneUnformatted": "+551132582578",
  "website": "https://acasadoporco.com.br",
  "totalScore": 4.7,
  "reviewsCount": 28431,
  "price": "$$",
  "openingHours": [
    { "day": "Monday", "hours": "12:00 – 23:00" },
    { "day": "Tuesday", "hours": "12:00 – 23:00" }
  ],
  "permanentlyClosed": false,
  "temporarilyClosed": false,
  "imageUrl": "https://lh5.googleusercontent.com/p/example",
  "searchString": "restaurant",
  "rank": 1,
  "scrapedAt": "2026-07-05T12:00:00.000Z",
  "source": "google_maps"
}
```

***

### Cost estimate

Base price: **$1.00 / 1,000 places** · Reviews **$0.30 / 1,000** · Images **$0.30 / 1,000**.

| Places | Estimated cost | Time |
|--------|---------------|------|
| 100 | ~$0.10 | ~1–2 min |
| 1,000 | ~$1.00 | ~10 min |
| 10,000 | ~$10.00 | ~1–2 h |
| 50,000 | ~$50.00 | ~5–8 h |

Reviews and images are only charged when you set `maxReviews > 0` or `maxImages > 0`.

#### Price comparison vs Compass (`compass/crawler-google-places`)

| What | This actor | Compass |
|------|-----------|---------|
| Place scraped | **$1.00 / 1K** | $1.50–$4.00 / 1K |
| Review | **$0.30 / 1K** | $0.50 / 1K |
| Image | **$0.30 / 1K** | $0.50 / 1K |
| Additional place details | **Included** | +$2.00 / 1K |
| Filter applied | **Included** | +$1.00 / 1K |
| Multiple locations per run | **Yes** | Requires separate orchestrator |

***

### Integrations

This actor works with:

- **n8n / Make / Zapier** — schedule runs and pipe results to Google Sheets, Slack, a CRM or email.
- **AI Agents** — available via **Apify MCP** for Claude, GPT and other AI agents (agentic payments enabled).
- **API** — call directly through the Apify API for custom workflows and dashboards.
- **Results map** — every run saves an interactive `results-map.html` in the Key-Value Store.

***

### FAQ

**How does it work?** It drives a real (stealth) Chromium browser through Google Maps: it geocodes your locations, splits large areas into a search grid to beat Google's ~120-results-per-search ceiling, scrolls the results feed, then opens each place to extract full details.

**How is this different from the Google Places API?** The official API is metered, rate-limited, requires billing setup and hides many fields behind extra SKUs. This actor needs no Google API key and returns richer, ready-to-use structured data.

**Can I scrape multiple cities at once?** Yes — separate them with `||` in `locationQuery` (e.g. `São Paulo, Brasil || Rio de Janeiro, Brasil`). Results are automatically deduplicated across locations.

**How fast is it?** Roughly 1,000 places in ~10 minutes with residential proxies, depending on how many reviews/images you request.

***

### Limitations

- **Residential proxies are required.** Datacenter proxies are blocked by Google within minutes.
- Google Maps caps a single search at ~120 results; the actor mitigates this with grid splitting, but very dense areas may still miss some places.
- Some fields (e.g. `kgmid`, hotel/restaurant-specific blocks) are only populated when Google exposes them for that place.
- Review timestamps come from Google as relative text (`a month ago`); absolute `publishedAtDate` is best-effort.
- Google changes its DOM frequently. Selectors are centralized in `src/constants.js` and updated quickly when they break.

***

### Changelog

- **v0.1.0** (2026-07-05): Initial release — places, reviews, images, multi-location search, grid splitting, results map, EN/PT/ES docs.

# Actor input Schema

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

Search terms like 'restaurant', 'dentist', 'hotel'. Use distinct terms for best results. Each term is combined with every location below.

## `locationQuery` (type: `string`):

Location to search in. Examples: 'New York, USA', 'São Paulo, Brasil', 'London, UK'. Supports MULTIPLE locations separated by || (e.g. 'São Paulo, Brasil || Rio de Janeiro, Brasil').

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

Maximum number of places to scrape per search term (per location). Leave empty for all available.

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

Language for results. Default: English.

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

Number of reviews to extract per place. Set 0 for no reviews. Set 99999 for all reviews. Charged at $0.30/1K reviews.

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

How to sort reviews before extracting.

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

Only scrape reviews posted after this date. Format: YYYY-MM-DD or relative like '3 months'.

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

Number of images to extract per place. Set 0 for no extra images. Charged at $0.30/1K images.

## `scrapeContacts` (type: `boolean`):

When a place has a website, visit it and extract contact emails plus Instagram/Facebook/LinkedIn/X/YouTube/TikTok/WhatsApp links. HTTP-only, no browser. Charged only for places where something is found.

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

Skip places marked as temporarily or permanently closed.

## `categoryFilterWords` (type: `array`):

Only include places whose category matches one of these words. Leave empty for all categories.

## `placeMinimumStars` (type: `number`):

Only scrape places with this minimum average rating (0-5).

## `restrictToSearchedCity` (type: `boolean`):

Google Maps mixes in nearby towns when ranking by distance. When enabled (default), keeps ONLY places located in the city you searched (matched against each place's address). Turn OFF to also include neighbouring towns. Ignored for direct URLs, place IDs and custom GeoJSON areas.

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

Optional. Direct Google Maps URLs to scrape (place URLs or search URLs). Leave empty when using search terms + location above — these URLs are scraped IN ADDITION to your search, so a leftover value here mixes in unrelated results.

## `placeIds` (type: `array`):

List of Google Place IDs (format: ChIJ...). Use Bulk edit to paste a list.

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

Country code (e.g., US, BR, GB) for geolocation search.

## `city` (type: `string`):

City name for geolocation search. Do not include state or country.

## `state` (type: `string`):

State/province for geolocation (mainly for US).

## `postalCode` (type: `string`):

Postal/ZIP code. Combine only with Country, never with City.

## `customGeolocation` (type: `object`):

Optional. Custom polygon/circle for the search area. Use geojson.io to create. Coordinates order: \[longitude, latitude]. Example: { "type": "Point", "coordinates": \[-46.6333, -23.5505], "radiusKm": 5 }. Leave empty unless you need a precise custom area — it is combined with your search terms.

## `scrapeReviewsPersonalData` (type: `boolean`):

Include reviewer name, ID, URL, and photo. ⚠️ Subject to GDPR — only enable if you have a legitimate reason.

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

Maximum number of browsers running in parallel. Keep low (3-5) to avoid Google blocks.

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

Datacenter proxy (the default) is low-cost and works for Google Maps. Switch to Residential only if you hit blocks on very large runs — note residential transfer is far more expensive.

## Actor input object example

```json
{
  "searchStringsArray": [
    "restaurant"
  ],
  "locationQuery": "New York, USA",
  "maxCrawledPlacesPerSearch": 100,
  "language": "en",
  "maxReviews": 0,
  "reviewsSort": "newest",
  "maxImages": 0,
  "scrapeContacts": true,
  "skipClosedPlaces": false,
  "restrictToSearchedCity": true,
  "scrapeReviewsPersonalData": true,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `places` (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 = {
    "searchStringsArray": [
        "restaurant"
    ],
    "locationQuery": "New York, USA",
    "maxCrawledPlacesPerSearch": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("analytics_tupiniquim/google-maps-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": ["restaurant"],
    "locationQuery": "New York, USA",
    "maxCrawledPlacesPerSearch": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("analytics_tupiniquim/google-maps-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 '{
  "searchStringsArray": [
    "restaurant"
  ],
  "locationQuery": "New York, USA",
  "maxCrawledPlacesPerSearch": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call analytics_tupiniquim/google-maps-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/eQfrbEECrmkFCiFN1/builds/PJGsCCbPBYIfi3NU8/openapi.json
