# Google Maps Reviews Scraper - $0.35 per 1,000 Reviews (`dami_studio/google-maps-reviews-scraper-v1`) Actor

The cheapest Google Maps reviews scraper on the market at $0.35 per 1,000 reviews. Give it a place URL, place ID or a search phrase and get every review paginated: star rating, full text, date, reviewer name with review and photo counts, owner reply, photo count. Newest first. No login, no cookies.

- **URL**: https://apify.com/dami\_studio/google-maps-reviews-scraper-v1.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 review 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/platform/actors/running/actors-in-store#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 Reviews Scraper

Point it at a Google Maps place — a URL, a place ID, or just the business name — and get every
review back as a row: star rating, the full review text, when it was posted, who wrote it (with
their own review and photo counts), the owner's reply, and how many photos the review carries.

Sorted newest first. No Google account, no cookies, no API key, nothing to log into.

### Price

**$0.35 per 1,000 reviews**, plus a $0.0000125 start fee per GB of run memory (this Actor runs at
1 GB, so that is $0.0000125 per run — a hundredth of a cent).

That is the cheapest Google Maps reviews scraper on the market. Here is the comparison, taken from
Apify's own store API on 2026-08-14, counting only the per-result event and ignoring the decoy
`apify-default-dataset-item` charges rivals attach beside their real price:

| Actor | Users (30d) | Per review | Start fee | 1,000 reviews |
|---|---|---|---|---|
| **dami\_studio/google-maps-reviews-scraper** | new | **$0.00035** | $0.0000125 | **$0.35** |
| beatanalytics/google-maps-reviews-scraper | 106 | $0.0005 | $0 | $0.50 |
| delicious\_zebu/google-maps-store-review-scraper | 24 | $0.0004 | $0.00005 | $0.40 |
| datablow/google-reviews-scraper | 37 | $0.003 | $0.00005 | $3.00 |
| agents/google-maps-reviews | 16 | $0.016 per query | $0 | n/a (per query) |
| compass/google-maps-reviews-scraper | 5,703 | no per-result price | — | you pay Apify platform compute instead |

The most-installed rival, compass, does not charge per review at all — it bills you Apify platform
usage, so what a run costs depends on how long its browser sits there. This Actor charges a flat
$0.00035 per review and nothing else, so a 5,000-review job costs $1.75 whether it takes one minute
or ten.

**What is free.** The uncharged sample row you get from an empty input is free. Every diagnostic row
(`ok: false`, with an `errorCode`) is free — blocks, empty places, bad URLs. Reviews dropped by your
keyword or date filter are free, because they are never pushed. You only pay for a review row that
actually landed in the dataset.

### Input

Everything is optional. Give it at least one of `startUrls`, `placeIds` or `searchStrings`.

```json
{
  "searchStrings": ["Katz's Delicatessen New York"],
  "maxReviews": 100,
  "maxPlaces": 1,
  "reviewsSort": "newest",
  "language": "en"
}
```

| Field | What it does |
|---|---|
| `startUrls` | Google Maps URLs — `/maps/place/…`, `/maps/search/…` or `?cid=…` |
| `placeIds` | Place IDs starting with `ChIJ` |
| `searchStrings` | Business names or queries; the top Maps match for each is scraped |
| `maxReviews` | Reviews per place, ceiling 2000 (default behaviour: 100) |
| `maxPlaces` | Safety cap on how many targets one run visits, ceiling 50 |
| `reviewsSort` | `newest` (default), `mostRelevant`, `highestRanking`, `lowestRanking` |
| `reviewsStartDate` | `2026-01-01` or `30 days` — older reviews are dropped and not charged |
| `reviewsFilterString` | Keep only reviews containing this word; the rest are not charged |
| `language` | Two-letter code Google answers in (`en`, `de`, `fr`, `es`, …) |
| `personalData` | Set `false` to blank out reviewer name, profile URL and profile ID |
| `proxyConfiguration` | Optional. Leave empty and it picks its own cheap egress |

The field names match `compass/google-maps-reviews-scraper` where they overlap
(`startUrls`, `placeIds`, `maxReviews`, `reviewsSort`, `reviewsStartDate`, `reviewsFilterString`,
`language`, `personalData`), so an existing input JSON can be pasted straight in.

### Output

