# Google Maps Negative Review Alert (`davidbenittah/google-maps-negative-review-alert`) Actor

Google Maps review monitor: watch your listings on a schedule and get alerted on rating drops and new negative reviews — with the review text and link.

- **URL**: https://apify.com/davidbenittah/google-maps-negative-review-alert.md
- **Developed by:** [David](https://apify.com/davidbenittah) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 Negative Review Alert

**Google Maps review monitor** that watches your business listings on a schedule and alerts you on two things that actually cost money: a **rating drop** and a **new negative review** — with the review text, star count, and direct link, so you can respond the same day instead of discovering it weeks later.

### Features

- **Alerts, not dumps**: review scrapers give you every review, every time. This monitor reports only what changed — new reviews at or below your star threshold, and average-rating drops beyond your delta.
- **Multi-location**: watch up to 50 listings per run — every branch of a franchise, every client of an agency.
- **Full alert record**: place name, current vs previous rating, review text, stars, publication date, direct review URL.
- **Schedule-ready**: state persists between runs; a review only ever alerts once.
- **Safe on flaky crawls**: a listing that temporarily fails to fetch keeps its baseline — no false re-alerts.
- **No personal reviewer data** is collected.

### Use cases

- **Franchises & multi-site businesses**: know within hours when any location takes a 1-star hit.
- **Reputation & marketing agencies**: monitor every client's listing from one scheduled task and prove your responsiveness.
- **Dentists, clinics, restaurants, hotels**: negative reviews left unanswered are the #1 local-conversion killer.
- **Ops teams**: a sudden rating drop at one branch is an early-warning signal of an operational problem.

### Input / Output

Input:

```json
{
  "places": [
    "https://www.google.com/maps/place/Your+Restaurant/@45.76,4.83,17z",
    "ChIJreV9aqYWdkgROM_boL6YbwA"
  ],
  "badReviewStars": 2,
  "ratingDropThreshold": "0.1"
}
````

Output — one dataset item per alert:

```json
{
  "type": "negative_review",
  "placeId": "ChIJ...",
  "name": "Chez Antoine",
  "currentScore": 4.2,
  "reviewStars": 1,
  "reviewText": "Attente d'une heure, c'est inacceptable",
  "reviewPublishedAt": "2026-07-05T19:00:00.000Z",
  "reviewUrl": "https://www.google.com/maps/reviews/...",
  "detectedAt": "2026-07-06T09:00:00.000Z"
}
```

Alert types: `negative_review`, `rating_drop` (with `previousScore` and `scoreDelta`), and `baseline` (first run only, one per listing). A `SUMMARY` record in the key-value store reports per-run counts.

### Pricing

Pay per event: a small fee per alert item. Under the hood the Actor runs the standard Google Maps Scraper (`compass/crawler-google-places`, billed to your account at its own pay-per-event rate: ~$0.004 per place plus ~$0.0005 per review checked). Watching 10 listings × 20 newest reviews daily costs roughly $0.14/day in scanning.

### FAQ

**How do alerts avoid duplicates?**
Seen review IDs and the last known rating are stored per listing in a persistent key-value store; only unseen negative reviews and fresh rating drops are reported.

**What does the first run return?**
One `baseline` item per listing (current rating, review count). Alerts start from the second run.

**How many of the reviews are checked?**
The newest `maxReviewsPerPlace` (default 20) per run. Schedule daily or weekly so new reviews always fall inside that window.

**Place URL or Place ID?**
Both work, but Place IDs (`ChIJ...`) are the most reliable — some decorated Google Maps URLs resolve to zero results in the underlying scraper. Grab the ID from Google's Place ID finder or from any Google Maps scraper output.

**How do I reset the baseline?**
Change `monitorId` (or the set of places — each set keeps its own state).

**Is this legal?**
The Actor collects public listing data and public review content via the standard Apify Google Maps Scraper, with reviewer personal data collection disabled. You are responsible for how you use the data.

# Actor input Schema

## `places` (type: `array`):

Google Maps Place IDs (ChIJ..., most reliable) or full Google Maps place URLs. One entry per business location. Hard maximum: 50 places per run. Find a Place ID with Google's Place ID finder or any Google Maps scraper output.

## `badReviewStars` (type: `integer`):

Alert on any new review with this many stars or fewer.

## `ratingDropThreshold` (type: `string`):

Alert when a listing's average rating drops by at least this much since the last run (e.g. 0.1).

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

How many of the newest reviews to scan per listing on each run. Hard maximum: 100.

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

Language code for place details (e.g. 'en', 'fr').

## `monitorId` (type: `string`):

Optional. Advanced: name this monitor to keep separate baselines for the same set of listings, or reset one by changing the ID.

## Actor input object example

```json
{
  "places": [
    "ChIJMYwentXB9EcRnD1RBwe9lmo"
  ],
  "badReviewStars": 2,
  "ratingDropThreshold": "0.1",
  "maxReviewsPerPlace": 20,
  "language": "en"
}
```

# 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 = {
    "places": [
        "ChIJMYwentXB9EcRnD1RBwe9lmo"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("davidbenittah/google-maps-negative-review-alert").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 = { "places": ["ChIJMYwentXB9EcRnD1RBwe9lmo"] }

# Run the Actor and wait for it to finish
run = client.actor("davidbenittah/google-maps-negative-review-alert").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 '{
  "places": [
    "ChIJMYwentXB9EcRnD1RBwe9lmo"
  ]
}' |
apify call davidbenittah/google-maps-negative-review-alert --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Negative Review Alert",
        "description": "Google Maps review monitor: watch your listings on a schedule and get alerted on rating drops and new negative reviews — with the review text and link.",
        "version": "1.0",
        "x-build-id": "dHq0BHYitbA1fAbDT"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/davidbenittah~google-maps-negative-review-alert/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-davidbenittah-google-maps-negative-review-alert",
                "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/davidbenittah~google-maps-negative-review-alert/runs": {
            "post": {
                "operationId": "runs-sync-davidbenittah-google-maps-negative-review-alert",
                "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/davidbenittah~google-maps-negative-review-alert/run-sync": {
            "post": {
                "operationId": "run-sync-davidbenittah-google-maps-negative-review-alert",
                "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",
                "required": [
                    "places"
                ],
                "properties": {
                    "places": {
                        "title": "Google Maps listings to watch",
                        "type": "array",
                        "description": "Google Maps Place IDs (ChIJ..., most reliable) or full Google Maps place URLs. One entry per business location. Hard maximum: 50 places per run. Find a Place ID with Google's Place ID finder or any Google Maps scraper output.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "badReviewStars": {
                        "title": "Negative review threshold (stars)",
                        "minimum": 1,
                        "maximum": 4,
                        "type": "integer",
                        "description": "Alert on any new review with this many stars or fewer.",
                        "default": 2
                    },
                    "ratingDropThreshold": {
                        "title": "Rating drop threshold",
                        "type": "string",
                        "description": "Alert when a listing's average rating drops by at least this much since the last run (e.g. 0.1).",
                        "default": "0.1"
                    },
                    "maxReviewsPerPlace": {
                        "title": "Newest reviews checked per place",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "How many of the newest reviews to scan per listing on each run. Hard maximum: 100.",
                        "default": 20
                    },
                    "language": {
                        "title": "Results language",
                        "type": "string",
                        "description": "Language code for place details (e.g. 'en', 'fr').",
                        "default": "en"
                    },
                    "monitorId": {
                        "title": "Custom monitor ID",
                        "type": "string",
                        "description": "Optional. Advanced: name this monitor to keep separate baselines for the same set of listings, or reset one by changing the ID."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
