# Google Maps Reviews Scraper (`data_alchemist/google-maps-reviews`) Actor

This actor extracts place details as well as reviews, ratings and photos from any Google Maps business listing. Fast, structured, and ready to use

- **URL**: https://apify.com/data_alchemist/google-maps-reviews.md
- **Developed by:** [Denys](https://apify.com/data_alchemist) (community)
- **Categories:** E-commerce, Travel, Automation
- **Features:** Limited permissions
- **Stats:** 30 total users, 1 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

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

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 Reviews Scraper

Extract reviews, ratings and photos from any Google Maps business listing — with AI-powered sentiment analysis and business insights. Fast, structured, and ready to use

***

### What it does

This actor calls the Google Maps API to collect reviews for one or more places. For each place it retrieves the author's name, profile link, Local Guide status, review and photo counts, star rating, date, source platform, full text (with translation if present), photos, and owner replies — all without running a browser.

You can feed it:

- **A list of place URLs or IDs** — scrape specific known places in bulk
- **A search query + location** — let the actor discover matching places within a radius and scrape them all

***

### Output

The result is a JSON object with place metadata and an array of reviews. When `generateAIOverview` is enabled, an `reviewOverview` field is added at the place level:

```json
{
  "placeId": "0x3a02a586c15e1b3d:0x2e5b31b1d5397aae",
  "placeName": "Some Business",
  "reviewOverview": "### Overall Sentiment\nPositive\n\n### Top Strengths\n- **Food Quality**: Customers consistently praise the deliciousness and quality of the food....",
  "reviews": [
    {
      "reviewId": "Ci9DQWLR...",
      "author": "John Smith",
      "authorUrl": "https://www.google.com/maps/contrib/123456789/reviews",
      "isLocalGuide": true,
      "authorReviewCount": 42,
      "authorPhotoCount": 7,
      "rating": 4,
      "date": "2 months ago",
      "reviewSource": "Google",
      "reviewUrl": "https://www.google.com/maps/reviews/data=...",
      "text": "Great place, would definitely come back again...",
      "textTranslated": null,
      "photos": [
        {
          "thumbnail": "https://lh3.googleusercontent.com/...",
          "fullsize": "https://lh3.googleusercontent.com/...=s1600"
        }
      ],
      "replies": [
        {
          "author": "Response from the owner",
          "date": "1 month ago",
          "text": "Thank you for your kind words!",
          "textTranslated": null
        }
      ]
    }
  ]
}
```

#### Review fields

| Field | Type | Description |
|---|---|---|
| `placeId` | `string` | Unique Google place ID |
| `placeName` | `string` | Name of POI or business |
| `reviewId` | `string` | Unique Google review ID |
| `author` | `string` | Reviewer's display name |
| `authorUrl` | `string \| null` | Link to the reviewer's Google Maps profile |
| `isLocalGuide` | `boolean` | Whether the reviewer is a Google Local Guide |
| `authorReviewCount` | `number \| null` | Total number of reviews written by the author |
| `authorPhotoCount` | `number \| null` | Total number of photos uploaded by the author |
| `rating` | `number` | Star rating (1–5) |
| `date` | `string \| null` | Relative date as shown on Google Maps |
| `reviewSource` | `string \| null` | Source platform (e.g. `Google`, `Google Maps`) |
| `reviewUrl` | `string \| null` | Direct link to the review on Google Maps (Google reviews only) |
| `text` | `string` | Original review text |
| `textTranslated` | `string \| null` | Translated text if Google auto-translated the review, otherwise `null` |
| `photos` | `array` | Review photos with `thumbnail` and `fullsize` (up to 1600px) URLs |
| `replies` | `array` | Owner replies, each with `author`, `date`, `text`, and `textTranslated` |

***

### Input

#### Scraping specific places

Provide a list of place URLs or IDs in `placeUrls`. Multiple entries are processed in parallel.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `placeUrls` | `string[]` | — | List of Google Maps place URLs or place IDs to scrape |
| `maxPlaces` | `number` | `0` (unlimited) | Maximum number of places to process across all inputs |
| `maxReviews` | `number` | `100` | Maximum reviews to collect per place; `0` = unlimited |
| `sortBy` | `string` | `newest` | Sort order: `newest`, `highest`, `lowest`, or `relevant` |
| `newerThan` | `number` | `0` (disabled) | Only fetch reviews posted within this many days; forces `sortBy` to `newest` |
| `language` | `string` | `en` | Two-letter language code for review text (e.g. `en`, `de`, `fr`) |
| `generateAIOverview` | `boolean` | `false` | Generate an AI-written summary of all reviews per place (see [AI Overview](#ai-overview)) |

##### Supported place URL / ID formats

| Format | Example |
|---|---|
| Full Google Maps URL | `https://www.google.com/maps/place/...` |
| Short URL | `https://maps.app.goo.gl/ykgpkGMfASnkhQgXA` |
| Hex place ID | `0x40d4e9413c90fc47:0xe70863b37a371fdf` |
| Base64 place ID | `ChIJgUbEo8cfqokR5lP9_Wh_DaM` |

Short `maps.app.goo.gl` links are resolved automatically before scraping begins. Hex and Base64 IDs are converted to canonical place URLs.

##### Example input — specific places

```json
{
  "placeUrls": [
    "https://maps.app.goo.gl/ykgpkGMfASnkhQgXA",
    "0x40d4e9413c90fc47:0xe70863b37a371fdf",
    "ChIJgUbEo8cfqokR5lP9_Wh_DaM"
  ],
  "maxReviews": 50,
  "sortBy": "newest",
  "language": "en"
}
```

***

#### Discovering places by search

Leave `placeUrls` empty and provide a search query with a location to let the actor find matching places automatically and scrape reviews from all of them.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `searchQuery` | `string` | — | Search term to discover places (e.g. `"restaurant"`, `"hotel"`) |
| `searchLocation` | `string` | — | Center of the search area — coordinates (`"58.75304, 17.01097"`) or a place name (`"Paris, France"`) |
| `searchRadius` | `number` | `5000` | Radius in meters around the search center to look for places (min 100) |
| `maxPlaces` | `number` | `0` (unlimited) | Cap the number of discovered places to scrape |

##### Example input — search-based discovery

```json
{
  "searchQuery": "coffee shop",
  "searchLocation": "Paris, France",
  "searchRadius": 2000,
  "maxPlaces": 20,
  "maxReviews": 30,
  "sortBy": "newest"
}
```

This finds up to 20 coffee shops within 2 km of central Paris and collects the 30 newest reviews from each.

***

### AI Overview

When `generateAIOverview` is set to `true`, the actor uses an AI model to produce a concise written summary of all collected reviews for each place. The summary is returned as an `aiOverview` string at the place level alongside the individual reviews.

**Pricing:** this feature incurs an additional charge per review with text that is processed by the AI. Reviews without text are not charged. The charge is applied on top of the standard per-review cost.

**Example output:**

```json
{
  "placeId": "0x3a02a586c15e1b3d:0x2e5b31b1d5397aae",
  "placeName": "Some Business",
  "reviewOverview": "### Overall Sentiment\nPositive\n\n### Top Strengths\n- **Food Quality**: Customers consistently praise the deliciousness and quality of the food....",
  "reviews": [...]
}
```

***

### Features

- **Bulk place input** — supply as many URLs or IDs as needed; all are processed automatically
- **Search-based discovery** — find places by name or category within any radius and scrape them all in one run
- **All place ID formats** — accepts full URLs, short links, hex IDs, and Base64 IDs
- **No browser required** — uses the Google Maps API directly for fast, reliable data retrieval
- **Date filtering** — `newerThan` limits results to recent reviews only, forcing newest-first sort automatically
- **Language control** — request review text in any supported Google Maps language
- **Sorting** — supports all four Google Maps sort modes: newest, highest rating, lowest rating, and most relevant
- **Translation detection** — captures both the auto-translated version (`textTranslated`) and the original (`text`) when present
- **Owner replies** — extracts owner responses including author, date, text, and translation if present
- **Full-size photos** — thumbnail URLs normalized to full-resolution (`=s1600`) variants
- **AI overview** — optional AI-generated summary of all reviews per place; charged per source review with text
- **Free plan limits** — free users are automatically capped at 100 places and 10 reviews per place, with AI overview disabled

***

### Free vs Paid plan limits

| | Free plan | Paid plan |
|---|---|---|
| Max places per run | 100 | Unlimited |
| Max reviews per place | 10 | Unlimited |
| AI overview | Not available | Available |

Limits are enforced automatically — no configuration needed. If your input requests more than the free plan allows, it is silently capped. Upgrade to a paid Apify plan to remove all restrictions.

# Actor input Schema

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

List of Google Maps place URLs to scrape reviews from. Accepts both full URLs (https://www.google.com/maps/place/...) and short URLs (https://maps.app.goo.gl/...).

## `maxPlaces` (type: `integer`):

Maximum number of places to scrape. Set to 0 for unlimited.

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

Maximum number of reviews to scrape per place. Set to 0 for unlimited.

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

Two-letter language code for reviews (e.g. en, de, fr). Controls the language of review text returned.

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

Order in which to retrieve reviews. Overridden to "newest" when Newer Than is set.

## `newerThan` (type: `integer`):

Only fetch reviews posted within this many days. Set to 0 for no limit. When set, sort order is forced to Newest.

## `searchQuery` (type: `string`):

Search term used to discover places (e.g. "restaurant", "hotel"). Used when Place URLs are not provided.

## `searchLocation` (type: `string`):

Center of the search area. Accepts coordinates (e.g. "58.75304, 17.01097") or a place name (e.g. "Paris, France") which will be resolved via geocoding. Required together with Search Query.

## `searchRadius` (type: `integer`):

Radius in meters around the search center to look for places.

## `generateAIOverview` (type: `boolean`):

When enabled, uses OpenAI (gpt-4o-mini) to generate a concise AI overview of all reviews per place. Requires OPENAI_API_KEY to be set in the environment.

## Actor input object example

```json
{
  "placeUrls": [
    "https://maps.app.goo.gl/ykgpkGMfASnkhQgXA"
  ],
  "maxPlaces": 0,
  "maxReviews": 100,
  "language": "en",
  "sortBy": "newest",
  "newerThan": 0,
  "searchRadius": 5000,
  "generateAIOverview": false
}
```

# 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 = {
    "placeUrls": [
        "https://maps.app.goo.gl/ykgpkGMfASnkhQgXA"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("data_alchemist/google-maps-reviews").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 = { "placeUrls": ["https://maps.app.goo.gl/ykgpkGMfASnkhQgXA"] }

# Run the Actor and wait for it to finish
run = client.actor("data_alchemist/google-maps-reviews").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 '{
  "placeUrls": [
    "https://maps.app.goo.gl/ykgpkGMfASnkhQgXA"
  ]
}' |
apify call data_alchemist/google-maps-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data_alchemist/google-maps-reviews"
        }
    }
}
```

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/XHBx1DQPTlRiDW3OE/builds/zTEzhdMaDWwDiPUhL/openapi.json