A real row from a real run (run `mg8e1KaEV80M11Pu5`, 12 newest reviews of Katz's Delicatessen):

```json
{
  "ok": true,
  "charged": true,
  "placeName": "Katz's Delicatessen",
  "placeUrl": "https://www.google.com/maps/place/Katz's+Delicatessen/@40.722233,-73.987429,17z/data=!3m1!4b1!4m6!3m5!1s0x89c2598f7ff4aa09:0x313547e757cb8cea!8m2!3d40.722233!4d-73.987429!16zL20vMDN0eF9o",
  "placeTotalScore": 4.5,
  "placeReviewsCount": 39526,
  "reviewsSort": "newest",
  "sortApplied": true,
  "reviewId": "Ci9DQUlRQUNvZENodHljRjlvT2treGRHUnhjMmxhWWs0MGMzQTRha3RYZW5keldGRRAB",
  "reviewerName": "Vanesa Herrera",
  "reviewerUrl": "https://www.google.com/maps/contrib/116379031429699768301/reviews",
  "reviewerId": "116379031429699768301",
  "reviewerNumberOfReviews": 5,
  "reviewerNumberOfPhotos": null,
  "isLocalGuide": false,
  "rating": 2,
  "relativeDate": "3 hours ago",
  "publishedAtDate": "2026-08-15T01:00:12.328Z",
  "text": "If you're in a group larger than six and want to eat at the table where the servers serve you, don't mention it because it will take a long time to get your table... In the end, the food was okay, but nothing extraordinary.",
  "ownerReply": null,
  "ownerReplyRelativeDate": null,
  "reviewPhotosCount": 0,
  "reviewPhotoUrls": []
}
```

Coverage on that run: 12 of 12 rows carried `placeName`, `placeTotalScore`, `placeReviewsCount`,
`rating`, `relativeDate`, `reviewerName`, `reviewerUrl`, `reviewerNumberOfReviews` and `text`, and
0 of 12 texts were left truncated with the "... More" preview. On a larger run of the same place
(100 reviews, run `M5qRtD9Rzymcff0pt`) 43 of the 100 rows also carried an `ownerReply` — the rest
simply have no reply — and the longest review body came back at over 1,900 characters.

Rows arrive newest first when `sortApplied` is `true`; that run's first rows were "3 hours ago",
"an hour ago", "21 minutes ago".

### Honest limits

- **`publishedAtDate` is derived, not exact.** Google only publishes a relative label
  ("a month ago"), so this Actor converts that label to a timestamp at scrape time. `relativeDate`
  is the raw label Google gave; use it when you need the ground truth. `reviewsStartDate` filtering
  works off the derived timestamp, so it is accurate to roughly the granularity Google shows.
- **`sortApplied` tells you the truth about sorting.** Google's sort control is a menu that
  occasionally does not open in a headless session. When that happens the run still returns reviews,
  but in Google's default "most relevant" order, and `sortApplied` is `false` on every row so you can
  see it rather than guess.
- **Google soft-throttles by IP.** Instead of an error it sometimes serves a cut-down place page
  with no Reviews tab at all — the page footer says "You're seeing a limited view of Google Maps".
  This Actor detects that page, rotates to a different exit address and retries up to three times.
  If all three fail you get an uncharged `BLOCKED` diagnostic row, not a silent empty dataset.
- **`placeReviewsCount` is the number Google prints on the reviews pane**, which is not always the
  same as the headline count on the overview card — Google counts star-only ratings differently in
  the two places. Treat it as Google's own figure for the review list you are paging, not as an
  audited total.
- **Ceiling is 2000 reviews per place.** Google's own pane stops serving more long before that on
  most places; very large places will return what the pane gives, then stop.
- **One place per search phrase.** A `searchStrings` entry resolves to Google's top match. If you
  need a specific branch, pass its place URL or place ID.
- **No reply threads, no review edits history, no reviewer email.** Google does not publish them.
- **Very short reviews can come back with an empty `text`.** Google Maps lets people leave a star
  rating with no words. Those rows still carry the rating, reviewer and date, and `text` is empty
  rather than padded with the card's chrome.
- **Runs use a real browser.** Google's reviews are not served by any public JSON endpoint — its
  internal `listugcposts` RPC returns HTTP 403 to every anonymous request (verified across four TLS
  fingerprints, four Google country hosts, with and without cookies and session tokens). A short run
  therefore has a fixed browser cost; runs of roughly 25 reviews or more are where the per-review
  price does its job.

### FAQ

**Do I need a Google account or an API key?**
No. Nothing is logged into. It reads the public Google Maps place page.

**How much does 10,000 reviews cost?**
$3.50, plus the start fee of one hundredth of a cent per run.

**Can I get only reviews from the last month?**
Yes — set `reviewsStartDate` to `30 days`. Older reviews are dropped before they are pushed, so you
are not charged for them.

**Can I scrape several places in one run?**
Yes. Put multiple entries in `startUrls`, `placeIds` or `searchStrings`. `maxReviews` applies per
place; `maxPlaces` caps how many are visited.

**What happens if a place has no reviews?**
You get one uncharged diagnostic row with `errorCode: "NO_RESULTS"` and the run finishes as
succeeded. You are not billed for it.

**What happens if I run it with empty input?**
You get exactly one labelled sample row (`_sample: true`, `charged: false`) showing the output
shape, and the run succeeds. Nothing is charged except the start fee.

**Is this really the cheapest Google Maps reviews scraper?**
At $0.35 per 1,000 reviews, yes — every other Google Maps reviews scraper on Apify with a real
per-result price charges more (see the table above), and the free-tier ones bill you platform
compute instead, which on a browser-driven review crawl runs higher than $0.35 per 1,000.

**Can I send the results to Google Sheets / a webhook?**
Results land in a standard Apify dataset, so every Apify integration works: API, webhooks, Zapier,
Make, or a direct CSV/JSON/Excel export from the run page.

# Actor input Schema

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

Google Maps URLs to scrape reviews from. Accepts /maps/place, /maps/search and ?cid= links.

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

Google place IDs (start with ChIJ). One per line, or paste a list with Bulk edit.

## `searchStrings` (type: `array`):

Business names or queries; the top Google Maps match for each is scraped.

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

How many reviews to collect for each place. Hard ceiling is 2000.

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

Safety cap on how many of the supplied targets are visited in one run.

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

Order Google returns the reviews in. Newest first is the default.

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

Absolute date (2026-01-01) or relative (30 days, 6 months). Older reviews are dropped and never charged.

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

Keep only reviews whose text contains this word. Filtered-out reviews are not charged.

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

Two-letter language code Google should answer in, e.g. en, de, fr, es.

## `personalData` (type: `boolean`):

Turn off to blank out reviewer name, profile URL and profile ID in the output.

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

Optional. Leave empty to use the built-in cheap egress ladder; supply your own servers to override it.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJIQBpAG2ahYAR_6128GcTUEo"
    }
  ],
  "placeIds": [
    "ChIJIQBpAG2ahYAR_6128GcTUEo"
  ],
  "searchStrings": [
    "Katz's Delicatessen New York"
  ],
  "maxReviews": 100,
  "maxPlaces": 10,
  "reviewsSort": "newest",
  "reviewsStartDate": "12 months",
  "reviewsFilterString": "pastrami",
  "language": "en",
  "personalData": true
}
```

# Actor output Schema

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

One row per result in the default dataset: placeName, placeUrl, placeTotalScore, placeReviewsCount, reviewsSort, reviewId, reviewerName, reviewerUrl. Empty or blocked runs return a single uncharged row instead.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJIQBpAG2ahYAR_6128GcTUEo"
        }
    ],
    "placeIds": [
        "ChIJIQBpAG2ahYAR_6128GcTUEo"
    ],
    "searchStrings": [
        "Katz's Delicatessen New York"
    ],
    "maxReviews": 100,
    "maxPlaces": 10,
    "reviewsSort": "newest",
    "reviewsStartDate": "12 months",
    "reviewsFilterString": "pastrami",
    "language": "en",
    "personalData": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/google-maps-reviews-scraper-v1").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 = {
    "startUrls": [{ "url": "https://www.google.com/maps/place/?q=place_id:ChIJIQBpAG2ahYAR_6128GcTUEo" }],
    "placeIds": ["ChIJIQBpAG2ahYAR_6128GcTUEo"],
    "searchStrings": ["Katz's Delicatessen New York"],
    "maxReviews": 100,
    "maxPlaces": 10,
    "reviewsSort": "newest",
    "reviewsStartDate": "12 months",
    "reviewsFilterString": "pastrami",
    "language": "en",
    "personalData": True,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/google-maps-reviews-scraper-v1").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 '{
  "startUrls": [
    {
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJIQBpAG2ahYAR_6128GcTUEo"
    }
  ],
  "placeIds": [
    "ChIJIQBpAG2ahYAR_6128GcTUEo"
  ],
  "searchStrings": [
    "Katz'\''s Delicatessen New York"
  ],
  "maxReviews": 100,
  "maxPlaces": 10,
  "reviewsSort": "newest",
  "reviewsStartDate": "12 months",
  "reviewsFilterString": "pastrami",
  "language": "en",
  "personalData": true
}' |
apify call dami_studio/google-maps-reviews-scraper-v1 --silent --output-dataset

```

## MCP server setup

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

```

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/EcRqI9L9AlHpOtLD5/builds/iW6oiLrafPrF0vUfo/openapi.json
