# Google Maps Scraper - Places, Leads, Emails & Contacts (`scrapesage/google-maps-scraper`) Actor

Scrape Google Maps places by keyword + location in any country: name, category, full address with city and postal code, phone, website, rating, coordinates, photos, attributes. Optional: review counts + full weekly hours, website emails, socials and phones. Monitor mode, place-ID lookup, no API key.

- **URL**: https://apify.com/scrapesage/google-maps-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (community)
- **Categories:** Lead generation, Travel, Agents
- **Features:** Limited permissions
- **Stats:** 949 total users, 177 monthly users, 100.0% runs succeeded, 4 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 places

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/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 - Places, Business Leads, Emails & Contacts

> **Disclaimer:** This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Google LLC or any of its subsidiaries. All trademarks mentioned are the property of their respective owners. "Google Maps" is referenced only to describe the publicly available website this Actor collects data from.

Extract **complete Google Maps business & place data** at scale - **name, category, full address, phone, website, rating, opening status, coordinates, photos and attributes** - for any search term and location. Then optionally turn every place into a **ready-to-contact B2B lead** by crawling its own website for **emails, phone numbers and social profiles**, with a 0–100 lead score on every record.

No API key, no login, no browser - fast JSON extraction straight from Google Maps' own data feed. **Every standard field and every filter is included in the place price**; review counts + full weekly hours and website contacts are two clear opt-ins. Searches are centred on the place you name, addresses are split into city / region / postal code in every country, big cities are scanned map tile by map tile for more places than one search shows, and rows are saved as each search finishes.

### Why this Google Maps scraper?

This actor puts **every standard field in one place record** and keeps the extras to two clear opt-ins: place details (total review count + full weekly hours) and website contacts (emails, social profiles, phones):

| Data | This actor |
|---|---|
| Name, category, full address, city/state/ZIP, country | ✅ |
| Phone (formatted + E.164), website, domain | ✅ |
| Rating, open/closed status, today's hours | ✅ |
| Latitude / longitude, plus code, neighborhood | ✅ |
| Place ID, CID, FID, Knowledge-Graph ID | ✅ |
| Business attributes (accessibility, service options…) | ✅ |
| Photos / image URLs | ✅ |
| **Total review count + full Mon–Sun opening hours** | ✅ opt-in, in any language |
| **Contact emails** (from the business website) | ✅ opt-in, lead price only when contacts are found |
| Facebook / Instagram / LinkedIn / X / YouTube / TikTok | ✅ included with contacts |
| Results centred on your location, far-away places left out | ✅ |
| City / region / postal code split correctly outside the US | ✅ |
| Look up places by place ID or Google Maps link | ✅ |
| **More places than one search shows** (the area is scanned map tile by map tile) | ✅ |
| **Owner profile behind the listing** (name + stable owner ID) | ✅ |
| **Booking / reservation link** (OpenTable, Resy, NexHealth, Vagaro… or Reserve with Google) + **order-online link** | ✅ |
| **Business identity attributes** (LGBTQ+ friendly, women-owned, veteran-owned…) + **hotel check-in / check-out times** | ✅ |
| **Tagline, editorial summary, photo count, secondary hours** | ✅ opt-in |
| Lead score (0–100) per place | ✅ |
| Monitor mode - only new / changed places | ✅ |
| Pricing | flat place fee + 2 clear opt-ins |

### Use cases

- **Local lead generation** - pull every plumber, dentist, law firm, gym or restaurant in a city, enrich their website for emails and socials, and score them by contactability. Perfect for agencies, SaaS and B2B sales.
- **Find businesses without a website** - set the website filter to "without a website" to build a targeted list for web-design and marketing offers.
- **Market & competitor research** - map saturation, ratings and categories across neighbourhoods or whole metros.
- **Data enrichment** - resolve names/addresses to phone, website, coordinates and place IDs for your CRM.
- **Recurring monitoring** - schedule the actor with monitor mode to capture only places that are new to your search or have changed (phone, website, rating or address) in a city or category.

### How to use

