# Google Maps Scraper (`labrat011/google-maps-scraper`) Actor

Scrape Google Maps places, reviews, and business leads at scale. No API keys. No login. No browser. Pure HTTP — fast, cheap, and reliable. Built for lead generation, local SEO research, competitor intelligence, and AI agents.

- **URL**: https://apify.com/labrat011/google-maps-scraper.md
- **Developed by:** [mick\_](https://apify.com/labrat011) (community)
- **Categories:** Lead generation, Social media, Travel
- **Stats:** 2 total users, 1 monthly users, 83.3% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 place results

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 & Business Leads

Scrape Google Maps places, reviews, and business leads at scale. **No API keys. No login. No browser.** Pure HTTP — fast, cheap, and reliable. Built for lead generation, local SEO research, competitor intelligence, and AI agents.

**Cheaper than [compass/crawler-google-places](https://apify.com/compass/crawler-google-places).** Starts at **$0.80 per 1,000 places** — 62% cheaper than the #1 competitor, with native batch search and LinkedIn lead enrichment built in.

---

### What it does

This actor extracts structured business data from Google Maps' public search pages. It supports single searches, massive batch searches across many keywords and locations in one run, direct place URL ingestion, and GeoJSON polygon targeting. Output is flat JSON, ready to feed into your CRM, lead-gen pipeline, or AI agent.

**Key data extracted:**
- Business name, address, phone, website, categories
- Star rating, review count, price level (`$` to `$$$$`)
- Latitude / longitude coordinates
- Opening hours (day-by-day)
- Permanently / temporarily closed flags
- Review text + star rating (up to 500 per place)
- **Light review sentiment** — positive / neutral / negative counts (no LLM cost)
- **Email + social profile enrichment** (optional) — pulled from the place's website
- **LinkedIn search URL** (optional) — pairs perfectly with [labrat011/linkedin-jobs-scraper](https://apify.com/labrat011/linkedin-jobs-scraper) for full B2B lead pipelines
- Google `placeId` + `googleCid` for cross-referencing with the Places API

---

### Why this scraper

| | This actor | [compass/crawler-google-places](https://apify.com/compass/crawler-google-places) |
|---|---|---|
| **Price per 1k places (base)** | **$0.80** | $2.10 |
| **Price per 1k places + full details** | **$1.50** | Higher |
| **Price per 1k reviews** | **$0.40** | Bundled / variable |
| **Memory** | **512 MB–1 GB** | Up to 8 GB |
| **Tech** | Pure HTTP (no browser) | Headless Chrome |
| **Batch keywords × locations** | ✅ Native Cartesian product | ⚠️ One search per run |
| **Global deduplication** | ✅ By `placeId` + `googleCid` | Within run only |
| **GeoJSON input** | ✅ Point + Polygon | ✅ Polygon only |
| **Email + social enrichment** | ✅ Optional (`$1.50/1k leads`) | 💰 Paid add-on |
| **LinkedIn integration** | ✅ Ready-to-use search URL | ❌ |
| **Output views** | `places`, `reviews`, `leads` | Single schema |
| **MCP-ready for AI agents** | ✅ | ⚠️ Limited |

---

### Use cases

#### 🎯 Lead Generation
Turn Google Maps into a prospect pipeline:
- Find every dentist, coffee shop, plumber, or SaaS company in your target city
- Extract emails and social profile links from their websites (optional)
- Qualify by rating and review count
- Auto-generate LinkedIn search URLs for decision-maker research
- Feed into HubSpot, Salesforce, Clay, or any CRM via Apify integrations

#### 📈 Local SEO Research
- Audit every competitor in a geographic area
- Compare ratings, review counts, and category saturation
- Track which businesses dominate the local pack for a given keyword
- Spot gaps and opportunities in underserved neighborhoods

#### 🔍 Competitor Intelligence
- Snapshot entire categories (e.g. "all yoga studios in Austin")
- Monitor reviews and sentiment over time (re-run weekly)
- Identify newcomers, closures, and rating trends
- Export to BI tools for dashboarding

#### 🤖 AI Agent Integration (MCP)
Use this actor as a live data source for AI agents:
- Ask Claude, GPT, or any MCP-compatible agent to search Google Maps in real time
- Build grounded RAG pipelines with current business data
- Let agents pull restaurant hours, phone numbers, or reviews on demand
- No authentication required — works out of the box with Apify's hosted MCP server

#### 📊 Market Research
- Study category density across cities and countries
- Analyze price level distributions, rating distributions, category taxonomies
- Extract phone numbers and websites for outbound campaigns

---

### Key features

- **No API key, login, or cookies** — scrapes public pages only
- **No browser / no Playwright** — pure HTTP, lower cost, faster execution
- **Batch search** — cross-multiply keywords × locations in one run
- **Direct place URL ingestion** — skip search, feed your existing list
- **Custom GeoJSON** — Point or Polygon for precise area targeting
- **Global deduplication** — by `placeId` and `googleCid` across the entire run
- **Review sentiment** — rating-based positive/neutral/negative counts (zero LLM cost)
- **Contact enrichment** — email + social profile scraping from place websites (optional)
- **LinkedIn integration** — auto-generated LinkedIn search URL per result (optional, free)
- **Output views** — `places`, `reviews`, `leads` presets for clean downstream use
- **Rating + closed-status filters** — drop low-quality or inactive places
- **Residential proxy rotation** — fresh IP on 429/403 to survive blocks
- **Resume on migration** — Apify state survives actor migrations mid-run
- **MCP-ready** — works as an AI agent tool via Apify's hosted MCP server

---

### Output format

#### Places view (default)

```json
{
  "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
  "googleCid": "0x89c25855c6480299:0x55194eb0b1bb2a3c",
  "name": "Blue Bottle Coffee",
  "address": "2001 E Cesar Chavez St, Austin, TX 78702",
  "categories": ["Coffee shop", "Cafe", "Breakfast restaurant"],
  "categoryMain": "Coffee shop",
  "rating": 4.6,
  "reviewCount": 512,
  "phone": "+1 512-524-1544",
  "website": "https://bluebottlecoffee.com/",
  "priceLevel": "$$",
  "latitude": 30.2592,
  "longitude": -97.7242,
  "openingHours": {
    "Monday": "7:00 AM – 6:00 PM",
    "Tuesday": "7:00 AM – 6:00 PM"
  },
  "thumbnailUrl": "https://lh5.googleusercontent.com/...",
  "images": ["https://lh5.googleusercontent.com/..."],
  "placeUrl": "https://www.google.com/maps/place/Blue+Bottle+Coffee/@30.2592,-97.7242,15z",
  "streetViewUrl": "https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=30.2592,-97.7242",
  "permanentlyClosed": false,
  "temporarilyClosed": false,
  "searchKeywords": "coffee shops",
  "searchLocation": "Austin, TX",
  "reviews": [
    { "rating": 5, "text": "Amazing espresso. Friendly staff." }
  ],
  "reviewSentiment": { "positive": 8, "neutral": 1, "negative": 1, "total": 10 },
  "scrapedAt": "2026-04-22T18:34:00+00:00"
}
````

#### Leads view (contact-ready)

```json
{
  "name": "Blue Bottle Coffee",
  "categoryMain": "Coffee shop",
  "phone": "+1 512-524-1544",
  "website": "https://bluebottlecoffee.com/",
  "emails": ["hello@bluebottlecoffee.com"],
  "socialProfiles": {
    "instagram": "https://instagram.com/bluebottle",
    "facebook": "https://facebook.com/bluebottlecoffee"
  },
  "linkedinSearchUrl": "https://www.linkedin.com/search/results/companies/?keywords=Blue%20Bottle%20Coffee",
  "address": "2001 E Cesar Chavez St, Austin, TX 78702",
  "rating": 4.6,
  "reviewCount": 512
}
```

***

### Input reference

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | string | — | Single keyword search (e.g. `coffee shops`) |
| `location` | string | — | Single location (e.g. `Austin, TX`) |
| `keywordsList` | string\[] | — | Batch keywords (overrides `keywords`) |
| `locationsList` | string\[] | — | Batch locations (overrides `location`) |
| `placeUrls` | string\[] | — | Skip search — scrape these Google Maps URLs directly |
| `customGeolocation` | object | — | GeoJSON Point or Polygon for precise targeting |
| `language` | select | `en` | Language code (ISO 639-1) |
| `countryCode` | select | `us` | Country code (ISO 3166-1 alpha-2) |
| `minRating` | select | 0 | `0`, `3`, `4`, `5` — drop places below this rating |
| `includeClosed` | boolean | `true` | Include permanently / temporarily closed places |
| `maxReviewsPerPlace` | integer | `10` | 0 to skip reviews entirely |
| `includeReviewSentiment` | boolean | `true` | Adds positive/neutral/negative review counts |
| `enrichDetails` | boolean | `false` | Visit each place's detail page for phone, website, opening hours, and images. Adds ~8-10 s per place |
| `enrichContacts` | boolean | `false` | Scrape email + socials from each place's website |
| `enrichLinkedIn` | boolean | `false` | Adds LinkedIn search URL per result (free) |
| `outputView` | select | `places` | `places`, `reviews`, or `leads` |
| `maxResults` | integer | `100` | Total cap across all searches (free: 25, paid: 10,000) |
| `maxResultsPerSearch` | integer | `100` | Cap per keyword × location combo |
| `proxyConfiguration` | object | RESIDENTIAL | Residential strongly recommended |

***

### Batch search example

Scrape three categories across three cities in one run:

```json
{
  "keywordsList": ["coffee shops", "coworking spaces", "yoga studios"],
  "locationsList": ["Austin, TX", "Dallas, TX", "Houston, TX"],
  "maxReviewsPerPlace": 5,
  "minRating": 4,
  "enrichLinkedIn": true,
  "maxResultsPerSearch": 20
}
```

This runs 9 searches (3 × 3), returns up to 180 places, deduplicates by `placeId` + `googleCid` across the whole run, and tags each result with `searchKeywords` + `searchLocation`.

***

### Lead-generation example

Find every high-rated dental practice in Dallas and extract their emails + social profiles:

```json
{
  "keywords": "dentist",
  "location": "Dallas, TX",
  "minRating": 4,
  "enrichDetails": true,
  "enrichContacts": true,
  "enrichLinkedIn": true,
  "outputView": "leads",
  "maxResults": 250
}
```

Every result includes phone, website, scraped emails, Instagram/Facebook/LinkedIn URLs, and a LinkedIn company search URL — pipe directly into Clay, HubSpot, or your cold-email tool.

***

### Pairs perfectly with [labrat011/linkedin-jobs-scraper](https://apify.com/labrat011/linkedin-jobs-scraper)

Run this actor first to get a list of target companies with `enrichLinkedIn: true`, then feed the `linkedinSearchUrl` or business names into `labrat011/linkedin-jobs-scraper`'s `companyFilter` field to pull current hiring managers, recruiters, and employee counts. Full B2B lead pipeline with **zero browser infrastructure**, at a fraction of the typical Clay / ZoomInfo cost.

***

### Pricing (Pay-Per-Event + Usage)

Pay only for what you get. Base charge covers every place returned; optional upgrade charges fire only when you actually receive the extra data. No monthly fees. Apify compute + proxy traffic is passed through at cost on top.

| Event | Price | Triggered when |
|---|---|---|
| **Place result** (`apify-default-dataset-item`) | **$0.0008** ($0.80 / 1k) | Every place in the dataset — name, rating, category, address, coordinates, thumbnail, Street View URL |
| **Detail-enriched place** (`result_detail_enriched`) | **$0.0007** ($0.70 / 1k) | When `enrichDetails: true` returned phone, website, full opening hours, or images |
| **Review extracted** (`result_review`) | **$0.0004** ($0.40 / 1k) | Per review attached to a place |
| **Contact-enriched lead** (`result_lead`) | **$0.0015** ($1.50 / 1k) | When `enrichContacts: true` yielded at least one email or social profile |
| **LinkedIn search URL** (`enrichLinkedIn`) | **FREE** | Every place when enabled |
| **Street View URL** | **FREE** | Every place with coordinates |
| Actor start (`apify-actor-start`) | $0.00005 (first 5s waived) | Once per run |

**Free tier:** 25 places per run. Reviews, detail enrichment, and contact enrichment disabled. Try before you subscribe.

#### Cost examples

Basic run — 1,000 places, no reviews, no enrichment:
`1,000 × $0.0008 = $0.80`

Full-data run — 1,000 places with detail enrichment, 5 reviews each, contact enrichment hitting 60%:
`$0.80 + (1,000 × $0.0007) + (5,000 × $0.0004) + (600 × $0.0015)`
`= $0.80 + $0.70 + $2.00 + $0.90 = $4.40`

Compass charges roughly `1,000 × $0.0021 = $2.10` for places alone, plus separate fees for reviews and contact enrichment. This actor is **62% cheaper on the base rate** and transparent on every upgrade.

***

### MCP Integration

Use this actor as a real-time tool for AI agents — no custom MCP server needed.

- **Endpoint:** `https://mcp.apify.com?tools=labrat011/google-maps-scraper`
- **Auth:** `Authorization: Bearer <APIFY_TOKEN>`
- **Transport:** Streamable HTTP
- **Compatible with:** Claude Desktop, Cursor, VS Code, Windsurf, Warp, Gemini CLI

**Claude Desktop / Cursor config:**

```json
{
  "mcpServers": {
    "google-maps-scraper": {
      "url": "https://mcp.apify.com?tools=labrat011/google-maps-scraper",
      "headers": {
        "Authorization": "Bearer <APIFY_TOKEN>"
      }
    }
  }
}
```

Once connected, your AI agent can search Google Maps by keyword + location, pull reviews, extract business contact info, and generate LinkedIn research URLs — all from a natural language prompt.

***

### Proxy guidance

Google aggressively blocks datacenter IPs on Maps. **Residential proxies are strongly recommended.** The actor defaults to Apify's RESIDENTIAL proxy group and will fail on Apify if no proxy is configured — this saves you compute on a run that would never succeed.

With residential proxies, the actor reliably handles runs of thousands of places. On retry, a fresh proxy IP is requested automatically so Google sees a different IP instead of the blocked one.

***

### Timeout & memory guidance

Detail enrichment, reviews, and contact enrichment each add requests per place, so runtime scales with your result count and which upgrades you enable.

| Max results | Detail | Reviews | Contacts | Est. runtime | Recommended timeout |
|---|---|---|---|---|---|
| 25 (free tier) | false | 0 | false | ~45 s | 180 s |
| 25 | true | 0 | false | ~4 min | 600 s |
| 100 | false | 10 | false | ~10 min | 900 s |
| 100 | true | 10 | false | ~20 min | 1800 s |
| 250 | true | 10 | true | ~50 min | 3600 s |
| 1,000 | false | 5 | false | ~1 hr | 4500 s |
| 5,000 | false | 0 | false | ~3 hr | 14400 s |

**Memory:** 512 MB is enough for most runs. Use 1 GB for runs > 500 results or with contact enrichment enabled.

***

### Limitations

- Google Maps caps per-area results at ~120 places — use multiple tight locations or GeoJSON polygons to drill into dense areas
- Review extraction is limited to what Google renders on the place page HTML — typically up to 500 reviews per place, sorted by relevance
- Email / social enrichment depends on the business website linking socials publicly and showing emails in HTML (not hidden behind obfuscation)
- LinkedIn search URLs are built from business names — accuracy depends on the name being unique (a company named "Acme" will return many false matches)
- Contact enrichment adds one request per unique website, cached within the run
- Opening hours follow Google's localized format (day names match the `language` setting)

***

### Legality

This actor only accesses publicly visible Google Maps data — the same information any browser visitor can see. It does not bypass login walls, solve CAPTCHAs, or access private data. Web scraping of publicly available data is generally legal, as established by the **hiQ Labs v. LinkedIn** ruling. However:

- Always check Google's Terms of Service before using scraped data commercially
- GDPR / CCPA apply when scraping personal data — handle emails and phone numbers responsibly
- Do not re-publish scraped content verbatim — use it for research, enrichment, and private internal workflows

You are responsible for your own compliance.

***

### FAQ

#### Do I need a Google Maps API key?

No. This actor scrapes public HTML pages and requires no Google credentials.

#### Will I get blocked by Google?

Not with residential proxies. Datacenter IPs get blocked within a few requests. The actor defaults to RESIDENTIAL proxy group and rotates IPs automatically on 429/403.

#### Why is my run returning fewer results than maxResults?

Google caps per-area results at ~120 places. To get more, use tighter locations (city neighborhoods, ZIP codes) or custom GeoJSON polygons that subdivide large areas.

#### How do I scrape only 5-star places?

Set `minRating: 5` in your input. The actor will skip any place rated below 5 stars.

#### Can I use this for B2B lead generation?

Yes — enable `enrichContacts` for emails + social profiles, and `enrichLinkedIn` for LinkedIn search URLs. Pair with [labrat011/linkedin-jobs-scraper](https://apify.com/labrat011/linkedin-jobs-scraper) for hiring-manager / recruiter research.

#### What's the difference between `placeId` and `googleCid`?

`placeId` is Google's canonical place identifier (what the Places API uses). `googleCid` is an older hex-encoded ID still embedded in Google Maps URLs. Both are included for cross-referencing with other tools.

#### Does the actor support pagination beyond 120 results per query?

Not directly — Google enforces a hard cap. Use batch mode (`keywordsList` × `locationsList`) or GeoJSON tiles to cover large areas.

#### Can I resume a failed run?

Yes. Apify state survives actor migrations; the actor picks up where it left off. For very large runs, split across multiple smaller jobs for resilience.

***

### Support

Open an issue on the [GitHub repo](https://github.com/labrat-0/google-maps-scraper) or message me through the Apify platform. PRs welcome.

# Actor input Schema

## `keywords` (type: `string`):

Business type, category, or keyword to search (e.g. 'coffee shops', 'dentists', 'plumbers near me'). Combined with Location to form the search query. Use Keywords List below for batch mode.

## `location` (type: `string`):

Where to search (e.g. 'Austin, TX', 'London, UK', '10001'). Free-text — accepts city, neighborhood, ZIP, or country. Use Locations List below for batch mode. Or use Custom Geolocation below for precise polygon targeting.

## `keywordsList` (type: `array`):

Run many keyword searches in one job. Combined with every entry in Locations List — e.g. \['dentist', 'orthodontist'] × \['Austin, TX', 'Dallas, TX'] = 4 searches, one run. Overrides the single Keywords field when provided.

## `locationsList` (type: `array`):

Multiple locations to search across in batch mode. Cross-multiplied with Keywords List. Leave empty or pass a single country to search broadly.

## `placeUrls` (type: `array`):

Skip search and scrape these Google Maps place URLs directly. Useful when you already have a list of businesses from a previous run, a spreadsheet, or the Places API.

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

Optional GeoJSON Point or Polygon for precise area targeting. When provided, the scraper searches within the geometry instead of free-text location. Supports { "type": "Point", "coordinates": \[lng, lat] } or { "type": "Polygon", "coordinates": \[\[\[lng, lat], ...]] }.

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

Language code for Google Maps (ISO 639-1). Affects place names, categories, and reviews.

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

Country code for Google Maps regional bias (ISO 3166-1 alpha-2, lowercase).

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

Only include places with at least this star rating.

## `includeClosed` (type: `boolean`):

When disabled, skips places marked permanently or temporarily closed on Google Maps.

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

How many reviews to extract for each place. Set to 0 to skip reviews entirely. Default 10 balances cost and signal.

## `includeReviewSentiment` (type: `boolean`):

Adds a simple positive/neutral/negative breakdown based on review star ratings. No LLM cost — adds zero to your bill.

## `reviewLanguage` (type: `string`):

Language code for reviews (ISO 639-1). Leave as 'en' for English.

## `enrichDetails` (type: `boolean`):

Visit each place's detail page to extract phone number, website, full opening hours, and photos. Adds ~8-10 seconds per place. Disabled by default — basic results (name, rating, category, address, coordinates) are extracted from the search page without this.

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

When enabled, fetches each place's website and extracts emails, Facebook, Instagram, Twitter/X, LinkedIn, YouTube, TikTok, and Pinterest profile URLs. Cached per unique website within the run.

## `enrichLinkedIn` (type: `boolean`):

Adds a ready-to-use LinkedIn company search URL to each result — feed it straight into labrat011/linkedin-jobs-scraper's companyFilter for full lead pipelines. Free.

## `outputView` (type: `string`):

Pre-filter results for common use cases. 'places' returns full place records, 'reviews' focuses on review data, 'leads' returns only contact-ready fields.

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

Maximum total places to return. Free users capped at 25. Subscribe for up to 10,000.

## `maxResultsPerSearch` (type: `integer`):

Cap per keyword/location combination in batch mode. Example: 3 keywords × 2 locations × 20 per search = up to 120 total results.

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

Proxy settings. RESIDENTIAL is required for reliable browser-based scraping. Do not use GOOGLE\_SERP here — it only supports plain HTTP fetching (not HTTPS tunneling) and will fail Playwright navigation.

## Actor input object example

```json
{
  "keywords": "coffee shops",
  "location": "Austin, TX",
  "keywordsList": [
    "coffee shops",
    "coworking spaces",
    "yoga studios"
  ],
  "locationsList": [
    "Austin, TX",
    "Dallas, TX",
    "Houston, TX"
  ],
  "placeUrls": [
    "https://www.google.com/maps/place/Example+Cafe/@30.2672,-97.7431,15z"
  ],
  "customGeolocation": {
    "type": "Point",
    "coordinates": [
      -97.7431,
      30.2672
    ]
  },
  "language": "en",
  "countryCode": "us",
  "minRating": "0",
  "includeClosed": true,
  "maxReviewsPerPlace": 10,
  "includeReviewSentiment": true,
  "reviewLanguage": "en",
  "enrichDetails": false,
  "enrichContacts": false,
  "enrichLinkedIn": false,
  "outputView": "places",
  "maxResults": 25,
  "maxResultsPerSearch": 25,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Scraped places — names, ratings, phone, website, coordinates, categories, opening hours, reviews, and optional contact/LinkedIn enrichment.

# 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 = {
    "keywords": "coffee shops",
    "location": "Austin, TX",
    "maxResults": 25,
    "maxResultsPerSearch": 25,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("labrat011/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 = {
    "keywords": "coffee shops",
    "location": "Austin, TX",
    "maxResults": 25,
    "maxResultsPerSearch": 25,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("labrat011/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 '{
  "keywords": "coffee shops",
  "location": "Austin, TX",
  "maxResults": 25,
  "maxResultsPerSearch": 25,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call labrat011/google-maps-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Scraper",
        "description": "Scrape Google Maps places, reviews, and business leads at scale. No API keys. No login. No browser. Pure HTTP — fast, cheap, and reliable. Built for lead generation, local SEO research, competitor intelligence, and AI agents.",
        "version": "0.0",
        "x-build-id": "YnSHrsust686m4sXj"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/labrat011~google-maps-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-labrat011-google-maps-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/labrat011~google-maps-scraper/runs": {
            "post": {
                "operationId": "runs-sync-labrat011-google-maps-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/labrat011~google-maps-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-labrat011-google-maps-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "keywords": {
                        "title": "🔍 Keywords",
                        "type": "string",
                        "description": "Business type, category, or keyword to search (e.g. 'coffee shops', 'dentists', 'plumbers near me'). Combined with Location to form the search query. Use Keywords List below for batch mode."
                    },
                    "location": {
                        "title": "📍 Location",
                        "type": "string",
                        "description": "Where to search (e.g. 'Austin, TX', 'London, UK', '10001'). Free-text — accepts city, neighborhood, ZIP, or country. Use Locations List below for batch mode. Or use Custom Geolocation below for precise polygon targeting."
                    },
                    "keywordsList": {
                        "title": "📋 Keywords List (Batch Mode)",
                        "type": "array",
                        "description": "Run many keyword searches in one job. Combined with every entry in Locations List — e.g. ['dentist', 'orthodontist'] × ['Austin, TX', 'Dallas, TX'] = 4 searches, one run. Overrides the single Keywords field when provided.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "locationsList": {
                        "title": "🗺️ Locations List (Batch Mode)",
                        "type": "array",
                        "description": "Multiple locations to search across in batch mode. Cross-multiplied with Keywords List. Leave empty or pass a single country to search broadly.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "placeUrls": {
                        "title": "🔗 Direct Place URLs",
                        "type": "array",
                        "description": "Skip search and scrape these Google Maps place URLs directly. Useful when you already have a list of businesses from a previous run, a spreadsheet, or the Places API.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "customGeolocation": {
                        "title": "🌐 Custom Geolocation (GeoJSON)",
                        "type": "object",
                        "description": "Optional GeoJSON Point or Polygon for precise area targeting. When provided, the scraper searches within the geometry instead of free-text location. Supports { \"type\": \"Point\", \"coordinates\": [lng, lat] } or { \"type\": \"Polygon\", \"coordinates\": [[[lng, lat], ...]] }."
                    },
                    "language": {
                        "title": "🌐 Language",
                        "enum": [
                            "en",
                            "es",
                            "fr",
                            "de",
                            "it",
                            "pt",
                            "nl",
                            "pl",
                            "ja",
                            "zh-CN",
                            "ko",
                            "ru",
                            "tr",
                            "ar"
                        ],
                        "type": "string",
                        "description": "Language code for Google Maps (ISO 639-1). Affects place names, categories, and reviews.",
                        "default": "en"
                    },
                    "countryCode": {
                        "title": "🏳️ Country Code",
                        "enum": [
                            "us",
                            "gb",
                            "ca",
                            "au",
                            "de",
                            "fr",
                            "es",
                            "it",
                            "nl",
                            "br",
                            "mx",
                            "jp",
                            "in",
                            "za",
                            "ae"
                        ],
                        "type": "string",
                        "description": "Country code for Google Maps regional bias (ISO 3166-1 alpha-2, lowercase).",
                        "default": "us"
                    },
                    "minRating": {
                        "title": "⭐ Minimum Rating",
                        "enum": [
                            "0",
                            "3",
                            "4",
                            "5"
                        ],
                        "type": "string",
                        "description": "Only include places with at least this star rating.",
                        "default": "0"
                    },
                    "includeClosed": {
                        "title": "🚫 Include Permanently Closed",
                        "type": "boolean",
                        "description": "When disabled, skips places marked permanently or temporarily closed on Google Maps.",
                        "default": true
                    },
                    "maxReviewsPerPlace": {
                        "title": "💬 Max Reviews per Place",
                        "minimum": 0,
                        "maximum": 500,
                        "type": "integer",
                        "description": "How many reviews to extract for each place. Set to 0 to skip reviews entirely. Default 10 balances cost and signal.",
                        "default": 10
                    },
                    "includeReviewSentiment": {
                        "title": "📊 Include Review Sentiment",
                        "type": "boolean",
                        "description": "Adds a simple positive/neutral/negative breakdown based on review star ratings. No LLM cost — adds zero to your bill.",
                        "default": true
                    },
                    "reviewLanguage": {
                        "title": "🗣️ Review Language",
                        "type": "string",
                        "description": "Language code for reviews (ISO 639-1). Leave as 'en' for English.",
                        "default": "en"
                    },
                    "enrichDetails": {
                        "title": "📋 Enrich Place Details (Phone, Website, Hours, Images)",
                        "type": "boolean",
                        "description": "Visit each place's detail page to extract phone number, website, full opening hours, and photos. Adds ~8-10 seconds per place. Disabled by default — basic results (name, rating, category, address, coordinates) are extracted from the search page without this.",
                        "default": false
                    },
                    "enrichContacts": {
                        "title": "📧 Enrich Contacts (Email + Social Profiles)",
                        "type": "boolean",
                        "description": "When enabled, fetches each place's website and extracts emails, Facebook, Instagram, Twitter/X, LinkedIn, YouTube, TikTok, and Pinterest profile URLs. Cached per unique website within the run.",
                        "default": false
                    },
                    "enrichLinkedIn": {
                        "title": "🔗 Enrich with LinkedIn Search URL",
                        "type": "boolean",
                        "description": "Adds a ready-to-use LinkedIn company search URL to each result — feed it straight into labrat011/linkedin-jobs-scraper's companyFilter for full lead pipelines. Free.",
                        "default": false
                    },
                    "outputView": {
                        "title": "📤 Output View",
                        "enum": [
                            "places",
                            "reviews",
                            "leads"
                        ],
                        "type": "string",
                        "description": "Pre-filter results for common use cases. 'places' returns full place records, 'reviews' focuses on review data, 'leads' returns only contact-ready fields.",
                        "default": "places"
                    },
                    "maxResults": {
                        "title": "📊 Max Results",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum total places to return. Free users capped at 25. Subscribe for up to 10,000.",
                        "default": 100
                    },
                    "maxResultsPerSearch": {
                        "title": "🔢 Max Results Per Search (Batch Mode)",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Cap per keyword/location combination in batch mode. Example: 3 keywords × 2 locations × 20 per search = up to 120 total results.",
                        "default": 100
                    },
                    "proxyConfiguration": {
                        "title": "🔒 Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings. RESIDENTIAL is required for reliable browser-based scraping. Do not use GOOGLE_SERP here — it only supports plain HTTP fetching (not HTTPS tunneling) and will fail Playwright navigation."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
