# Google Maps Scraper API — Emails, Reviews, Photos & Leads (`pro100chok/google-maps-scraper`) Actor

Google Maps scraper and Google Places API alternative: extract business names, phones, websites, hours, ratings and reviews — plus emails and 7 social profiles pulled from each place's website. Bypass Google's 120-place limit. Export JSON, CSV, Excel. From $3/1k places, no API key.

- **URL**: https://apify.com/pro100chok/google-maps-scraper.md
- **Developed by:** [Raven](https://apify.com/pro100chok) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Features:** Limited permissions, Single-tenant, Server interface
- **Stats:** 296 total users, 23 monthly users, 100.0% runs succeeded, 4 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.90 / 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.
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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 🗺️ Google Maps Scraper — Emails, Reviews & Contact Details

**Extract data from thousands of Google Maps places** — business name, category, full address, phone number, website, opening hours, rating, reviews, and images — and **enrich every place with emails and social media profiles** pulled from its website. Export to Excel, CSV, JSON, or HTML, run via API, schedule and monitor runs, or integrate with your favorite tools. No code, no Google Maps API key, no daily quotas.

🚀 Build a lead list of any local business in any city in minutes — every barbershop in Berlin, every dentist in Texas, every coffee shop in Tokyo — with the **owner's email already extracted** from their website.

![Google Maps on Apify — every place every email as structured JSON](https://raw.githubusercontent.com/PRO100CHOK/apify-readme-assets/main/google-maps-scraper/hero.png)

<table>
<tr>
<td colspan="4" style="padding:10px 14px;background:#C7392D;border:none;border-radius:4px 4px 0 0">
<span style="color:#FFFFFF;font-size:14px;font-weight:700;letter-spacing:0.5px">Raven &middot; Local & lead-gen suite</span>
<span style="color:#FBD9D7;font-size:13px">&nbsp;&nbsp;&bull;&nbsp;&nbsp;Google Maps, website contacts, Trustpilot, TripAdvisor</span>
</td>
</tr>
<tr>
<td style="background:#FBDDDB;padding:10px 12px;border:1px solid #E4E4E7;border-right:none;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/2nh2cdeW87EFLjZmA-actor-w0yugQzf3ETbRbAC2-ehi6JwVR72-ae55cffc-cd6e-481f-bb22-f89a349f7287.png" width="20" height="20" style="vertical-align:middle;border-radius:4px"> &nbsp;<a href="https://apify.com/pro100chok/google-maps-scraper" style="color:#B03228;text-decoration:none;font-weight:700;font-size:13px">Google&nbsp;Maps</a></span><br>
<span style="color:#B03228;font-size:11px;font-weight:600">&#10148; You are here</span>
</td>
<td style="background:#FDF0EF;padding:10px 12px;border:1px solid #E4E4E7;border-right:none;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/2nh2cdeW87EFLjZmA-actor-1X9ZSt3urlN5pptAO-Nyu91cUNLw-9d50dd18-fb66-400e-85c7-413263018bd8.png" width="20" height="20" style="vertical-align:middle;border-radius:4px"> &nbsp;<a href="https://apify.com/pro100chok/extract-emails" style="color:#18181B;text-decoration:none;font-weight:700;font-size:13px">Website&nbsp;Contacts</a></span><br>
<span style="color:#71717A;font-size:11px">Emails, phones, socials</span>
</td>
<td style="background:#FDF0EF;padding:10px 12px;border:1px solid #E4E4E7;border-right:none;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/2nh2cdeW87EFLjZmA-actor-lFLILoeJarJWgpyfA-7BP7SUkgSm-50326886-1a52-4c64-bd8d-be2556872aa9.png" width="20" height="20" style="vertical-align:middle;border-radius:4px"> &nbsp;<a href="https://apify.com/pro100chok/trustpilot-all-in-one-scraper" style="color:#18181B;text-decoration:none;font-weight:700;font-size:13px">Trustpilot&nbsp;Scraper</a></span><br>
<span style="color:#71717A;font-size:11px">Reviews, companies, scores</span>
</td>
<td style="background:#FDF0EF;padding:10px 12px;border:1px solid #E4E4E7;border-top:none;vertical-align:top;width:25%">
<span style="white-space:nowrap"><img src="https://apify-image-uploads-prod.s3.us-east-1.amazonaws.com/2nh2cdeW87EFLjZmA-actor-caoIAzJRQpPYIg12M-tRWDnGB6Xs-7d9d7a8f-dbff-412c-b8ee-789318d445f2.png" width="20" height="20" style="vertical-align:middle;border-radius:4px"> &nbsp;<a href="https://apify.com/pro100chok/tripadvisor-all-in-one" style="color:#18181B;text-decoration:none;font-weight:700;font-size:13px">TripAdvisor&nbsp;Scraper</a></span><br>
<span style="color:#71717A;font-size:11px">Hotels, restaurants, reviews</span>
</td>
</tr>
</table>

### 📍 What is Google Maps Scraper?

Google Maps Scraper is a no-code web scraping tool that extracts business data from Google Maps at scale. Give it a search term (for example `barber shop`, `dental clinic`, or `coffee`) plus a location, and it returns every matching place with full contact details — names, addresses, phone numbers, websites, ratings, reviews, opening hours, and photos — then enriches each place with **emails and social links** scraped from its website.

It's a flexible, affordable **Google Places API alternative**: no per-request key, no small result caps, and no complicated setup — just the business data you actually need, ready to export.

### 🎯 What can you do with it?

- 🧲 **Lead generation** — build targeted B2B lists with verified emails and phone numbers for cold outreach
- 📍 **Local SEO & GMB audits** — competitor analysis, listing monitoring, and NAP citation building
- 🍽️ **Market research** — analyze competitor density, ratings, and reviews in any area
- 🛒 **Franchise & market-entry research** — map every competitor in a region with full contact details
- 🤖 **AI / LLM pipelines** — clean, structured business data for downstream models
- 📊 **Real-estate & retail scouting** — find the right neighborhood by category density

### 📦 What data does Google Maps Scraper extract?

| Group | Fields |
|---|---|
| **Identification** | `name`, `place_id`, `google_maps_url`, `category`, `categories[]`, `description` |
| **Address** | `address` (full), `city`, `state`, `zip_code`, `country_code` (ISO-2), `area` (neighborhood), `plus_code` |
| **Coordinates** | `latitude`, `longitude` |
| **Contact** | `phone`, `website`, `email` (primary), `emails[]` (all found) |
| **Social profiles** | `facebook`, `instagram`, `twitter`, `linkedin`, `youtube`, `tiktok`, `telegram` |
| **Reputation** | `rating` (0–5), `reviews_count`, `price_level` (`$`–`$$$$`) |
| **Status** | `permanently_closed`, `temporarily_closed` |
| **Hours** | `opening_hours` (full 7-day schedule) |
| **Reviews** (add-on) | `reviews[]` — `text`, `textTranslated`, `language`, `rating`, `author`, `publishedAt`, `publishedAtDate`, `authorAvatar`, `authorProfileUrl`, `authorId`, `authorReviewsCount`, `authorPhotosCount`, `reviewId`, `photos[]`, `ownerResponse` |
| **Images** (add-on) | `images[]` — direct image URLs (no binaries, just links) |

### ⚡ Why this Google Maps Scraper

- ✅ **Emails included in the base price** — every place with a website is enriched with business emails. Most competing scrapers charge this as a separate add-on
- ✅ **Bypass Google's ~160-place limit** — `deepSearch` (on by default) splits any city by postal code and district to return thousands of places per search term
- ✅ **Full Google reviews** — pull every review per place with text, rating, author, exact date, photos, and the owner's reply
- ✅ **7 social networks auto-extracted** — Facebook, Instagram, X (Twitter), LinkedIn, YouTube, TikTok, and Telegram links from each place's website
- ✅ **International-ready** — accurate address parsing worldwide: ISO-2 country code, city, state, postal code, and neighborhood, all separated cleanly
- ✅ **No code + full API** — run from the UI, or via API in Python and Node.js, with scheduling, webhooks, and integrations
- ✅ **Export anywhere** — Excel, CSV, JSON, or HTML; results stream in real time
- ✅ **Pay only for results** — transparent pay-per-event pricing, no subscription, no minimum spend

### 💰 How much does it cost?

**From $3 / 1,000 places — with emails included.** This scraper uses Apify's **pay-per-event** pricing, so you only pay for what you actually extract:

| Event | When you pay | Price (USD) |
|---|---|---|
| **`place`** | One place pushed to the dataset | **$0.003** |
| **`contact`** | A unique email enriched from a website | **$0.002** |
| **`review`** | One review attached to a place (when `includeReviews` is on) | **$0.0005** |
| **`image`** | One image URL attached (when `includeImages` is on) | **$0.0002** |

**Real-world cost examples:**

- 🏪 **1,000 barbershops with emails** → 1,000 × $0.003 + ~400 unique emails × $0.002 ≈ **$3.80**
- 🍽️ **100 restaurants + 50 reviews each + 20 photos each** → $0.30 + $2.50 + $0.40 ≈ **$3.20**
- 🌆 **Full coverage of a mid-size city (3,000 places)** → ~$10

Cap any run with **Default run options → Max total charge** so you never overspend. Duplicate emails are charged once per run, and junk/placeholder emails (`noreply@`, `example.com`, etc.) are filtered out before billing.

#### Why pay-per-event pricing?

You pay for concrete results — places, emails, reviews, images — not for compute time or opaque "credits." A run that returns 500 places costs the same whether it takes one minute or ten, so pricing is predictable and easy to budget.

### 🚀 How do I use Google Maps Scraper?

No coding required:

1. Click **Try for free** and open the input form.
2. Enter one or more **search terms** (e.g. `coffee shop`) and a **location** (e.g. `Berlin, Germany`).
3. (Optional) Turn on reviews or images, and set your limits. Deep search is already on.
4. Click **Start** and watch results fill in live.
5. **Export** to Excel, CSV, JSON, or HTML — or pull the data via API.

### ⚡ Real-time API (Standby mode)

Need places inside your own app instead of a dataset? The same scraper is kept warm as an HTTP API — one request in, the places back in the response body. No run to start, no run to poll, no dataset to fetch.

```bash
curl "https://pro100chok--google-maps-scraper.apify.actor/search?\
q=dentist&location=Austin,%20TX&limit=10&contacts=true&token=<YOUR_APIFY_TOKEN>"
```

```json
{
  "ok": true,
  "count": 10,
  "truncated": true,
  "tookSecs": 11.9,
  "warnings": [],
  "stats": { "found": 42, "language": "en", "countryCode": "us" },
  "items": [
    {
      "name": "Austin Family Dentistry",
      "address": "1600 W 38th St #300, Austin, TX 78731",
      "phone": "+1 512-555-0134",
      "email": "hello@example.com",
      "website": "https://example.com",
      "rating": 4.8,
      "reviews_count": 312,
      "category": "Dentist",
      "latitude": 30.3072,
      "longitude": -97.7431
    }
  ]
}
```

Open the **Standby** tab on the Actor page to browse every endpoint and fire test requests straight from the browser — it is generated from the Actor's OpenAPI 3 specification, which the API also serves at `/openapi.json`.

| Endpoint | What it does |
|---|---|
| `GET /search` | Search Google Maps and get the places back |
| `POST /search` | Same, with the Actor's full input object as the JSON body |
| `GET /` | Usage: every endpoint and parameter, as JSON |
| `GET /health` | Liveness check |
| `GET /openapi.json` | The OpenAPI 3 specification |

Common parameters — `q` (required), `location`, `limit`, `timeout`, `contacts`, `reviews` / `maxReviews`, `images` / `maxImages`, `popularTimes`, `language`, `deepSearch`, `minStars`, `minReviews`, `website`, `onlyWithEmail`, `skipClosed`. `q`, `location` and `categories` take either a repeated parameter (`?q=gym&q=spa`) or a comma-separated one (`?q=gym,spa`). Every field of the input schema below works too, spelled exactly as it is spelled there.

Three things to know:

- **It answers within your time budget.** `timeout` defaults to 120s and is capped at 280s, because Apify closes a Standby request after 5 minutes. When the budget runs out you get the places found so far with `truncated: true` — never an empty error.
- **`limit` defaults to 20 and is capped at 1000**, and `deepSearch` is off — an API call should come back quickly. For tens of thousands of places, start a normal run instead.
- **Billing is identical** to a normal run: per place, per contact enrichment, per review, per image.

### ⬇️ Input

| Field | Type | Default | Description |
|---|---|---|---|
| 🔍 `searchStringsArray` | array | — | Search terms, one per line (e.g. `barber shop`, `dental clinic`) |
| 📍 `locationQuery` | string | — | Free-text location, e.g. `Washington, DC` or `Berlin, Germany` |
| 🏙️ `city` / 🗺️ `state` / 🌍 `country` | string | — | Optional structured location fields |
| 🧮 `maxItems` | integer | `100` | Hard cap on total results across all terms and locations — you're never charged past it. Empty = no limit |
| 📍 `locationQueries` | array | `[]` | Search every location in the list. Each term runs against each location (6 terms x 38 cities = 228 searches) |
| 🎯 `maxCrawledPlacesPerSearch` | integer | — | Cap per term+location. With many locations this keeps coverage even, so the first cities can't spend the whole budget |
| 🌐 `deepSearch` | boolean | `true` | Split the area by postal code / district to get past Google's ~160-place limit per search |
| 🏷️ `categoryFilter` | string | — | Keep only places whose category matches (e.g. `Barber shop`) |
| 🗣️ `language` | select | *auto* | Results language. Left on **Auto** it follows the language you typed in; pick one only to force a different one. There is no country field — Google's `gl` hint is read off your locations |
| 📊 `popularTimes` | boolean | `false` | **Add-on**. Weekly busyness histogram per place — how busy every hour of every day usually is, plus Google's live reading. Costs one extra request per place; no extra charge. ⚠️ Temporarily empty — Google stopped serving it on the web on Oct 13, 2026 |
| 📧 `scrapeContactsFromWebsite` | boolean | `true` | Extract emails + social links from each place's website |
| 📭 `skipPlacesWithoutEmail` | boolean | `false` | Lead-list mode — output only places with an email |
| 🔁 `skipDuplicateEmails` | boolean | `true` | Keep only the first place per email address — booking platforms put one shared mailbox on dozens of listings |
| 💬 `includeReviews` | boolean | `false` | **Add-on**. Attach reviews per place (text, rating, author, date, photos) |
| 🔢 `maxReviewsPerPlace` | integer | `20` | Cap reviews per place (1–5000) |
| 🖼️ `includeImages` | boolean | `false` | **Add-on**. Attach photo URLs per place |
| 🔢 `maxImagesPerPlace` | integer | `20` | Cap images per place (1–200) |
| ⚡ `concurrency` | integer | `3` | Parallel Google sessions, each on its own IP |

#### 🟢 Quick example — every barbershop in Berlin with emails

```json
{
  "searchStringsArray": ["barber shop"],
  "locationQuery": "Berlin, Germany",
  "maxItems": 500,
  "deepSearch": true,
  "scrapeContactsFromWebsite": true
}
```

#### 🟡 Example — restaurants in NYC with full review history

```json
{
  "searchStringsArray": ["italian restaurant", "ramen", "steakhouse"],
  "locationQuery": "New York, NY",
  "maxItems": 100,
  "includeReviews": true,
  "maxReviewsPerPlace": 200,
  "includeImages": true,
  "maxImagesPerPlace": 30
}
```

### ⬆️ Output

Every place is one row/record. View results in the **table** or **JSON** tab, or export to Excel, CSV, JSON, or HTML.

```jsonc
{
  "place_id": "ChIJZW3FhdK3t4kRLXEtK4yueuE",
  "name": "Scissors & Scotch",
  "category": "Barber shop",
  "categories": ["Barber shop"],
  "address": "331 N St NE, Washington, DC 20002, USA",
  "city": "Washington",
  "state": "DC",
  "zip_code": "20002",
  "country_code": "US",
  "area": "Near Northeast",
  "plus_code": "WX4X+PH",
  "latitude": 38.9068,
  "longitude": -77.001,
  "phone": "(202) 481-2850",
  "website": "https://scissorsscotch.com/",
  "email": "info@scissorsscotch.com",
  "emails": ["info@scissorsscotch.com", "dc@scissorsscotch.com"],
  "facebook": "https://www.facebook.com/scissorsscotch",
  "instagram": "https://www.instagram.com/scissorsscotch/",
  "twitter": "https://twitter.com/scissorsscotch",
  "rating": 4.7,
  "reviews_count": 1422,
  "price_level": "$$",
  "permanently_closed": false,
  "temporarily_closed": false,
  "opening_hours": "Monday: 9 AM–8 PM | Tuesday: 9 AM–8 PM | Wednesday: 9 AM–8 PM | Thursday: 9 AM–8 PM | Friday: 9 AM–7 PM | Saturday: 9 AM–7 PM | Sunday: 10 AM–5 PM",
  "google_maps_url": "https://www.google.com/maps/search/?api=1&query=Scissors+%26+Scotch&query_place_id=ChIJZW3FhdK3t4kRLXEtK4yueuE",
  "reviews": [
    {
      "rating": 5,
      "text": "Best haircut I've had in DC. Stylist took time to understand what I wanted...",
      "language": "en",
      "publishedAt": "2 months ago",
      "publishedAtDate": "2026-08-30T17:42:11.513000+00:00",
      "author": "Mike Visalli",
      "authorAvatar": "https://lh3.googleusercontent.com/a/...",
      "authorProfileUrl": "https://www.google.com/maps/contrib/111279794912534073117?hl=en-US",
      "authorId": "111279794912534073117",
      "authorReviewsCount": 38,
      "authorPhotosCount": 12,
      "reviewId": "ChdDSUhNMG9...",
      "photos": ["https://lh3.googleusercontent.com/grass-cs/..."],
      "ownerResponse": {"text": "Thanks Mike, see you next time!", "publishedAt": "2 months ago"}
    }
  ],
  "images": [
    "https://lh3.googleusercontent.com/grass-cs/...",
    "https://lh3.googleusercontent.com/grass-cs/..."
  ],
  "search_query": "barber shop",
  "search_location": "Washington, DC",
  "scraped_at": "2026-05-12T10:15:30+00:00"
}
```

### 📊 Popular times

> ⚠️ **Temporarily unavailable (since October 13, 2026).** Google has stopped serving
> popular times on Google Maps for the web — the histogram is gone even in a regular
> browser, for every place and country we checked. While that lasts, `popular_times`
> comes back empty; the rest of each place is unaffected and nothing extra is charged.
> The actor picks the data up again automatically as soon as Google brings it back.

Turn on `popularTimes` and each place carries Google's busyness histogram:

```json
"popular_times": {
  "days": {
    "monday": [
      { "hour": 9,  "percent": 30, "label": "Usually not too busy", "time": "9 AM" },
      { "hour": 20, "percent": 84, "label": "Usually as busy as it gets", "time": "8 PM" }
    ]
  },
  "live": { "day": "wednesday", "hour": 11, "percent": 93, "label": "Busier than usual" }
}
```

Labels follow the run's language — a Ukrainian run returns
`"Зараз: Зазвичай достатньо людно"`. Two things worth knowing before you switch
it on: Google keeps this out of the search response, so it costs **one extra
request per place** and slows a run down noticeably; and Google only computes a
histogram for places with enough foot traffic, so quieter businesses return an
empty `popular_times`. There is no separate charge — it is part of the Place event.

### 🌍 Languages & countries

**Nothing to configure.** The actor reads the language and the country straight
out of your input:

| You type | It searches as |
|---|---|
| `стоматолог` in `Бровари, Київська область, Україна` | `hl=uk`, `gl=UA` |
| `dentist` in `Kyiv, Ukraine` | `hl=en`, `gl=UA` |
| `gym` in `Austin, TX` | `hl=en`, `gl=US` |
| `歯医者` in `東京, 日本` | `hl=ja`, `gl=JP` |
| a `google.com.ua/maps/...` link | `gl=UA` |
| cities in several countries | no country bias, so no country is favoured |

Set 🗣️ `language` yourself to override the detection — the country follows your
locations either way. 45 result languages are available. Address parsing is
tested across 60+ countries — US, EU (DE/FR/IT/ES/NL/PL), UK, CIS (RU/UA/BY/KZ),
Turkey, Japan, Brazil, and Mexico — with ISO-2 country codes auto-detected.

### ❓ Frequently asked questions

**How does Google Maps Scraper work?**
You enter one or more search terms and a location. The scraper searches Google Maps just like a person would, collects every matching business, and for each place with a website it also visits that site to pull emails and social profiles. Results stream into your dataset as they're found.

**What are the disadvantages of the Google Maps API?**
The official Google Places API requires an API key and billing, caps results (for example a maximum of 5 reviews per place with no pagination), limits how many places you can pull per query, and doesn't return emails or social profiles at all. This scraper has no key, higher limits, and enriches each place with contact data Google's API never exposes.

**Can I scrape places from multiple locations at once?**
Yes. Add multiple search terms; `deepSearch` (on by default) covers an entire city or region and gets past Google's ~160-place limit per area.

**Can I extract Google Maps reviews?**
Yes — enable `includeReviews` to attach reviews per place with text, rating, author, date, and photos, up to your `maxReviewsPerPlace` cap.

**Can I get emails and phone numbers for lead generation?**
Yes. Phone numbers come straight from Google Maps, and emails plus social links are extracted from each place's website — included in the base price. Turn on `skipPlacesWithoutEmail` for a clean lead list.

**Can I integrate Google Maps Scraper with other apps?**
Yes. Connect it to Make, Zapier, Google Sheets, Slack, and more, or trigger runs and pull data with webhooks and the Apify API.

**Can I use Google Maps Scraper as its own API, in Python or Node.js?**
Yes, two ways. Every run and dataset is available through the Apify API, with ready-made Python and JavaScript client libraries, a CLI, and an MCP server. And for real-time use there is [Standby mode](#-real-time-api-standby-mode): `GET /search?q=dentist&location=Austin,%20TX` returns the places in the response body, no run to poll — see the **Standby** tab for the interactive documentation.

**Is it legal to scrape Google Maps data?**
Scraping publicly available business data is generally legal. This scraper only collects public information (names, addresses, phones, public websites, ratings, and reviews). You are responsible for how you use the data and for complying with applicable laws such as GDPR/CCPA.

### 📞 Support & feedback

Found a bug or need a feature? Email **africanec@gmail.com** — usually fixed and redeployed within 24 hours.

To speed up debugging you can share run data with the developer: [Apify Security Settings](https://console.apify.com/settings/security) → **"Share run data with developers"** → enable for this Actor.

# Changelog

This Actor's version history is a separate document: https://apify.com/pro100chok/google-maps-scraper/changelog.md

# Actor input Schema

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

What to search for — one term per line (e.g. `restaurant`, `gym`, `dentist`). Each term is searched in every location below, so 3 terms x 5 cities = 15 searches. You can leave this empty ONLY if you paste Google Maps search links into 'Google Maps search URLs' below.

## `locationQueries` (type: `array`):

One location per line — the search runs in every one of them. Format: free text as you'd type into Google Maps, from broad to narrow:
• `New York` · `Rajasthan, India` · `Brooklyn, New York`
• `Jaisalmer, Rajasthan, India` · `11201` (postal code)

Each search term is run against each location, so 6 terms × 38 cities = 228 searches. For a single city just enter one line. Leave empty to use the structured City / State / Country fields below instead.

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

Paste Google Maps SEARCH links (e.g. `google.com/maps/search/gyms+in+Jaipur`) and their query is added to the run. Links to one specific place are not supported — use the search fields above for those.

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

Leave on **Auto** and the actor picks the language from what you typed — search in Ukrainian and you get Ukrainian categories and reviews, search in English and you get English. Pick a language here only to force a different one.

The country (Google's `gl` hint) is detected the same way, from your locations — `Бровари, Київська область, Україна` searches as Ukraine, `Austin, TX` as the US — so there is nothing to set for it.

## `popularTimes` (type: `boolean`):

⚠️ **Temporarily unavailable:** since October 13, 2026 Google no longer serves popular times on Google Maps for the web, so this field comes back empty until Google brings it back.

Attach Google's weekly busyness histogram to each place — how busy it usually is for every hour of every day, plus the live "busier than usual" reading when Google has one.

**Costs one extra request per place** (Google keeps this out of the search response), so a run with it on is noticeably slower. No extra charge — it is included in the Place event. Many places have no histogram at all: Google only computes one where a business gets enough traffic.

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

Optional — city name. Combined with the other fields into one location. Ignored if you filled the Locations list above.

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

Optional — US state or other top-level region (e.g. `CA`, `Texas`). Combined with the other fields into one location.

## `country` (type: `string`):

Optional — full country name, e.g. `USA`, `Germany`, `India`. Combined with the other fields into one location.

## `county` (type: `string`):

Optional — county or district. Combined with the other fields into one location.

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

Optional — narrows the search to one postal code. Combined with the city/state/country fields into a single location.

## `maxItems` (type: `integer`):

Hard cap on how many places the run returns in total, across ALL search terms and locations. The actor stops as soon as it has this many — you are never charged for extras. Leave empty to keep going until Google runs out of results.

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

Cap for ONE search term in ONE location. With many locations this is what keeps coverage even: without it the first cities crawled can consume the whole 'Max results' budget and the rest return nothing. Leave empty for no per-search cap. The global 'Max results' still applies on top.

## `deepSearch` (type: `boolean`):

Google caps a single search at ~160 places. With this on, the actor splits the location into postal codes and districts and keeps searching until it hits your Max results — the only way to get thousands of places. On by default; it costs nothing on small runs, since crawling stops the moment Max results is reached.

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

Keep only places whose Google category matches one of these words (e.g. `gym`, `fitness`). Leave empty to keep every category. Filtered-out places cost you nothing — they are dropped before enrichment.

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

How strictly a place name must match your search term. Google returns loosely related places by default, which is noise for lead lists.

## `placeMinimumStars` (type: `string`):

Skip places rated below this. Places with no rating yet are always kept.

## `minimumReviewsCount` (type: `integer`):

Skip places with fewer reviews than this — a quick way to drop inactive or barely-registered listings.

## `website` (type: `string`):

Emails come from a place's website, so 'Only places WITH a website' is the setting for email-focused lead lists. 'Only WITHOUT' finds businesses to sell web design to.

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

Drop businesses Google marks as permanently or temporarily closed. Worth turning on for lead lists — a closed business is a wasted row.

## `scrapeContactsFromWebsite` (type: `boolean`):

For every place that has a website, fetch homepage + contact pages and extract emails plus Facebook / Instagram / X / LinkedIn / YouTube / TikTok / Telegram links.

## `skipPlacesWithoutEmail` (type: `boolean`):

Keep ONLY places where an email was found. Requires email scraping to be on (above). Careful: this typically removes 50-60% of results, since most small businesses publish only a phone number.

## `skipDuplicateEmails` (type: `boolean`):

Keep only the first place for each email address. Booking platforms and website templates put one shared address (e.g. `support@platform.com`) on dozens of listings — this drops those repeats so you don't pay for the same lead twice. Places with no email are never affected.

## `includeReviews` (type: `boolean`):

Attach user reviews per place — text, rating, author, date, and attached photos. Paginates through Google's review API, so you get the full review history (up to your cap below). Billed per review extracted — see pricing.

## `maxReviewsPerPlace` (type: `integer`):

Hard cap on reviews attached to one place. The actor paginates Google's review API (~10 reviews per page) until it hits this cap or runs out of reviews.

## `includeImages` (type: `boolean`):

Attach photo URLs to each place. Sources: 3-5 thumbnails from the search response + user-submitted photos from reviews (works only together with 💬 includeReviews). Higher review limit → more photos. Billed per image.

## `maxImagesPerPlace` (type: `integer`):

How many image URLs to collect per place (the URLs only, not the image files). Charged per image.

## `maxRetries` (type: `integer`):

How many times to retry a search that fails. The default is fine; raise it only on a very unstable connection.

## `concurrency` (type: `integer`):

Google sessions running in parallel, each on its own IP. Higher = faster. 10 is a good default; raise it for very large runs.

## Actor input object example

```json
{
  "searchStringsArray": [
    "barber shop"
  ],
  "locationQueries": [
    "Jaipur, Rajasthan, India",
    "Jodhpur, Rajasthan, India"
  ],
  "startUrls": [],
  "language": "",
  "popularTimes": false,
  "maxItems": 1000,
  "deepSearch": true,
  "categoryFilterWords": [],
  "searchMatching": "all",
  "placeMinimumStars": "",
  "website": "allPlaces",
  "skipClosedPlaces": false,
  "scrapeContactsFromWebsite": true,
  "skipPlacesWithoutEmail": false,
  "skipDuplicateEmails": true,
  "includeReviews": false,
  "maxReviewsPerPlace": 20,
  "includeImages": false,
  "maxImagesPerPlace": 20,
  "maxRetries": 5,
  "concurrency": 10
}
```

# Actor output Schema

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

All scraped places pushed to the dataset.

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

No description

## `contacts` (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": [
        "barber shop"
    ],
    "locationQueries": [
        "New York"
    ],
    "startUrls": [],
    "categoryFilterWords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("pro100chok/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": ["barber shop"],
    "locationQueries": ["New York"],
    "startUrls": [],
    "categoryFilterWords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("pro100chok/google-maps-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": [
    "barber shop"
  ],
  "locationQueries": [
    "New York"
  ],
  "startUrls": [],
  "categoryFilterWords": []
}' |
apify call pro100chok/google-maps-scraper --silent --output-dataset

```

## MCP server setup

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