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

Extract business data from Google Maps — addresses, phones, websites, ratings, reviews, images, opening hours, popular times & more. Search by keyword, URL, Place ID, or custom GeoJSON area.

- **URL**: https://apify.com/lovely\_radiologist/google-maps-scraper.md
- **Developed by:** [Vivek Gaur](https://apify.com/lovely_radiologist) (community)
- **Categories:** Lead generation, Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 place scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 📍 Google Maps Scraper

Extract rich, structured data from any Google Maps place — business names, addresses, phone numbers, websites, ratings, reviews, images, opening hours, popular times, contact details, and much more. Supports keyword searches, direct place URLs, Place IDs, and custom GeoJSON area searches.

***

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

| Category | Fields |
|---|---|
| 🏷️ **Identity** | Title, subtitle, description, category, categories, Place ID |
| 📍 **Location** | Full address, street, city, state, postal code, country, coordinates (lat/lng), Plus Code |
| ☎️ **Contact** | Phone (formatted + raw), website URL |
| ⭐ **Rating** | Average score, review count, review distribution (1–5 stars) |
| 📝 **Reviews** | Reviewer name, photo, star rating, text, date, owner response, images, Local Guide status |
| 🖼️ **Images** | Full-resolution image URLs, optional author attribution |
| 🕐 **Hours** | Opening hours per day |
| 📊 **Popularity** | Popular times histogram (by hour/day), live occupancy text |
| ➕ **Attributes** | Service options, accessibility, atmosphere, dining, payments, amenities |
| 🔗 **Social** | Facebook, Instagram, LinkedIn, Twitter, YouTube, TikTok, Pinterest (from website) |
| 📧 **Contact enrichment** | Emails, extra phone numbers from the place''s own website |
| ❓ **Q\&As** | Community questions and answers |
| 🍽️ **Restaurant extras** | Price range, table reservation provider, food delivery links |
| 🏨 **Hotel extras** | Star rating, description |
| 🔍 **Discover** | "People also search for" related places |
| 🌐 **Web results** | External web results shown in the place listing |
| 🤖 **Competitor analysis** | Scored rankings, strengths/weaknesses, interactive HTML map |

***

### 🚀 Quick Start

#### 1. Search by keyword + location

```json
{
  "searchStringsArray": ["pizza restaurant"],
  "locationQuery": "Manhattan, New York, USA",
  "maxCrawledPlacesPerSearch": 50,
  "maxReviews": 5
}
```

#### 2. Scrape specific places by URL

```json
{
  "startUrls": [
    { "url": "https://www.google.com/maps/place/Eiffel+Tower/@48.8583701,2.2922926,17z" }
  ],
  "maxReviews": 20,
  "maxImages": 10,
  "scrapePlaceDetailPage": true
}
```

#### 3. Scrape by Place ID

```json
{
  "placeIds": ["ChIJN1t_tDeuEmsRUsoyG83frY4"],
  "scrapePlaceDetailPage": true,
  "maxReviews": 100
}
```

#### 4. Custom GeoJSON area (polygon)

```json
{
  "searchStringsArray": ["coffee shop"],
  "customGeolocation": {
    "type": "Polygon",
    "coordinates": [[
      [-74.02, 40.70], [-73.97, 40.70],
      [-73.97, 40.73], [-74.02, 40.73],
      [-74.02, 40.70]
    ]]
  }
}
```

#### 5. Lead generation — scrape contacts from websites

```json
{
  "searchStringsArray": ["law firm"],
  "locationQuery": "Chicago, USA",
  "maxCrawledPlacesPerSearch": 100,
  "scrapeContacts": true
}
```

***

### 📥 Input Parameters

#### 🔎 Search & Location

| Parameter | Type | Default | Description |
|---|---|---|---|
| `searchStringsArray` | string\[] | — | Search keywords (e.g. `["pizza", "burger"]`). Each runs a separate search. |
| `locationQuery` | string | — | Location in free text (e.g. `"New York, USA"` or `"Paris, France"`). Combined with search terms. |
| `language` | string | `"en"` | Language for results — ISO 639-1 code (`"en"`, `"fr"`, `"de"`, etc.) |
| `countryCode` | string | — | ISO country code for geolocation (`"US"`, `"GB"`, `"DE"`, etc.) |
| `city` | string | — | City name for precise geolocation |
| `state` | string | — | State or province for geolocation |
| `postalCode` | string | — | Postal/ZIP code (best combined with `countryCode`) |
| `customGeolocation` | object | — | GeoJSON geometry: Point (with `radiusKm`), Polygon, or MultiPolygon |
| `maxCrawledPlacesPerSearch` | integer | `50` | Max places per search query (1 – 10,000) |
| `startUrls` | object\[] | — | Direct Google Maps URLs to scrape (bypasses keyword search) |
| `placeIds` | string\[] | — | Google Place IDs to scrape directly (e.g. `ChIJ...`) |

#### 🔽 Filtering

| Parameter | Type | Default | Description |
|---|---|---|---|
| `categoryFilterWords` | string\[] | — | Include only places whose category contains one of these words |
| `searchMatching` | string | `"all"` | `all` · `only_includes` (name contains search term) · `only_exact` |
| `placeMinimumStars` | string | — | Minimum rating: `two`, `twoAndHalf`, `three`, `threeAndHalf`, `four`, `fourAndHalf` |
| `website` | string | `"allPlaces"` | `allPlaces` · `withWebsite` · `withoutWebsite` |
| `skipClosedPlaces` | boolean | `false` | Skip permanently or temporarily closed places |

#### 📝 Reviews

| Parameter | Type | Default | Description |
|---|---|---|---|
| `maxReviews` | integer | `0` | Reviews per place (`0` = none, `99999` = all available) |
| `reviewsSort` | string | `"newest"` | Sort order: `newest` · `mostRelevant` · `highestRanking` · `lowestRanking` |
| `reviewsStartDate` | string | — | Only reviews after this date (`YYYY-MM-DD` or e.g. `"3 months"`) |
| `reviewsFilterString` | string | — | Keyword filter — only reviews containing this phrase |
| `reviewsOrigin` | string | `"all"` | `all` sources or `google` only |
| `scrapeReviewsPersonalData` | boolean | `true` | Include reviewer name, photo, and profile URL |

#### 🖼️ Images

| Parameter | Type | Default | Description |
|---|---|---|---|
| `maxImages` | integer | `0` | Images per place (`0` = none, `99999` = all available) |
| `scrapeImageAuthors` | boolean | `false` | Include image author name and Google Maps profile URL |

#### 🔍 Detail Page & Extras

| Parameter | Type | Default | Description |
|---|---|---|---|
| `scrapePlaceDetailPage` | boolean | `false` | Scrape the full detail page. Required for: opening hours, popular times, Q\&As, amenities |
| `maxQuestions` | integer | `0` | Q\&A pairs to extract per place (`0` = none) |
| `scrapeTableReservation` | boolean | `false` | Extract table reservation provider (Resy, OpenTable, etc.) |
| `scrapeOrderOnline` | boolean | `false` | Extract food delivery / order-online providers |
| `includeWebResults` | boolean | `false` | Include external web results shown in the listing |
| `scrapeContacts` | boolean | `false` | Visit each place website to extract emails, phones, and social media links |

#### 🤖 Competitor Analysis

| Parameter | Type | Default | Description |
|---|---|---|---|
| `enableCompetitorAnalysis` | boolean | `false` | After scraping, generate a scored competitor report + interactive HTML map |

#### 🛡️ Proxy

| Parameter | Type | Description |
|---|---|---|
| `proxyConfiguration` | object | Proxy settings. Apify residential proxies recommended for Google Maps at scale. |

***

### 📤 Output Schema

Each scraped place is saved as one JSON item in the dataset:

```json
{
  "title": "Joe's Pizza",
  "subTitle": "Pizza restaurant",
  "description": "Classic NYC slice joint since 1975.",
  "price": "Under $10",
  "categoryName": "Pizza restaurant",
  "categories": ["Pizza restaurant", "Italian restaurant"],

  "address": "7 Carmine St, New York, NY 10014",
  "neighborhood": "Greenwich Village",
  "street": "7 Carmine St",
  "city": "New York",
  "state": "NY",
  "postalCode": "10014",
  "countryCode": "US",
  "lat": 40.7303,
  "lng": -74.0019,
  "plusCode": "Q22F+MF New York",

  "googleMapsUrl": "https://www.google.com/maps/place/...",
  "placeId": "ChIJD7fiBh9u5kcRYJSMaMOCCwQ",
  "website": "https://joespizzanyc.com",
  "phone": "(212) 255-3946",
  "phoneUnformatted": "(212) 255-3946",

  "totalScore": 4.5,
  "reviewsCount": 4200,
  "reviewsDistribution": {
    "oneStar": 50, "twoStar": 30, "threeStar": 120,
    "fourStar": 900, "fiveStar": 3100
  },

  "permanentlyClosed": false,
  "temporarilyClosed": false,
  "claimStatus": null,

  "openingHours": [
    { "day": "Monday", "hours": "10 AM–11 PM" },
    { "day": "Tuesday", "hours": "10 AM–11 PM" }
  ],

  "popularTimesHistogram": {
    "Mo": [{ "hour": 9, "occupancyPercent": 20 }, { "hour": 12, "occupancyPercent": 75 }],
    "Fr": [{ "hour": 18, "occupancyPercent": 95 }]
  },
  "popularTimesLiveText": "Usually not too busy",

  "additionalInfo": {
    "Service options": [{ "Dine-in": true }, { "Takeout": true }, { "Delivery": false }],
    "Accessibility": [{ "Wheelchair accessible entrance": true }],
    "Payments": [{ "Credit cards": true }, { "NFC mobile payments": true }]
  },

  "thumbnailUrl": "https://lh3.googleusercontent.com/...",
  "imageUrls": ["https://lh3.googleusercontent.com/..."],
  "images": [{ "imageUrl": "...", "authorName": "Alice Johnson", "authorUrl": "..." }],

  "reviews": [{
    "reviewId": "ChdDSUhNMG9nS0...",
    "reviewerName": "Bob Smith",
    "reviewerPhotoUrl": "https://lh3.googleusercontent.com/...",
    "reviewerNumberOfReviews": 42,
    "isLocalGuide": true,
    "stars": 5,
    "text": "Best pizza in NYC, no contest!",
    "publishAt": "2 months ago",
    "publishedAtDate": "2024-06-01",
    "likesCount": 12,
    "responseFromOwnerText": "Thank you so much!",
    "responseFromOwnerDate": "a month ago",
    "reviewImageUrls": [],
    "reviewDetailedRating": { "Food": 5, "Service": 5, "Atmosphere": 4 }
  }],

  "questions": [{ "question": "Is parking available?", "answer": "Street parking nearby." }],
  "peopleAlsoSearch": [{ "title": "John's Pizza", "totalScore": 4.3, "reviewsCount": 980 }],

  "reserveTableUrl": "https://www.google.com/maps/reserve/v/dine/...",
  "tableReservationProvider": "OpenTable",
  "orderOnlineUrls": [{ "provider": "Uber Eats", "url": "https://ubereats.com/..." }],

  "emails": ["contact@joespizzanyc.com"],
  "phones": ["+1 212-255-3946"],
  "facebook": "https://facebook.com/joespizzanyc",
  "instagram": "https://instagram.com/joespizzanyc",
  "linkedin": null,
  "twitter": "https://twitter.com/joespizzanyc",
  "youtube": null,
  "tiktok": null,
  "pinterest": null,

  "searchString": "pizza restaurant",
  "rank": 1,
  "scrapedAt": "2026-08-19T00:00:00.000Z"
}
```

***

### 📍 Geolocation Options

#### Free-text location (simplest)

Type any location into `locationQuery`:

- `"New York, USA"` · `"Paris, France"` · `"10001"` (postal code)

#### Structured geolocation (more precise)

Combine `countryCode`, `state`, `city`, `postalCode` for pinpoint accuracy.

#### GeoJSON custom area (most flexible)

**Circle** — search within a radius:

```json
{ "type": "Point", "coordinates": [-73.9857, 40.7484], "radiusKm": 5 }
```

**Polygon** — custom drawn area *(first and last coordinate must match to close the shape)*:

```json
{
  "type": "Polygon",
  "coordinates": [[
    [-0.3228, 51.5972], [-0.3150, 51.3880],
    [0.0605, 51.3892], [0.0519, 51.6004],
    [-0.3228, 51.5972]
  ]]
}
```

**MultiPolygon** — multiple disconnected areas in one run:

```json
{
  "type": "MultiPolygon",
  "coordinates": [
    [[[-74.02,40.70],[-73.97,40.70],[-73.97,40.73],[-74.02,40.73],[-74.02,40.70]]],
    [[[2.30,48.84],[2.37,48.84],[2.37,48.88],[2.30,48.88],[2.30,48.84]]]
  ]
}
```

> 💡 Use [geojson.io](https://geojson.io) to draw your area visually and copy the GeoJSON output.

> ⚠️ GeoJSON uses **longitude first, then latitude** — opposite of Google Maps.

***

### 🎯 Common Use Cases

#### 🧲 Lead generation

```json
{
  "searchStringsArray": ["dentist", "dental clinic"],
  "locationQuery": "Austin, Texas, USA",
  "maxCrawledPlacesPerSearch": 200,
  "scrapeContacts": true,
  "website": "withWebsite",
  "placeMinimumStars": "three"
}
```

#### 🏆 Competitor research

```json
{
  "searchStringsArray": ["italian restaurant"],
  "locationQuery": "Rome, Italy",
  "maxCrawledPlacesPerSearch": 50,
  "maxReviews": 20,
  "enableCompetitorAnalysis": true
}
```

#### 📅 Monitor recent reviews

```json
{
  "startUrls": [{ "url": "https://www.google.com/maps/place/Your+Business/..." }],
  "maxReviews": 50,
  "reviewsSort": "newest",
  "reviewsStartDate": "1 month"
}
```

#### 🍽️ Full restaurant profile

```json
{
  "searchStringsArray": ["sushi restaurant"],
  "locationQuery": "San Francisco, USA",
  "maxCrawledPlacesPerSearch": 30,
  "scrapePlaceDetailPage": true,
  "maxReviews": 10,
  "maxImages": 5,
  "scrapeTableReservation": true,
  "scrapeOrderOnline": true
}
```

***

### ⭐ Reviews in Detail

| Field | Description |
|---|---|
| `reviewId` | Unique Google review ID |
| `reviewerName` | Reviewer's display name |
| `reviewerPhotoUrl` | Profile photo URL |
| `reviewerNumberOfReviews` | Total reviews by this person |
| `isLocalGuide` | Whether reviewer is a Google Local Guide |
| `stars` | 1–5 star rating |
| `text` | Full review text |
| `publishAt` | Relative time ("2 months ago") |
| `publishedAtDate` | Absolute date |
| `likesCount` | "Helpful" likes count |
| `responseFromOwnerText` | Owner's reply |
| `reviewImageUrls` | Photos attached to the review |
| `reviewDetailedRating` | Per-category ratings (Food, Service, Atmosphere) |

**Sort:** `newest` · `mostRelevant` · `highestRanking` · `lowestRanking`

**Date filter:** `reviewsStartDate: "3 months"` or `"2024-01-01"`

**Keyword filter:** `reviewsFilterString: "parking"` → only reviews mentioning "parking"

***

### 📧 Contact Enrichment

When `scrapeContacts: true`, the scraper visits each place's website and extracts:

- 📧 **Emails** — from page text and `mailto:` links
- ☎️ **Extra phones** — beyond the Google Maps listing
- 📱 **Social media**: Facebook, Instagram, LinkedIn, Twitter/X, YouTube, TikTok, Pinterest

> Uses only publicly visible data on each business's own website. No paid APIs required.

***

### 🤖 Competitor Analysis

Enable with `enableCompetitorAnalysis: true`. After scraping completes, the actor:

1. **Scores each place** (0–100 composite): rating 50% + review volume 30% + data completeness 20%
2. **Ranks all places** from strongest to weakest
3. **Identifies signals** per place: exceptional rating, high review volume, missing website, etc.
4. **Produces a market summary**: competitive stats, gaps, and opportunities
5. **Generates an interactive HTML map** (dark mode):
   - 🟢 Top ranked → 🟡 Mid → 🔴 Lowest — color-coded pins
   - Clickable popups: rank, score, reviews, address
   - Sidebar leaderboard with score bars

> 💡 Use a single focused search term (e.g. `"italian restaurant"`) so all places are in the same category and can be meaningfully compared.

***

### 💡 Tips for Best Results

**More results**

- Use `locationQuery` — the scraper automatically splits large areas into a grid of searches, unlocking thousands of results past Google's 120-result cap.
- Multiple distinct search terms (`["restaurant", "bar", "cafe"]`) run separately and combine results.

**Cleaner results**

- Avoid near-duplicates like `["restaurant", "restaurants"]` — same results, slower run.
- Use `categoryFilterWords` to narrow broad searches.

**Reviews efficiently**

- Set `maxReviews` only as high as needed.
- Combine `reviewsSort: "newest"` + `reviewsStartDate` to collect only recent feedback.

**Proxy**

- For < 100 places, default proxies are fine.
- For large-scale runs or reviews, use Apify residential proxies for maximum reliability.

***

### 📊 Export Formats

| Format | Best for |
|---|---|
| **JSON** | Full nested structure, API ingestion |
| **CSV / Excel** | Spreadsheet analysis, CRM import |
| **XML** | Legacy system integrations |

For review analysis: use the **Reviews** dataset view to get **one row per review** instead of one row per place.

***

### ❓ FAQ

**How is this different from the Google Places API?**
The Google Places API caps results at 60 per search and requires billing. This scraper has no result cap, no API key, and extracts more fields (popular times, full reviews, images, contact enrichment).

**Can I scrape multiple cities in one run?**
Yes — use `customGeolocation` with a `MultiPolygon` containing one polygon per city.

**Can I scrape a specific list of businesses?**
Yes — provide Google Maps URLs in `startUrls` or Place IDs in `placeIds`.

**Can I schedule recurring runs?**
Yes — use Apify's built-in scheduling to run daily, weekly, or on any cron schedule.

**Is it legal?**
Scraping publicly visible business data is generally permitted. Handle reviewer personal data in accordance with GDPR/CCPA. Disable reviewer data collection with `scrapeReviewsPersonalData: false`.

***

### 🔗 Integrations & API

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("YOUR_ACTOR_ID").call(run_input={
    "searchStringsArray": ["coffee shop"],
    "locationQuery": "Berlin, Germany",
    "maxCrawledPlacesPerSearch": 100,
    "maxReviews": 5,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

**Node.js:**

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('YOUR_ACTOR_ID').call({
    searchStringsArray: ['coffee shop'],
    locationQuery: 'Berlin, Germany',
    maxCrawledPlacesPerSearch: 100,
    maxReviews: 5,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Also integrates with: **Zapier**, **Make**, **Google Sheets**, **Slack**, **Airbyte**, **LangChain**, and any tool supporting webhooks.

***

### 📬 Feedback & Issues

Found a bug or want a new feature? Open an issue on the actor's **Issues** tab. All feedback is actively monitored.

# Actor input Schema

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

List of search terms to scrape (e.g. \["pizza in New York", "hotels in Paris"]). Can include location in the search term.

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

Restrict search to a specific location (e.g. "New York, USA" or "Paris, France"). Combined with searchStringsArray.

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

Maximum number of places to scrape per search query. Default is 50.

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

Language for Google Maps results (ISO 639-1 code, e.g. "en", "fr", "de").

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

ISO 3166-1 alpha-2 country code for geolocation (e.g. "US", "GB", "DE").

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

City name for geolocation (e.g. "New York", "London").

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

State or province for geolocation (e.g. "New York", "California").

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

Postal/ZIP code for geolocation (best combined with countryCode).

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

Define a custom search area using a GeoJSON geometry. Supports Point (with radiusKm), Polygon, or MultiPolygon.

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

Direct Google Maps URLs to scrape (e.g. https://www.google.com/maps/place/...). Skip search, scrape these places directly.

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

List of Google Place IDs to scrape directly (starting with ChIJ or GhIJ).

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

Only include places whose category contains one of these words (e.g. \["pizza", "italian"]).

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

Restrict which places are included based on name matching with the search term.

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

Only include places with at least this many stars.

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

Filter places by whether they have a website.

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

Skip places that are permanently or temporarily closed.

## `scrapePlaceDetailPage` (type: `boolean`):

Scrape the full detail page for each place. Required for: opening hours, popular times, Q\&As, additional attributes, and full contact info. Increases time and cost.

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

Number of reviews to scrape per place. 0 = no reviews. Use 99999 to scrape all available (up to 5,000).

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

Sort order for reviews.

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

Only include reviews published after this date. Format: YYYY-MM-DD or relative (e.g. "3 months"). Requires reviewsSort = "newest".

## `reviewsFilterString` (type: `string`):

Only include reviews containing this keyword or phrase.

## `reviewsOrigin` (type: `string`):

Filter reviews by origin source.

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

Include reviewer name, profile URL, and photo in review results.

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

Number of images to scrape per place. 0 = no images. Use 99999 to scrape all available.

## `scrapeImageAuthors` (type: `boolean`):

Include the author name and profile URL for each scraped image.

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

Visit each place's website and extract publicly visible emails, phone numbers, and social media profiles (Facebook, Instagram, LinkedIn, Twitter, YouTube, TikTok).

## `maxQuestions` (type: `integer`):

Number of Questions & Answers to extract per place. Requires scrapePlaceDetailPage = true.

## `scrapeTableReservationProvider` (type: `boolean`):

Scrape table reservation provider info (e.g. Resy, OpenTable). For restaurants only. Requires scrapePlaceDetailPage = true.

## `scrapeOrderOnline` (type: `boolean`):

Scrape food delivery/order online widget data (providers, fees). Requires scrapePlaceDetailPage = true.

## `includeWebResults` (type: `boolean`):

Include the "Web results" section shown at the bottom of some place listings.

## `enableCompetitorAnalysis` (type: `boolean`):

After scraping, generate a competitor analysis report comparing all scraped places (rankings, strengths, strategic overview, HTML map visualization).

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

Proxy settings for requests. Use Apify residential proxies for best results on Google Maps.

## Actor input object example

```json
{
  "searchStringsArray": [
    "pizza in New York",
    "coffee shop in London"
  ],
  "locationQuery": "New York, USA",
  "maxCrawledPlacesPerSearch": 50,
  "language": "en",
  "customGeolocation": {
    "type": "Point",
    "coordinates": [
      -73.9857,
      40.7484
    ],
    "radiusKm": 5
  },
  "placeIds": [
    "ChIJN1t_tDeuEmsRUsoyG83frY4"
  ],
  "searchMatching": "all",
  "website": "allPlaces",
  "skipClosedPlaces": false,
  "scrapePlaceDetailPage": false,
  "maxReviews": 0,
  "reviewsSort": "newest",
  "reviewsStartDate": "2024-01-01",
  "reviewsOrigin": "all",
  "scrapeReviewsPersonalData": true,
  "maxImages": 0,
  "scrapeImageAuthors": false,
  "scrapeContacts": false,
  "maxQuestions": 0,
  "scrapeTableReservationProvider": false,
  "scrapeOrderOnline": false,
  "includeWebResults": false,
  "enableCompetitorAnalysis": false
}
```

# Actor output Schema

## `places` (type: `string`):

All scraped Google Maps places with full details: address, coordinates, phone, website, rating, review count, opening hours, popular times, and more.

## `reviews` (type: `string`):

One row per review across all scraped places. Includes reviewer name, star rating, review text, date, owner response, and Local Guide status.

## `images` (type: `string`):

One row per image across all scraped places. Includes image URL and optional author attribution.

## `contacts` (type: `string`):

Contact information extracted from each place website: emails, extra phone numbers, and social media profiles (Facebook, Instagram, LinkedIn, Twitter, YouTube, TikTok).

## `competitorMap` (type: `string`):

Interactive dark-mode HTML map with color-coded pins and a ranked leaderboard. Only generated when enableCompetitorAnalysis is true.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("lovely_radiologist/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("lovely_radiologist/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 '{}' |
apify call lovely_radiologist/google-maps-scraper --silent --output-dataset

```

## MCP server setup

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