1. [Sign up for Apify](https://console.apify.com/sign-up) - the free plan is enough to try this actor.
2. Open the **Google Maps Scraper**, enter one or more **search terms** and a **location**, and click **Start**.
3. Rows are saved search by search, so the dataset fills while the run is going (a run stopped by its time limit or cost cap keeps everything it found; an aborted run keeps the rows already saved).
4. **Export** as JSON, CSV, Excel, XML, or RSS - or pull results programmatically via the [Apify API](https://docs.apify.com/api/v2).

### Input

```json
{
    "searchQueries": ["coffee shops", "dentist"],
    "locationQuery": "Austin, TX",
    "maxPlacesPerSearch": 120,
    "maxResults": 1000,
    "enrichContacts": true,
    "scrapePlaceDetails": true,
    "minRating": "4",
    "websiteFilter": "all",
    "sortBy": "leadScore"
}
```

- **searchQueries** - what to look for (categories, business types, or names). Each is combined with the location.
- **locationQuery** - city / area, e.g. `Austin, TX`, `New York, NY`, `London, UK`, `Berlin, Germany`. The map is centred on it and places far outside it are left out (and not charged). Add the region or country to ambiguous names (`Portland, ME`). Leave empty if you put the location in the search term (`dentist in Houston, TX`) or use coordinates / links. A location with no search term ends the run with a clear message and no charge.
- **latitude / longitude / zoom** *(optional)* - explicit search center instead of a location string.
- **startUrls** *(optional)* - Google Maps links: place links (including the app's "Share" links and this actor's own `url` values) are looked up as that business; search links (`…/maps/search/<term>/@lat,lng,zoomz`) run as a search of that map area.
- **urlsFromFile** *(optional, "Import URLs from a file")* - paste many links at once, or one link to a .txt/.csv file, Google Sheet or Drive file that lists them. If the file cannot be read, the run ends with a clear message and no charge.
- **placeIds** *(optional)* - look up specific businesses by place ID (`ChIJ…`), feature ID (`0x…:0x…`) or place link, one per line - handy for refreshing places you scraped before. If the form's example search (restaurants in Austin, TX) is still filled in, it is skipped when you give place IDs or links.
- **maxPlacesPerSearch** *(default 120)* - how many places to collect per search term. One Google search gives a limited list; set this higher (for example 500 or 2,000) and the actor pages each search to its end and then scans the area map tile by map tile, nearest the centre first, so a big city returns several times more places. `maxResults` still caps the whole run.
- **maxResults** *(default 1000)* - cap on the rows saved (after filtering).
- **maxDistanceKm** *(default 0 = automatic)* - leave out places farther than this from the location's centre. Automatic = a radius sized to the place you searched (at least 40 km).
- **enrichContacts** *(default false)* - crawl each place's website (home + contact/about) for emails, social profiles and phones. Google Maps never exposes emails - this is the only way to get them.
- **scrapePlaceDetails** *(default false)* - add the **total review count**, the **full Monday–Sunday opening hours**, a refined rating and a popular-times flag (`hasPopularTimes` is sparse: Google only includes popular-times data on some of its responses, so the flag appears on a minority of rows - a missing value means Google left it out of that call, not that the place has no busy hours). Fetched from Google Maps' own place data call over HTTP - about a second per place, so a 100-place run with details finishes in well under a minute.
- **detailConcurrency** *(default 8, up to 16)* - parallel place-detail requests when `scrapePlaceDetails` is on (plain HTTP, no extra memory needed).
- **minRating / categoryFilterWords / websiteFilter / skipClosedPlaces / withPhoneOnly / withEmailOnly / nameQuery** - filters.
- **language (hl) / countryCode (gl)** - localisation.
- **sortBy** - `leadScore` (default), `rating`, or `distance` (Google's own order). Rows are ordered within each saved batch (up to 150 rows, saved search by search); for one overall order, sort the exported file.
- **monitorMode / monitorKey** - emit only new / changed places across runs. The first run is the baseline: it saves up to `maxResults` and remembers everything else it scanned, so later runs deliver only places that were never seen before (plus changes to delivered ones).

### Output

One record per place (`type: "place"`). `reviewsCount`, `openingHours` (full week, day names in English whatever the search language) and `hasPopularTimes` (sparse - see the input notes) are present when **scrapePlaceDetails** is on; `emails` / `socialProfiles` / `contactPhones` when **enrichContacts** is on, with `enriched: true` when the website gave an e-mail, a social profile or a phone number the listing does not already show, and `enriched: false` when it was checked and gave nothing new. Searches with a location also carry `distanceKm` (from the location's centre). `city`, `state` (the region outside the US) and `postalCode` come from Google's own structured address in every country. Empty fields are omitted, so exports never carry blank columns:

**On every place, no add-on needed:** `ownerName` and `ownerId` - the Google Business Profile that manages the listing (each location has its own; the ID is a stable key for that listing's profile, not a company-wide identifier). Where Google publishes one, you also get `bookingUrl` and `bookingProvider` - the booking or appointment page, either a third-party provider (OpenTable, Resy, NexHealth, Vagaro and similar) or Google's own *Reserve with Google* flow (`bookingProvider: "google.com"`); a link back to the place's own website is never reported as a booking link. Restaurants that take orders through Google also get `orderOnlineUrl`. `identityAttributes` carries Google's business-identity badges such as *LGBTQ+ friendly* or *Identifies as women-owned*, and hotels get `checkInTime` / `checkOutTime`.

**With `scrapePlaceDetails` on, each place also gets** `tagline` (Google's one-line descriptor, e.g. *"Sharp venue for elevated American eats"*), `editorialSummary` (Google's longer write-up), `photoCount`, `reservationUrl`, `secondaryHours` - named schedules a place keeps alongside its opening hours, such as **Happy hours**, *Brunch* or *Kitchen* - and `locatedIn`, the mall, airport, hospital or other venue the place sits inside (*"Mall of America"*), on places that are inside one. Places looked up by place ID carry `locatedIn` without the add-on.

How often these appear depends on the place and the category: owner details are on effectively every place, and booking links and identity badges on roughly half. Tagline and editorial summary are the norm on restaurants, bars and hospitality and thin out in other categories; secondary hours are rarer again, since most places keep a single schedule. A field is simply omitted when Google publishes nothing, so exports stay clean.

```json
{
    "type": "place",
    "placeId": "ChIJm3f11RnLRIYRvuJG0P8_6bw",
    "cid": "13612481716647551678",
    "fid": "0x8644cb19d5f5779b:0xbce93fffd046e2be",
    "kgmid": "/g/11wqplhln0",
    "title": "BRB Coffee",
    "categoryName": "Coffee shop",
    "categories": ["Coffee shop", "Espresso bar"],
    "description": "Cozy neighbourhood coffee bar",
    "address": "3501 Guadalupe St, Austin, TX 78705",
    "street": "3501 Guadalupe St",
    "neighborhood": "North University",
    "city": "Austin",
    "state": "TX",
    "postalCode": "78705",
    "countryCode": "US",
    "latitude": 30.3012578,
    "longitude": -97.7386692,
    "plusCode": "8R29+QV Austin, Texas",
    "phone": "(614) 772-8409",
    "phoneUnformatted": "+16147728409",
    "website": "https://brbcoffee.com/",
    "domain": "brbcoffee.com",
    "totalScore": 4.8,
    "reviewsCount": 1284,
    "status": "Open · Closes 7 PM",
    "openNow": true,
    "hoursToday": "7 AM–7 PM",
    "openingHours": [
        { "day": "Monday", "hours": "7 AM–7 PM" },
        { "day": "Tuesday", "hours": "7 AM–7 PM" }
    ],
    "hasPopularTimes": true,
    "additionalInfo": { "Accessibility": ["Wheelchair accessible entrance"] },
    "imageUrl": "https://lh3.googleusercontent.com/…",
    "photoCount": 9,
    "ownerName": "BRB Coffee",
    "ownerId": "112304401891219815938",
    "identityAttributes": ["LGBTQ+ friendly"],
    "bookingProvider": "resy.com",
    "bookingUrl": "https://resy.com/cities/aus/brb-coffee",
    "reservationUrl": "https://resy.com/cities/aus/brb-coffee",
    "orderOnlineUrl": "https://www.google.com/searchviewer/42?cvd=…",
    "tagline": "Neighbourhood espresso bar with weekend brunch",
    "editorialSummary": "Compact North University coffee bar serving single-origin espresso, house pastries and a weekend brunch menu.",
    "secondaryHours": [
        { "name": "Brunch", "hours": [{ "day": "Saturday", "hours": "9 AM–2 PM" }] }
    ],
    "emails": ["hello@brbcoffee.com"],
    "socialProfiles": { "instagram": "https://instagram.com/brbcoffee" },
    "contactPhones": ["+16147728409"],
    "leadScore": 86,
    "url": "https://www.google.com/maps/place/?q=place_id:ChIJm3f11RnLRIYRvuJG0P8_6bw",
    "searchString": "coffee shops in Austin, TX",
    "scrapedAt": "2026-06-23T12:00:00.000Z"
}
```

**Dataset views** - alongside the raw table, the dataset ships four ready-made views you can switch between in the Storage tab or select through the API: **Places & leads** (the working lead list), **Booking & reservations**, **Owner & business identity**, and **Place profile**.

### How much does it cost to scrape Google Maps?

This Actor uses Apify's **pay-per-event** pricing: you pay for the results it delivers and, from 26 October 2026, Apify's standard run-start fee, with no monthly rental. The events it can charge are:

- **A place** - one Google Maps place with all standard fields – name, categories, full address, phone, website, rating, today's hours, coordinates, plus code, photos, attributes. Filters and the area scan never cost extra, and places left out by a filter or the distance check are not charged.
- **An enriched lead** - a place whose own website gave at least one e-mail, social profile or phone number the Google listing did not already show, with a 0–100 lead score. Charged instead of the place fee, never on top of it. A website that gives nothing new is billed as a plain place.
- **The place-details add-on** - charged once per place when "Scrape place details" is on and Google returned the total review count or the full Monday–Sunday hours; places where neither could be read are not charged.
- **Actor Start** - from 26 October 2026, Apify's standard fee each time a run starts (one per GB of run memory, so one at the default 1 GB).

The current price of each event is shown on the **Pricing** tab of this page. Set a maximum total charge on the run if you want a hard cap on spend: the run stops at the cap and every saved row is billed, nothing beyond it. Use the input limits to control how much the Actor fetches.

### Automate & schedule

Run this actor on autopilot and pull results into your own stack:

- **[Apify API](https://docs.apify.com/api/v2)** - start runs, fetch datasets, and manage schedules over REST.
- **[apify-client for JavaScript](https://docs.apify.com/api/client/js/)** and **[apify-client for Python](https://docs.apify.com/api/client/python/)** - official SDKs.
- **[Schedules](https://docs.apify.com/platform/schedules)** - run it hourly/daily/weekly to watch a city or category for new businesses; perfect for lead pipelines.
- **[Webhooks](https://docs.apify.com/platform/integrations/webhooks)** - trigger downstream actions (CRM import, Slack alert, email sequence) the moment a run finishes.

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'MY_APIFY_TOKEN' });

const run = await client.actor('scrapesage/google-maps-scraper').call({
    searchQueries: ['plumbers'],
    locationQuery: 'Phoenix, AZ',
    maxResults: 500,
    enrichContacts: true,
    websiteFilter: 'with_website',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Got ${items.length} places & leads`);
```

### Integrate with any app

Connect the dataset to 5,000+ apps - no code required:

- **[Make](https://docs.apify.com/platform/integrations/make)** - multi-step automation scenarios.
- **[Zapier](https://docs.apify.com/platform/integrations/zapier)** - push new leads straight into your CRM.
- **[Slack](https://docs.apify.com/platform/integrations/slack)** - get notified when a monitored search finds new places.
- **[Google Drive / Sheets](https://docs.apify.com/platform/integrations/drive)** - auto-export every run to a spreadsheet.
- **[Airbyte](https://docs.apify.com/platform/integrations/airbyte)** - pipe results into your data warehouse.
- **[GitHub](https://docs.apify.com/platform/integrations/github)** - trigger runs from commits or releases.

### Use with AI assistants (MCP)

The output is clean, LLM-ready JSON. Call this actor from Claude, ChatGPT, or any agent framework through the **[Apify MCP server](https://docs.apify.com/platform/integrations/mcp)** - ask your assistant to "find the top-rated dentists in Austin with their phone and email" and let it run this scraper for you.

### Agent-ready: autonomous payments (x402 & Skyfire)

This actor is **agent-ready**: AI agents can discover it, run it, and **pay for it autonomously**, with no Apify account and no human in the loop. It uses [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) pricing and [limited permissions](https://docs.apify.com/platform/actors/development/permissions), so it qualifies for Apify's agentic-payment standards:

- **[x402](https://docs.apify.com/platform/integrations/x402)**: an open, HTTP-native payment protocol. Agents pay per run in USDC on the Base network directly through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp), with no account and no API key.
- **[Skyfire](https://docs.apify.com/platform/integrations/skyfire)**: agent-to-service payments for fully autonomous AI-agent workflows.

Building an AI agent, MCP tool, or autonomous data pipeline? This scraper is ready to plug in and pay as it goes.

### More scrapers from scrapesage

Build a complete **local-business lead-gen stack**:

- **[Google Maps Reviews Scraper](https://apify.com/scrapesage/google-reviews-scraper)** - the review text, ratings, dates and owner replies for the places you find here (pass it this actor's place links).
- **[Website Contact Scraper](https://apify.com/scrapesage/website-contact-scraper)** - emails, phones & socials from any list of domains (pairs perfectly with this actor).
- **[Google Ads Transparency Scraper](https://apify.com/scrapesage/google-ads-transparency-scraper)** - see who's advertising what on Google.
- **[Facebook Ad Library Scraper](https://apify.com/scrapesage/facebook-ad-library-scraper)** - competitor ad intelligence.
- **[Bark Listing Scraper](https://apify.com/scrapesage/bark-listing-scraper)** - service-provider leads from Bark.
- **[Thumbtack Scraper](https://apify.com/scrapesage/thumbtack-scraper)** - home-service pro leads, reviews & hire data.
- **[BBB Scraper](https://apify.com/scrapesage/bbb-scraper)** - Better Business Bureau profiles, ratings & accreditation.
- **[Eventbrite Scraper](https://apify.com/scrapesage/eventbrite-scraper)** - events plus organizer leads with emails.
- **[LinkedIn Jobs Scraper](https://apify.com/scrapesage/linkedin-jobs-scraper)** - job postings as hiring-intent signals.

### Tips

- **Coverage**: set `maxPlacesPerSearch` above 120 (for example 2,000) to get every place in a city: each search is paged to its end and the area is then scanned map tile by map tile. For a whole state or country, list its cities as separate searches.
- **Find prospects who need a website**: set `websiteFilter` to *Only without a website*.
- **Cleaner leads**: combine `enrichContacts` with `withEmailOnly` to keep only places that have a reachable email.
- **Recurring monitoring**: turn on `monitorMode`, give each saved search its own `monitorKey`, and pair it with a [Schedule](https://docs.apify.com/platform/schedules) - after the first (baseline) run you only pay for places that are new or changed.
- **Refresh places you already have**: paste their `url` values (or place IDs) into **Place IDs** to fetch just those businesses again.
- **Big runs**: rows are saved search by search, so you can open the dataset while a long run is still going, and a run stopped by its time limit or cost cap keeps everything it found.
- **Proxies**: keep the default Apify Proxy; Google Maps responds cleanly through it.
- **Cost control**: the base search + contact enrichment is fast and cheap. Only turn on `scrapePlaceDetails` when you actually need review counts / full weekly hours - it adds one quick data request per place (about a second each, up to 16 in parallel) and the placeDetails event.

### FAQ

**How do I scrape Google Maps for a specific city?** Put the city in `locationQuery` (e.g. `Austin, TX`) and your category in `searchQueries` (e.g. `dentist`). The actor centres the search on that location automatically.

**How do I get more than 120 places per search?** Set **Max places per search** higher (for example 500 or 2,000). One Google search shows a limited list, so the actor pages it to the end and then searches the area again in smaller map tiles, nearest the centre first, until it reaches your number or stops finding new places. You pay per place delivered; the scan itself has no extra fee.

**Does it need a Google Maps / Places API key?** No. It reads Google Maps' own public data feed - no API key, no quota, no billing account, and far more fields than the official Places API returns.

**Where do the emails come from?** Never from Google Maps (it doesn't publish them). With `enrichContacts` on, the actor visits each business's own public website and extracts publicly listed contact emails and social links - the same thing a human visitor would see. Placeholder addresses that website templates leave behind (such as info@mysite.com) are filtered out.

**Does it work outside the US?** Yes. The search is centred on the location you name (add the country for ambiguous names), places far outside it are left out, and the address is split into street, city, region and postal code from Google's own structured address in every country. Results come back in the language you choose (`language`).

**Can I scrape specific places I already know?** Yes - paste Google place IDs (`ChIJ…`), feature IDs, place links or this actor's own `url` values into **Place IDs** or **Google Maps URLs**; each is fetched directly as that business.

**How do I get the review count and full weekly opening hours?** Turn on `scrapePlaceDetails`. The actor fetches each place's own Maps data record (the same call the Maps app makes) over HTTP and merges the total review count, the complete Monday–Sunday hours and a refined rating onto the row - roughly a second per place, no browser involved.

**Can I export to Google Sheets, CSV, or Excel?** Yes - one click in the dataset view, or automatically on every run via the [Google Drive integration](https://docs.apify.com/platform/integrations/drive).

**How do I get only new businesses over time?** Turn on `monitorMode` and run on a [Schedule](https://docs.apify.com/platform/schedules); the actor remembers what it has seen and emits only new or changed places.

**Is scraping Google Maps legal?** This actor collects publicly available data only. You are responsible for using the data in compliance with applicable laws (GDPR/CCPA for personal data) and Google's terms.

**A field is missing on some records - why?** Some places genuinely don't publish a website, phone or email. To keep exports clean, a field is simply omitted when it has no value (so CSV/Excel files never contain blank filler columns) - it's missing because the data doesn't exist, not because the scraper skipped it.

### Disclaimer

**This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Google LLC or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.**

"Google Maps" and any related marks are the property of their respective owners and are used here only in a descriptive, nominative sense - to identify the publicly accessible website from which this Actor collects data. This Actor is not an official Google Maps product, is not authorised or certified by Google LLC, and does not distribute Google Maps software. It collects only publicly available information; you are responsible for ensuring your use of that data complies with applicable laws, regulations and the terms of the source website.

### Need help?

Open an issue on the actor's **Issues** tab, or visit the [Apify help center](https://help.apify.com/). Feature requests are welcome - this actor is actively maintained.

# Actor input Schema

## `searchQueries` (type: `array`):

What to search for on Google Maps - categories, business types or names, e.g. "coffee shops", "dentist", "plumbers", "law firms". Each term is combined with the location below.

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

City / area to search in, e.g. "Austin, TX", "New York, NY", "London, UK", "Berlin, Germany". The map is centred on this place and places far outside it are left out (see Max distance). Add the region or country to ambiguous names ("Portland, ME", "Paris, France"). Leave empty if you put the location inside the search term ("dentist in Houston, TX") or use coordinates / Google Maps links.

## `latitude` (type: `number`):

Explicit search-center latitude. Overrides the geocoded location. Use with longitude (and optionally zoom).

## `longitude` (type: `number`):

Explicit search-center longitude.

## `zoom` (type: `integer`):

Map zoom for the search viewport when using coordinates. Higher = tighter area, more local results. Typical city search: 12-14.

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

Paste Google Maps links: place links (…/maps/place/…, the app's "Share" links maps.app.goo.gl/…, and this actor's own `url` output …/maps/place/?q=place_id:…) are looked up as that one business; search links (…/maps/search/<term>/@lat,lng,zoomz) run as a search of that map area.

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

Look up specific businesses by Google place ID (ChIJ…), feature ID (0x…:0x…) or place link, one per line - for example to refresh places you scraped before. Each one is fetched directly and billed as one place.

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

How many places to collect per search term + location. One Google search shows about 120 places; set this higher (for example 500 or 2,000) and the actor scans the search area map tile by map tile to go past that limit (slower, more places). Max results still caps the whole run.

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

Cap on the number of place records saved (after filtering). Rows are saved search by search as they are ready, so the dataset fills while the run is going and a stopped run keeps everything found so far.

## `maxDistanceKm` (type: `integer`):

Leave places farther than this from the centre of the location (or of the given coordinates / map link) out of the results. 0 = automatic: a radius sized to the place you searched (at least 40 km, wider for big metros, states and countries). Places left out are not charged.

## `enrichContacts` (type: `boolean`):

For every place that has a website, crawl its home + contact/about page and extract publicly listed e-mail addresses, social profiles (Facebook, Instagram, LinkedIn, X, YouTube, TikTok) and phone numbers, turning each place into a ready-to-contact B2B lead. Google Maps never exposes emails; this is the only way to get them. A place is billed as an enriched lead only when its website gives an e-mail, a social profile or a phone number the listing does not already show; otherwise it is billed as a plain place.

## `scrapePlaceDetails` (type: `boolean`):

Add the review count, the complete Monday–Sunday opening hours (in any language), a refined rating and (where Google shows one) a popular-times flag to each place. Fetched from Google Maps' own place data call over plain HTTP - about a second per place with up to 16 in parallel - and billed per place that actually got details (placeDetails event). Leave off for the cheapest run; turn on when you need review counts and full hours.

## `detailConcurrency` (type: `integer`):

How many place-detail requests run in parallel when "Scrape place details" is on. Details are fetched over plain HTTP (no browser), so 8-16 is safe; lower it only if Google starts rate-limiting a very large run.

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

Keep only places with at least this average rating (e.g. 4.0). Leave empty for all.

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

Keep only places whose Google category contains any of these words (case-insensitive), e.g. "restaurant", "bar". Useful to narrow a broad search.

## `websiteFilter` (type: `string`):

Keep all places, only those with a website, or only those without one (great for finding businesses that need a site).

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

Drop places marked as permanently or temporarily closed.

## `withPhoneOnly` (type: `boolean`):

Keep only places that have a phone number.

## `withEmailOnly` (type: `boolean`):

Keep only places for which contact enrichment found at least one e-mail address. Turn on "Enrich contacts" too.

## `nameQuery` (type: `string`):

Keep only places whose name contains this text (case-insensitive).

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

Google language code for results, e.g. en, es, de, fr, pt.

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

Google country code biasing results, e.g. us, gb, de, au, br.

## `sortBy` (type: `string`):

Ordering of the rows within each saved batch (rows are saved search by search, in batches of up to 150 places; for one overall order, sort the exported file).

## `includeRawFields` (type: `boolean`):

Attach Google's raw place array (sourceArray) to each record for full transparency / advanced parsing.

## `monitorMode` (type: `boolean`):

Remember places across runs and emit only NEW or CHANGED ones (phone, website, rating or address change). The first run is the baseline: it saves up to Max results and remembers every other place it scanned, so later runs only deliver places that were never seen before (plus changes to delivered ones). Great for watching a city/category for new businesses. Pair it with an Apify Schedule to run on a cadence.

## `monitorKey` (type: `string`):

Namespace for monitor memory. Use a distinct key per saved search so their states don't collide.

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

Google Maps responds cleanly from Apify Proxy. The default (automatic) proxy is recommended.

## `urlsFromFile` (type: `string`):

Paste a list of URLs (one per line), OR one link to a .txt/.csv file, Google Sheet or Google Drive file containing them. Lets you import many Start URLs at once instead of typing each. Google Sheet/Drive share links are handled automatically.

## Actor input object example

```json
{
  "searchQueries": [
    "coffee shops",
    "dentist"
  ],
  "locationQuery": "Austin, TX",
  "maxPlacesPerSearch": 120,
  "maxResults": 1000,
  "maxDistanceKm": 0,
  "enrichContacts": false,
  "scrapePlaceDetails": false,
  "detailConcurrency": 8,
  "minRating": "",
  "websiteFilter": "all",
  "skipClosedPlaces": false,
  "withPhoneOnly": false,
  "withEmailOnly": false,
  "language": "en",
  "countryCode": "us",
  "sortBy": "leadScore",
  "includeRawFields": false,
  "monitorMode": false,
  "monitorKey": "default",
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "urlsFromFile": ""
}
```

# Actor output Schema

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

All scraped Google Maps place records as JSON items in the default dataset.

# 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 = {
    "searchQueries": [
        "restaurants"
    ],
    "locationQuery": "Austin, TX",
    "urlsFromFile": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesage/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 = {
    "searchQueries": ["restaurants"],
    "locationQuery": "Austin, TX",
    "urlsFromFile": "",
}

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/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 '{
  "searchQueries": [
    "restaurants"
  ],
  "locationQuery": "Austin, TX",
  "urlsFromFile": ""
}' |
apify call scrapesage/google-maps-scraper --silent --output-dataset

```

## MCP server setup

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