# Google Reviews Analysis AI - complaints, praise & contacts (`rich_minds/google-reviews-insights`) Actor

First 25 businesses free. Google reviews analysis per business: recurring complaints, praise, owner reply rate, a reputation-risk score, verified contacts and an AI opener. Pay only for businesses that qualify.

- **URL**: https://apify.com/rich\_minds/google-reviews-insights.md
- **Developed by:** [Rich Minds](https://apify.com/rich_minds) (community)
- **Categories:** Lead generation, Marketing, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Reviews Analysis AI - complaints, praise & contacts

**Google reviews analysis you can act on: one reputation report per business — the complaints that keep coming back, what customers praise, the negative reviews nobody answered, a risk score, and who to contact.**

⚡ First **25 businesses free** · 💵 **$0.001** per qualified business · 🤖 **$0.009** with the AI analysis · 🔑 No API key needed on Apify plans that can run Store Actors ([which plan?](#-faq)) · 🧾 you pay only for businesses that qualify

![One row per qualified business — rating, unanswered negatives, reputation risk, recurring complaints, score and the AI opener](https://api.apify.com/v2/key-value-stores/YxRnBpIxkk8rnWaB5/records/shortlist.svg)

> **Try it in 30 seconds.** Click **Try it** — the form is already filled with a free demo (three sample businesses,
> nothing charged). Then point it at your own Google Maps places: your first **25 qualified businesses** are free.
> → [What a run costs](#-pricing--what-a-run-really-costs) · [What the AI adds](#-what-the-ai-tier-adds) · [Run it weekly](#-run-it-weekly)

### ⚡ At a glance

| | |
|---|---|
| **What you get** | one row per business: reputation metrics, recurring complaints, praise themes, 3 talking points, risk score, contacts, an outreach opener |
| **You provide** | Google Maps place URLs, a category + city, an existing scraper dataset — or pasted review rows |
| **Source** | runs [compass/Google-Maps-Reviews-Scraper](https://apify.com/compass/google-maps-reviews-scraper) (or the Google Maps Scraper) on your account |
| **Demo run** | 3 sample businesses → 1 filtered out by the rating cap → **2 qualified reports** (the output below) |
| **Price** | first 25 free, then $0.001 per qualified business, $0.009 with AI; filtered-out businesses cost $0 |
| **Keys / setup** | none on Apify plans that can run Store Actors — AI runs through Apify's built-in model access; on the free plan use `llmProvider: byok` with your own key |
| **Works with** | Schedules, webhooks, Google Sheets, Slack, Make / n8n / Zapier, MCP & AI agents |

### 🎯 What this Actor does

It reads the reviews the Google Maps Reviews Scraper returns, groups them into **one row per business**, and delivers
only the businesses that match what you are looking for:

- **Reputation metrics** — reviews analysed, recent average vs overall rating, negative count, unanswered negatives, owner reply rate, a rule-based `reputationRisk` (0–100) and a sample of the negative reviews (text only — reviewer identities are never kept).
- **AI review analysis** — up to 4 `recurringComplaints` (themes found in more than one review), `praiseThemes`, exactly 3 `talkingPoints` tied to a specific review or website fact, an AI risk score, a one-line summary and the reasons behind the score.
- **Verified contacts** — when the source carries a website: direct vs generic email (every domain MX-checked, optional mailbox verification with your MillionVerifier / NeverBounce key), phone, WhatsApp, social profiles and the owner's name when the site names one (never invented).
- **Website signals** — live/dead, tech stack, tracking pixels, online booking, chat, a speed grade: the gaps a local agency sells into.
- **Fit score and label** (`hot` / `warm` / `cold`) against *your* goal, with `targetFlags` to keep only the businesses that have the problem you solve.
- **Outreach** — a subject line and an opener (email, SMS, WhatsApp, DM or call script) anchored on one observed detail, plus a next step.

It remembers every business you already received (never billed twice), works as a tool for AI agents through Apify's
MCP server, and can POST each qualified business to a webhook.

### 🆚 Why this instead of the Google Maps Reviews Scraper?

[compass/Google-Maps-Reviews-Scraper](https://apify.com/compass/google-maps-reviews-scraper) is the tool 6,800+ Apify
users a month use to pull reviews — and this Actor runs it for you. What the scraper returns is one row per review:
stars, text, date. The work starts afterwards. This Actor does that work.

| | [Google Maps Reviews Scraper](https://apify.com/compass/google-maps-reviews-scraper) alone | **Google Reviews Analysis AI** |
|---|---|---|
| **Row** | one per review | one per **business**, with the whole review picture |
| **Price** | $0.0006 per review scraped | the scraper's price on your account + $0.001 per *qualified* business ($0.009 with AI), first 25 free |
| **Patterns** | you read the reviews | recurring complaints, praise themes, three talking points, risk score |
| **Owner engagement** | not summarised | reply rate, unanswered negatives, recent-vs-overall trend |
| **Contacts** | none | email (MX-checked), phone, WhatsApp, socials, owner name — from the business's own site |
| **Repeat runs** | the same places again | cross-run memory: only new businesses are delivered and charged |
| **Spend control** | per review | hard caps: `maxQualified`, `maxToProcess`, `maxDiscoveryChargeUsd` |

### 💵 Pricing — what a run really costs

Pay per event: **one event per qualified business, nothing else.**

| Event | When it is charged | Price |
|---|---|---|
| `free-tier` | your first 25 qualified businesses on this Actor, in any mode | **$0.00** |
| `qualified-business-basic` | AI off — reputation metrics, flags, reply rate, negative-review sample, contacts, website signals, rule scores | **$0.001** |
| `qualified-business-ai` | AI on — everything above plus complaints, praise, talking points, AI risk, fit score with reasons, subject line, opener, next step | **$0.009** |

**Never charged:** loading and grouping, website crawling, email checks, businesses below `minScore`, businesses that
fail a filter, businesses you received in an earlier run. Platform compute is included in the event price.

**How that compares** — $0.001 is 1.3× the median unit price of the source Actor and its closest competitors
($0.00075), but one qualified business replaces 30 raw review rows — about $0.02 of review rows at that price.

**Billed separately, at cost:** the source Actor on your account (≈ $0.0006 per review, so ≈ $0.018 for a business with
30 reviews; `dataset` and `list` mode need no source run), and AI tokens through Apify's model access (≈ $0.005–0.01 per
business at Claude Haiku 4.5 list prices — computed from the prompt size, not a platform measurement) or your own key.

**Worked example** — 40 clinics × 30 reviews, *every one qualifies* (the worst case for your bill), AI on:

| Line | Calculation | Total |
|---|---|---|
| Source scraper on your account | 1,200 reviews × $0.0006 | $0.72 |
| This Actor, first run | 25 free + 15 × $0.009 | $0.135 |
| AI tokens | 40 × ≈ $0.01 | ≈ $0.40 |
| **Total** | 40 reputation reports with contacts and openers | **≈ $1.26** |

Filters that drop businesses lower the second and third lines — a dropped business costs $0 here.

### 🤖 What the AI tier adds

The same business with AI **off** (`qualified-business-basic`, $0.001) — facts, flags and a rule score, from the demo run:

```json
{
  "name": "Corner Café", "googleRating": 3.6, "reviewsAnalyzed": 5, "negativeReviewCount": 4,
  "unansweredNegativeReviews": 4, "ownerResponseRate": 0.0, "reputationRisk": 91, "ruleScore": 81,
  "flags": ["low_rating", "recent_negative_reviews", "unanswered_negative_reviews", "rating_trend_down"]
}
```

AI **on** (`qualified-business-ai`, $0.009) — the same row, read and judged against *your* goal:

```json
{
  "name": "Corner Café", "aiReputationRisk": 88, "aiScore": 72, "score": 82, "label": "hot",
  "recurringComplaints": ["slow service and long waits"],
  "praiseThemes": ["nice pastries", "sunny terrace", "decent food"],
  "talkingPoints": [
    "Three of the last five reviews mention slow service and long waits, yet none have received a response.",
    "A recent 5-star review praised your pastries and sunny terrace, showing you have strong positives to build on."
  ],
  "outreachOpener": "I noticed three of your recent reviews mention slow service and long waits, yet none have been answered—let's turn that around."
}
```

Reading 30 reviews, spotting the pattern, checking replies and writing a first line is the part that takes an agency
10 minutes per business. The AI tier does it for $0.009 plus tokens.

### 🚀 How to use it

1. **Click `Try it`** — the free demo is pre-filled and works as is.
2. **Pick a campaign preset** (`campaignPreset`): *Reputation agency*, *Local SEO agency*, *Business owner self-audit* or *CX / feedback software* — it fills the goal, offer, rating filter and target flags; anything you type wins.
3. **Pick a source** (`sourceMode`): `actor` runs the reviews scraper for place URLs (`startUrls` / `placeIds` in `discoveryInput`) or the Google Maps Scraper for a category + city; `dataset` reads a previous scraper run (`datasetId`); `list` takes rows you paste (`itemsList`).
4. **Describe what you look for and what you offer** (`goalDescription`, `offerDescription`) — *"Restaurants rated 3.5–4.3 whose reviews complain about slow service and get no reply"* beats *"restaurants"*.
5. **Set filters and caps** — `maxRating`, `targetFlags`, `requireEmail`, `minScore`, `maxQualified`, `maxDiscoveryChargeUsd` — and press **Start**.
6. **Open the dataset** — the **Qualified businesses**, **Reputation report**, **Outreach sheet** and **Contact sheet** views; export CSV / Excel / JSON.

```
load reviews → group per business → free filters (rating, review count, closed, seen before)
  → website crawl + email checks → reputation metrics, flags, rule score → target-flag filter
  → AI analysis of the best candidates → rank & cap → charge one event per qualified business → push → webhook
```

### ⚙️ Input

Reviews for places you already know:

```json
{
  "campaignPreset": "reputation-agency",
  "sourceMode": "actor",
  "discoveryInput": { "startUrls": [{ "url": "https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4" }] },
  "maxReviewsPerBusiness": 30,
  "maxDiscoveryChargeUsd": 0.5,
  "maxQualified": 25
}
```

Search a category in a city (websites and phones included, so contacts can be found): set `discoveryActorId` to
`compass/crawler-google-places` and `discoveryInput` to `{"searchStringsArray": ["dentist"], "locationQuery": "Austin, TX"}`.

| Field | Default | What it does |
|---|---|---|
| `campaignPreset` | `custom` | One of the 4 presets, or your own settings |
| `sourceMode` | `actor` | `actor`, `dataset` or `list` (the form starts on the free `list` demo) |
| `discoveryActorId` | `compass/Google-Maps-Reviews-Scraper` | The source Actor in `actor` mode |
| `maxDiscoveryChargeUsd` | `2` | Stops the source run at this spend (form: $0.50) — API calls without it are capped at $2 |
| `maxReviewsPerBusiness` | `30` | Newest reviews kept and shown to the AI per business |
| `maxRating` | `0` | Keep only businesses rated at or below this (`4.3` = a reputation problem; 0 = off) |
| `minScore` | `50` | Below this = not delivered, not charged |
| `requireEmail` | `false` | Only deliver businesses with an email found on their website |
| `enableAi` | `true` | AI analysis on/off |
| `llmProvider` | `apify` | Apify's model access, or `byok` with `llmApiKey` |
| `outreachChannel` | `email` | `email` (with subject), `sms`, `whatsapp`, `dm` or `call` |
| `maxQualified` | `100` | Hard cap on delivered businesses (and on what you pay) |
| `dedupeAcrossRuns` | `true` | Never deliver the same business twice |

The rest, all in the **Input** tab: `datasetId`, `itemsList`, `defaultCountryCode`, `minReviewsPerBusiness`,
`minRating`, `targetFlags`, `skipClosedPlaces`, `enrichWebsite`, `maxPagesPerSite`, `respectRobotsTxt`, `verifyEmails`,
`emailVerifier` + `emailVerifierApiKey`, `excludeFreeEmailProviders`, `llmModel`, `llmApiKey`, `outreachTone`,
`aiCandidateMultiplier`, `deepResearch` + `maxToolCallsPerItem` (the AI may open the business's page and search the
web before scoring), `maxToProcess`, `dedupeStoreName`, `webhookUrl` + `webhookHeaders`, `proxyConfiguration`.

**Target flags:** `low_rating`, `mediocre_rating`, `few_reviews`, `recent_negative_reviews`, `negative_share_high`,
`unanswered_negative_reviews`, `low_owner_response_rate`, `rating_trend_down`, `no_website`, `website_unreachable`,
`no_email_found`, `no_online_booking`, `no_chat_widget`, `no_analytics`, `no_ads_pixel`, `slow_website`,
`site_builder_template`, `no_reviews_analysed`, `closed`.

### 📤 Output

One dataset item per qualified business, best-scoring first. A real row from the AI run on the sample input (the
demo's café points at a real public website, mozilla.org, so the crawl has something to read — that is where its email
and socials come from):

```json
{
  "name": "Corner Café",
  "category": "Cafe",
  "city": "San Francisco",
  "googleRating": 3.6,
  "reviewCount": 214,
  "reviewsAnalyzed": 5,
  "sampleAverageStars": 2.6,
  "negativeReviewCount": 4,
  "unansweredNegativeReviews": 4,
  "ownerResponseRate": 0.0,
  "reputationRisk": 91,
  "aiReputationRisk": 88,
  "recurringComplaints": ["slow service and long waits"],
  "praiseThemes": ["nice pastries", "sunny terrace", "decent food"],
  "talkingPoints": [
    "Three of the last five reviews mention slow service and long waits, yet none have received a response.",
    "A recent 5-star review praised your pastries and sunny terrace, showing you have strong positives to build on.",
    "Your Google rating sits at 3.6 despite a solid A grade for site performance, indicating a gap between online perception and site quality."
  ],
  "bestEmail": "trademark-permissions@mozilla.com",
  "contactQuality": "other",
  "websiteStatus": "live",
  "trackingTools": ["Google Tag Manager"],
  "performanceGrade": "A",
  "targetFlagsMatched": ["unanswered_negative_reviews", "recent_negative_reviews", "low_owner_response_rate", "low_rating"],
  "contactabilityScore": 65,
  "ruleScore": 81,
  "aiScore": 72,
  "score": 82,
  "label": "hot",
  "reasons": ["Google rating is 3.6, well below the 4.3 threshold", "Owner has replied to 0% of reviews", "Multiple recent reviews cite slow service and long waits"],
  "summary": "Corner Café is a San Francisco cafe with a 3.6-star rating plagued by recurring slow-service complaints and no owner replies.",
  "outreachSubject": "Improving Corner Café's Google reputation",
  "outreachOpener": "I noticed three of your recent reviews mention slow service and long waits, yet none have been answered—let's turn that around.",
  "recommendedNextStep": "Craft a personalized email offering a free audit of their Google review responses.",
  "chargedEvent": "free-tier"
}
```

![The Reputation report view — reply rate, AI risk, praise, talking points and summary per business](https://api.apify.com/v2/key-value-stores/YxRnBpIxkk8rnWaB5/records/reputation.svg)

| View | Use it for |
|---|---|
| **Qualified businesses** | the overview: rating, negatives, risk, score, complaints, email, opener |
| **Reputation report** | what an agency shows the owner: reply rate, trend, complaints, praise, talking points, summary |
| **Outreach sheet** | Smartlead / Instantly / lemlist import or a dialer: decision-maker, email, subject, opener, next step |
| **Contact sheet** | CRM import: emails, quality, phone, WhatsApp, website, socials, address |

The run's `RUN_SUMMARY` (also its `OUTPUT`) holds the funnel — businesses loaded → filtered → AI-analysed → qualified —
skip counts per reason, charged events and the free-tier balance.

⭐ **Found it useful? A review on the Store helps others find it** — it takes a minute on the Actor's page.

### 🔁 Run it weekly

1. **Actions → Schedule** in the Console — weekly (or daily) on the same places, your input saved as is.
2. Keep `dedupeAcrossRuns: true` — every business you received is remembered, so the next run delivers and charges
   **only new ones**. Add `reviewsStartDate` to `discoveryInput` to analyse only fresh reviews.
3. Add `webhookUrl` or the Google Sheets / Slack integration, and new reputation reports land where you work.

Weekly cost is the new businesses only: 10 new per week × $0.009 = $0.09 plus tokens and the scraper.

#### 🎯 Try it for your niche

Saved inputs for three niches are in the repo (`storage-example/tasks/`); paste one into the form, run it once, then
schedule it. Each caps the source at $0.50.

| Niche | What it looks for | Input |
|---|---|---|
| Reputation agency | dentists in Austin, TX rated ≤ 4.3 with unanswered complaints and an email on their site | `reputation-agency-dentists.json` |
| Local SEO agency | restaurants in Denver, CO with few reviews, no replies, weak website | `local-seo-restaurants.json` |
| CX / booking software | physiotherapy clinics in Manchester, UK whose reviews mention waits, phones, bookings | `cx-saas-clinics.json` |

### 🔌 Integrations, automation and API

- **Google Sheets / Slack** — one click in the Actor's **Integrations** tab; the *Reputation report* view maps straight onto a sheet.
- **Zapier / Make / n8n** — set `webhookUrl` to the tool's webhook trigger; each qualified business arrives as `{"event": "business.qualified", "business": {…}}`. Or trigger on Apify's *Run succeeded* event and read the dataset.
- **Cold-email tools** — export the **Outreach sheet** as CSV; the columns map onto Smartlead / Instantly / lemlist custom fields, so a sequence can open with the `outreachOpener` column.
- **Schedules** — see [Run it weekly](#-run-it-weekly).
- **AI agents / MCP** — the first call should be the free trial: `sourceMode: "list"` with a few review rows. An empty `{}` runs the free demo.

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("rich_minds/google-reviews-insights").call(run_input={
    "sourceMode": "list",  # free trial on your own rows; switch to "actor" + discoveryInput for real places
    "itemsList": [{"title": "Corner Café", "totalScore": 3.6, "reviews": [
        {"stars": 1, "text": "Cold coffee, 20 minute wait.", "publishedAtDate": "2026-09-10"},
        {"stars": 2, "text": "Slow service again.", "publishedAtDate": "2026-08-28"},
        {"stars": 5, "text": "Lovely pastries."}]}],
    "goalDescription": "Cafés with recurring service complaints the owner ignores",
    "maxQualified": 25,
    "maxDiscoveryChargeUsd": 0.5,  # spend cap on your account once you switch to "sourceMode": "actor"
})
for biz in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(biz["name"], biz["reputationRisk"], biz["recurringComplaints"], biz["outreachOpener"])
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('rich_minds/google-reviews-insights').call({
    sourceMode: 'list',
    itemsList: [{ title: 'Corner Café', totalScore: 3.6, reviews: [
        { stars: 1, text: 'Cold coffee, 20 minute wait.' }, { stars: 2, text: 'Slow service again.' }, { stars: 5, text: 'Lovely pastries.' }] }],
    goalDescription: 'Cafés with recurring service complaints the owner ignores',
    maxQualified: 25,
    maxDiscoveryChargeUsd: 0.5, // spend cap once you switch to sourceMode: 'actor'
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((b) => [b.name, b.reputationRisk, b.label]));
```

**Use it from Claude, ChatGPT or any MCP client** — add Apify's MCP server with this Actor as a tool:

```json
{"mcpServers": {"apify": {"url": "https://mcp.apify.com/?actors=rich_minds/google-reviews-insights"}}}
```

Then ask: *"Run google-reviews-insights in `list` mode on these reviews first (free) and tell me the recurring
complaints; then analyse these 5 dentists' Google Maps URLs with `maxDiscoveryChargeUsd: 0.5` and tell me who to call first."*

#### Run outcomes — what your integration sees

| Outcome | Run status | Dataset | `OUTPUT` | Charged? | What to do |
|---|---|---|---|---|---|
| Free demo (`{}` or the pre-filled sample) | SUCCEEDED | sample businesses | `demo: true` | no | set `discoveryInput` or paste your own rows |
| Success | SUCCEEDED | qualified businesses, best first | funnel, `chargedEvents` | per qualified business | — |
| Nothing matched | SUCCEEDED | empty | `qualified: 0` | no | loosen `minScore`, `maxRating`, `targetFlags` |
| Invalid input | FAILED | empty | — | no | fix the field the status message names |
| Source failed | FAILED | empty | `sourceError` | no | follow the reason (plan, spend cap, dataset mode) |
| AI unavailable | SUCCEEDED | rule-scored businesses | `aiError` | basic price | `llmProvider: byok` with your own key |

### 👥 Who is it for?

| You are… | You run it to… | Start with |
|---|---|---|
| A reputation / review-management agency | find businesses losing customers to unanswered bad reviews — the report *is* the pitch | preset *Reputation agency*, `requireEmail: true` |
| A local SEO agency | find good businesses with a weak review engine: few reviews, no replies, weak site | preset *Local SEO agency* |
| A CX, booking or messaging SaaS | reach businesses whose reviews describe the problem your product fixes | preset *CX / feedback software*, `targetFlags` |
| A business owner or franchise manager | audit your own locations or a competitor's reviews | preset *Business owner*, `outreachChannel: call` |
| A lead-gen freelancer | sell a weekly reputation-leads feed into a client's Google Sheet | any preset + a schedule + the Sheets integration |

### 🧠 How the AI works

- **Grounded, not generative.** The model sees one business at a time — Google Maps facts, the review sample (stars, text, date, whether the owner replied), website signals — and returns a typed assessment. A complaint counts as *recurring* only when it appears in more than one review; every talking point must point at a specific review or website fact. Owner names are checked against the crawled text and dropped if absent; cold businesses get no opener.
- **Your goal, your offer.** The score measures fit with `goalDescription` and how likely the business needs `offerDescription`. `reputationRisk` is separate, so a spotless business can still fit a review-generation offer.
- **Tokens where they matter.** Only the best rule-scored businesses get the AI pass (`aiCandidateMultiplier` × `maxQualified`), and the review sample is capped at `maxReviewsPerBusiness`.
- **Model.** Default Claude Haiku 4.5 through Apify's built-in model access; any OpenRouter slug in `llmModel`, or `llmProvider: "byok"` with your own OpenAI, Anthropic, Gemini or Groq key.
- **Graceful fallback.** If the model cannot be reached, the run continues with rule-based metrics and those businesses are charged at the basic price.

### 🔒 Data, compliance and limits

- Only **public data**: Google Maps listings, public Google reviews and the business's own public web pages. No login, no cookies.
- **Reviewer personal data is never stored** — names, IDs, profile URLs and photos are dropped on import, and the source runs with reviewer personal data switched off.
- The crawler respects `robots.txt` and reads a handful of pages per site. No LinkedIn or personal-profile scraping — owner names come only from what the business publishes about itself.
- **Contacts need a website in the source.** The reviews scraper returns reviews only; use the Google Maps Scraper as source (or rows with websites) for emails and phones. Without a website a business is still analysed on its reviews.
- **The analysis is a sample** of the newest `maxReviewsPerBusiness` reviews. Email checks are MX-level unless you add a mailbox verifier; the speed grade is a crawl-time heuristic.
- Built for B2B prospecting and reputation work: the opener is a draft for a human to send. Follow the outreach laws that apply to you (CAN-SPAM, GDPR/PECR, …).

### ❓ FAQ

**How much will one run cost me?** Your first 25 qualified businesses are free on this Actor. After that $0.001 per qualified business, or $0.009 with AI, plus the source scraper on your account (≈ $0.018 for 30 reviews) and AI tokens (≈ $0.01 per business). The [worked example](#-pricing--what-a-run-really-costs) shows 40 businesses for ≈ $1.26 in the worst case.

**Is this a Google reviews scraper?** It uses one: in `actor` mode it runs the Google Maps Reviews Scraper on your account and turns its rows into one analysed report per business. If you already have a scraper dataset, `dataset` mode reads it with no new scraping.

**Can I use it with Google Maps reviews I already scraped?** Yes — `dataset` mode takes any run of the Google Maps Reviews Scraper or the Google Maps Scraper with reviews; `list` mode takes rows you paste.

**Is this review sentiment analysis?** More than that: besides the negative share and the rating trend it names the complaint themes that repeat, what customers praise, and three talking points you can use — per business, not per review.

**How does it help with reputation management?** It finds the businesses with unanswered negative reviews and falling ratings, and hands you the evidence (the complaint themes, the reply rate) plus a first line — the report an agency shows the owner.

**Can I use it to find local SEO leads?** Yes — the *Local SEO agency* preset keeps good businesses with few reviews, no owner replies and a weak or missing website, with contacts from their site.

**Which Apify plan do I need?** Any plan runs the free demo and `dataset` / `list` mode. Running the source scraper and the built-in AI (Apify's model access) needs a plan that can run Store Actors; on the free plan use `llmProvider: "byok"` with your own key. If the AI is refused, the status says "AI unavailable" and businesses are charged at the basic price.

**What happens if nothing matches my filters?** The run succeeds with 0 rows and charges nothing; `RUN_SUMMARY` shows how many businesses each filter dropped.

**Will I be charged for the same business twice?** Not with `dedupeAcrossRuns` on (default): every business you received is remembered on your account. Use a different `dedupeStoreName` per campaign.

**Can I schedule it?** Yes — see [Run it weekly](#-run-it-weekly); you only pay for new businesses.

**Is it legal?** It processes public listings and public reviews, never stores reviewer identities and does not log in anywhere. How you use the output (outreach) is governed by the laws that apply to you.

### 🧩 More Actors from the same developer

Not quite your use case? The same pay-per-qualified-result model, for other lead sources:

- [AI Local Business Leads - Website Audit & Verified Emails](https://apify.com/rich_minds/local-business-lead) — Google Maps businesses with a website audit and verified emails.
- [Instagram Influencer Finder — AI-vetted creators & emails](https://apify.com/rich_minds/instagram-creator-qualifier) — creators vetted for a brand campaign.
- [LinkedIn Buying Intent Leads](https://apify.com/rich_minds/linkedin-intent-leads) — LinkedIn posts showing buying intent, qualified per author.

### 🆘 Support

Something missing or wrong? Open an issue on the **Issues** tab of this Actor — requests from real campaigns are shipped first.

### 📝 Changelog

- **0.1.x** (2026-09-25) — market-parity pricing ($0.001 / $0.009 per qualified business, first 25 free); `{}` and the pre-filled form run a free demo; $2 default spend cap on the source for API calls; a review ask in the success status.
- **0.1** (2026-09-21) — initial release: reviews grouped per business from either Google Maps flow; reputation metrics, flags and risk; AI complaints, praise, talking points, fit score and opener; website contact enrichment with MX / mailbox verification; 4 campaign presets; `targetFlags`; cross-run dedupe; webhook; free tier.

# Actor input Schema

## `campaignPreset` (type: `string`):

Start from a ready-made campaign: fills the goal, offer, filters and target opportunities below - anything you type yourself always wins. <b>Custom</b> = use only what you enter.

## `sourceMode` (type: `string`):

<b>actor</b> - run a Google Maps reviews source on your account (its usage is billed separately) and analyse its output. <b>dataset</b> - analyse an existing dataset from the Google Maps Reviews Scraper or the Google Maps Scraper (with reviews). <b>list</b> - paste rows yourself. The form starts on the <b>free demo</b> (sample rows below, nothing charged); switch to <b>actor</b> to analyse your own places.

## `discoveryActorId` (type: `string`):

<b>actor</b> mode. Default <code>compass/Google-Maps-Reviews-Scraper</code> (reviews for places you name). Use <code>compass/crawler-google-places</code> to search by category + city and get websites and phones too - that is what the contact enrichment needs.

## `discoveryInput` (type: `object`):

<b>actor</b> mode. Reviews scraper: <code>startUrls</code> (Google Maps place URLs) or <code>placeIds</code>. Google Maps scraper: <code>searchStringsArray</code> + <code>locationQuery</code> (+ <code>maxCrawledPlacesPerSearch</code>). <code>maxReviews</code>, <code>reviewsSort: newest</code> and no reviewer personal data are set for you.

## `maxDiscoveryChargeUsd` (type: `number`):

Hard cap on what the source Actor run may charge your account (≈ $0.02 per business with 30 reviews on the Google Maps Reviews Scraper). Default $2 — also for API and MCP calls that omit it.

## `maxReviewsPerBusiness` (type: `integer`):

How many of the newest reviews per business are kept and shown to the AI. More = better themes, more tokens.

## `datasetId` (type: `string`):

<b>dataset</b> mode. Output of the Google Maps Reviews Scraper (one row per review) or the Google Maps Scraper with reviews (one row per place).

## `itemsList` (type: `array`):

<b>list</b> mode. Either review rows (<code>placeId</code>, <code>title</code>, <code>stars</code>, <code>text</code>, <code>publishedAtDate</code>, <code>responseFromOwnerText</code>…) or place rows with a <code>reviews</code> array (<code>title</code>, <code>website</code>, <code>phone</code>, <code>totalScore</code>, <code>reviewsCount</code>, <code>reviews: \[{stars, text}]</code>).

## `defaultCountryCode` (type: `string`):

Two-letter country used to normalise phone numbers when a row has no country.

## `goalDescription` (type: `string`):

Describe the businesses you want. The AI scores every business against this. Example: <i>Restaurants and clinics rated 3.5-4.3 whose reviews show recurring service complaints the owner ignores.</i>

## `offerDescription` (type: `string`):

One or two sentences on your offer. Used to judge fit, write the talking points and the outreach opener.

## `minReviewsPerBusiness` (type: `integer`):

Skip businesses with fewer reviews than this in the sample (nothing to analyse).

## `minRating` (type: `number`):

Drop businesses rated below this (0 = no filter).

## `maxRating` (type: `number`):

Drop businesses rated above this - e.g. 4.3 to keep only those with a reputation problem (0 = no filter).

## `targetFlags` (type: `array`):

Only deliver businesses that have at least one of these findings, and rank those with more of them higher. Leave empty to keep every business. Available: <code>low\_rating</code>, <code>mediocre\_rating</code>, <code>few\_reviews</code>, <code>recent\_negative\_reviews</code>, <code>negative\_share\_high</code>, <code>unanswered\_negative\_reviews</code>, <code>low\_owner\_response\_rate</code>, <code>rating\_trend\_down</code>, <code>no\_reviews\_analysed</code>, <code>no\_website</code>, <code>website\_unreachable</code>, <code>no\_email\_found</code>, <code>no\_online\_booking</code>, <code>no\_chat\_widget</code>, <code>no\_analytics</code>, <code>no\_ads\_pixel</code>, <code>slow\_website</code>, <code>site\_builder\_template</code>, <code>closed</code>.

## `requireEmail` (type: `boolean`):

Only deliver (and charge) businesses where an email was found on their website. Needs a source that provides websites.

## `minScore` (type: `integer`):

Businesses scoring below this are discarded and <b>not charged</b>.

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

Drop places marked temporarily or permanently closed.

## `enrichWebsite` (type: `boolean`):

Visit the business website (home + contact/about pages) for emails, phones, WhatsApp, social profiles, owner names, tech stack, booking, chat, tracking pixels and a speed grade. Only for rows that carry a website.

## `maxPagesPerSite` (type: `integer`):

Homepage plus up to this many contact/about pages.

## `respectRobotsTxt` (type: `boolean`):

Skip pages the site's robots.txt disallows.

## `verifyEmails` (type: `boolean`):

Check that each email's domain can receive mail. Free; removes dead addresses.

## `emailVerifier` (type: `string`):

Mailbox-level verification with <b>your own</b> MillionVerifier or NeverBounce account, on top of the MX check. At most 2 addresses per business are checked.

## `emailVerifierApiKey` (type: `string`):

Required when a verification service is selected. Stored encrypted by Apify, never logged.

## `excludeFreeEmailProviders` (type: `boolean`):

Drop gmail / yahoo / hotmail style addresses.

## `enableAi` (type: `boolean`):

Recurring complaints, praise themes, three talking points, a reputation-risk score, the fit score with reasons, the decision-maker and a personalised opener. Off = rule-based metrics only (cheaper).

## `llmProvider` (type: `string`):

<b>Apify (no keys)</b> - the AI runs through Apify's built-in OpenRouter proxy; tokens are billed to your Apify account at OpenRouter's rates. <b>My own key</b> - use your OpenAI / Anthropic / Gemini / Groq key instead.

## `llmModel` (type: `string`):

Leave empty for the default (Claude Haiku 4.5). Apify mode takes an OpenRouter slug such as <code>anthropic/claude-haiku-4.5</code> or <code>openai/gpt-4.1-mini</code>. Own-key mode takes <code>provider:model</code>.

## `llmApiKey` (type: `string`):

Required when <b>AI model access</b> is <i>My own API key</i>. Stored encrypted by Apify, never logged.

## `outreachChannel` (type: `string`):

The opener is written for this channel. Email also gets a subject line.

## `outreachTone` (type: `string`):

Voice of the generated opener.

## `aiCandidateMultiplier` (type: `integer`):

How many of the highest rule-scored businesses get the AI pass, as a multiple of <b>Max qualified</b>.

## `deepResearch` (type: `boolean`):

Let the AI open the business's web page and run a web search before scoring, to verify claims and fill gaps. More tokens and a small web-search charge per call. Off = the AI sees only the record.

## `maxToolCallsPerItem` (type: `integer`):

Hard cap on page fetches + web searches the AI may make for one business in deep-research mode.

## `maxQualified` (type: `integer`):

Hard cap on results (and therefore on what you pay for). The best-scoring businesses are output first.

## `maxToProcess` (type: `integer`):

Upper bound on how many businesses are enriched/scored in one run. Default = 3 x max qualified.

## `dedupeAcrossRuns` (type: `boolean`):

Remembers every business you received (in a named key-value store on your account) and skips it in future runs.

## `dedupeStoreName` (type: `string`):

Key-value store used for cross-run memory. Use different names for different campaigns.

## `webhookUrl` (type: `string`):

Every qualified business is POSTed here as JSON (Zapier, Make, n8n, your CRM). For Google Sheets / Slack use Apify's Integrations tab.

## `webhookHeaders` (type: `object`):

Extra HTTP headers for the webhook, e.g. an Authorization header.

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

Apify Proxy is recommended so website crawling is not blocked.

## Actor input object example

```json
{
  "campaignPreset": "custom",
  "sourceMode": "list",
  "discoveryActorId": "compass/Google-Maps-Reviews-Scraper",
  "discoveryInput": {
    "startUrls": [
      {
        "url": "https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4"
      }
    ]
  },
  "maxDiscoveryChargeUsd": 0.5,
  "maxReviewsPerBusiness": 30,
  "itemsList": [
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 2,
      "text": "Waited 45 minutes past my appointment time and nobody apologised. Front desk never picks up the phone.",
      "publishedAtDate": "2026-09-01",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 1,
      "text": "Called four times to reschedule, no answer, no callback. Went elsewhere.",
      "publishedAtDate": "2026-08-20",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 5,
      "text": "Dr. Patel is wonderful with kids, very gentle.",
      "publishedAtDate": "2026-08-15",
      "responseFromOwnerText": "Thank you!",
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 3,
      "text": "Good dentist but the booking is chaos - double booked twice this year.",
      "publishedAtDate": "2026-08-02",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 4,
      "text": "Clean clinic, friendly hygienist.",
      "publishedAtDate": "2026-07-25",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 2,
      "text": "Overcharged compared to the quote and impossible to reach anyone about it.",
      "publishedAtDate": "2026-07-10",
      "responseFromOwnerText": "We are sorry, please call us.",
      "name": "REDACTED"
    },
    {
      "title": "Python Software Foundation",
      "website": "https://www.python.org",
      "phone": null,
      "totalScore": 4.8,
      "reviewsCount": 120,
      "categoryName": "Non-profit",
      "city": "Wilmington",
      "countryCode": "US",
      "placeId": "ChIJ-psf",
      "reviews": [
        {
          "stars": 5,
          "text": "Great community and documentation."
        },
        {
          "stars": 4,
          "text": "Conference was well organised."
        },
        {
          "stars": 5,
          "text": "Helpful mailing lists."
        }
      ]
    },
    {
      "title": "Corner Café",
      "website": "https://www.mozilla.org",
      "totalScore": 3.6,
      "reviewsCount": 214,
      "categoryName": "Cafe",
      "city": "San Francisco",
      "countryCode": "US",
      "placeId": "ChIJ-corner",
      "reviews": [
        {
          "stars": 1,
          "text": "Cold coffee, rude staff, 20 minute wait for a latte.",
          "publishedAtDate": "2026-09-10"
        },
        {
          "stars": 2,
          "text": "Waited ages, order was wrong, nobody cared.",
          "publishedAtDate": "2026-09-05"
        },
        {
          "stars": 2,
          "text": "Slow service again. The pastries are nice though.",
          "publishedAtDate": "2026-08-28"
        },
        {
          "stars": 5,
          "text": "Lovely pastries and a sunny terrace.",
          "publishedAtDate": "2026-08-01"
        },
        {
          "stars": 3,
          "text": "Decent food, chaotic service at lunchtime.",
          "publishedAtDate": "2026-07-20"
        }
      ]
    }
  ],
  "defaultCountryCode": "US",
  "minReviewsPerBusiness": 3,
  "minRating": 0,
  "maxRating": 0,
  "requireEmail": false,
  "minScore": 50,
  "skipClosedPlaces": true,
  "enrichWebsite": true,
  "maxPagesPerSite": 3,
  "respectRobotsTxt": true,
  "verifyEmails": true,
  "emailVerifier": "none",
  "excludeFreeEmailProviders": false,
  "enableAi": true,
  "llmProvider": "apify",
  "outreachChannel": "email",
  "outreachTone": "friendly",
  "aiCandidateMultiplier": 2,
  "deepResearch": false,
  "maxToolCallsPerItem": 3,
  "maxQualified": 100,
  "dedupeAcrossRuns": true,
  "dedupeStoreName": "google-reviews-insights-seen",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `qualified` (type: `string`):

All qualified businesses as JSON, best-scoring first.

## `reputationCsv` (type: `string`):

Rating, recent average, negative and unanswered counts, reply rate, risk, complaints, praise, talking points per business.

## `outreachCsv` (type: `string`):

Business, decision-maker, direct email, phone, WhatsApp, subject, opener and next step - the columns an outreach tool needs.

## `runSummary` (type: `string`):

JSON record with the funnel (businesses -> filtered -> enriched -> AI-analysed -> qualified), per-reason skip counts, charged events, free-tier balance and webhook delivery counts.

# 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 = {
    "sourceMode": "list",
    "discoveryInput": {
        "startUrls": [
            {
                "url": "https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4"
            }
        ]
    },
    "maxDiscoveryChargeUsd": 0.5,
    "itemsList": [
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 2,
            "text": "Waited 45 minutes past my appointment time and nobody apologised. Front desk never picks up the phone.",
            "publishedAtDate": "2026-09-01",
            "responseFromOwnerText": null,
            "name": "REDACTED"
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 1,
            "text": "Called four times to reschedule, no answer, no callback. Went elsewhere.",
            "publishedAtDate": "2026-08-20",
            "responseFromOwnerText": null,
            "name": "REDACTED"
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 5,
            "text": "Dr. Patel is wonderful with kids, very gentle.",
            "publishedAtDate": "2026-08-15",
            "responseFromOwnerText": "Thank you!",
            "name": "REDACTED"
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 3,
            "text": "Good dentist but the booking is chaos - double booked twice this year.",
            "publishedAtDate": "2026-08-02",
            "responseFromOwnerText": null,
            "name": "REDACTED"
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 4,
            "text": "Clean clinic, friendly hygienist.",
            "publishedAtDate": "2026-07-25",
            "responseFromOwnerText": null,
            "name": "REDACTED"
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 2,
            "text": "Overcharged compared to the quote and impossible to reach anyone about it.",
            "publishedAtDate": "2026-07-10",
            "responseFromOwnerText": "We are sorry, please call us.",
            "name": "REDACTED"
        },
        {
            "title": "Python Software Foundation",
            "website": "https://www.python.org",
            "phone": null,
            "totalScore": 4.8,
            "reviewsCount": 120,
            "categoryName": "Non-profit",
            "city": "Wilmington",
            "countryCode": "US",
            "placeId": "ChIJ-psf",
            "reviews": [
                {
                    "stars": 5,
                    "text": "Great community and documentation."
                },
                {
                    "stars": 4,
                    "text": "Conference was well organised."
                },
                {
                    "stars": 5,
                    "text": "Helpful mailing lists."
                }
            ]
        },
        {
            "title": "Corner Café",
            "website": "https://www.mozilla.org",
            "totalScore": 3.6,
            "reviewsCount": 214,
            "categoryName": "Cafe",
            "city": "San Francisco",
            "countryCode": "US",
            "placeId": "ChIJ-corner",
            "reviews": [
                {
                    "stars": 1,
                    "text": "Cold coffee, rude staff, 20 minute wait for a latte.",
                    "publishedAtDate": "2026-09-10"
                },
                {
                    "stars": 2,
                    "text": "Waited ages, order was wrong, nobody cared.",
                    "publishedAtDate": "2026-09-05"
                },
                {
                    "stars": 2,
                    "text": "Slow service again. The pastries are nice though.",
                    "publishedAtDate": "2026-08-28"
                },
                {
                    "stars": 5,
                    "text": "Lovely pastries and a sunny terrace.",
                    "publishedAtDate": "2026-08-01"
                },
                {
                    "stars": 3,
                    "text": "Decent food, chaotic service at lunchtime.",
                    "publishedAtDate": "2026-07-20"
                }
            ]
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("rich_minds/google-reviews-insights").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 = {
    "sourceMode": "list",
    "discoveryInput": { "startUrls": [{ "url": "https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4" }] },
    "maxDiscoveryChargeUsd": 0.5,
    "itemsList": [
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 2,
            "text": "Waited 45 minutes past my appointment time and nobody apologised. Front desk never picks up the phone.",
            "publishedAtDate": "2026-09-01",
            "responseFromOwnerText": None,
            "name": "REDACTED",
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 1,
            "text": "Called four times to reschedule, no answer, no callback. Went elsewhere.",
            "publishedAtDate": "2026-08-20",
            "responseFromOwnerText": None,
            "name": "REDACTED",
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 5,
            "text": "Dr. Patel is wonderful with kids, very gentle.",
            "publishedAtDate": "2026-08-15",
            "responseFromOwnerText": "Thank you!",
            "name": "REDACTED",
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 3,
            "text": "Good dentist but the booking is chaos - double booked twice this year.",
            "publishedAtDate": "2026-08-02",
            "responseFromOwnerText": None,
            "name": "REDACTED",
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 4,
            "text": "Clean clinic, friendly hygienist.",
            "publishedAtDate": "2026-07-25",
            "responseFromOwnerText": None,
            "name": "REDACTED",
        },
        {
            "placeId": "ChIJ-bright-smile",
            "title": "Bright Smile Dental",
            "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
            "totalScore": 4.1,
            "reviewsCount": 87,
            "categoryName": "Dentist",
            "address": "12 Main St, Austin, TX",
            "city": "Austin",
            "countryCode": "US",
            "stars": 2,
            "text": "Overcharged compared to the quote and impossible to reach anyone about it.",
            "publishedAtDate": "2026-07-10",
            "responseFromOwnerText": "We are sorry, please call us.",
            "name": "REDACTED",
        },
        {
            "title": "Python Software Foundation",
            "website": "https://www.python.org",
            "phone": None,
            "totalScore": 4.8,
            "reviewsCount": 120,
            "categoryName": "Non-profit",
            "city": "Wilmington",
            "countryCode": "US",
            "placeId": "ChIJ-psf",
            "reviews": [
                {
                    "stars": 5,
                    "text": "Great community and documentation.",
                },
                {
                    "stars": 4,
                    "text": "Conference was well organised.",
                },
                {
                    "stars": 5,
                    "text": "Helpful mailing lists.",
                },
            ],
        },
        {
            "title": "Corner Café",
            "website": "https://www.mozilla.org",
            "totalScore": 3.6,
            "reviewsCount": 214,
            "categoryName": "Cafe",
            "city": "San Francisco",
            "countryCode": "US",
            "placeId": "ChIJ-corner",
            "reviews": [
                {
                    "stars": 1,
                    "text": "Cold coffee, rude staff, 20 minute wait for a latte.",
                    "publishedAtDate": "2026-09-10",
                },
                {
                    "stars": 2,
                    "text": "Waited ages, order was wrong, nobody cared.",
                    "publishedAtDate": "2026-09-05",
                },
                {
                    "stars": 2,
                    "text": "Slow service again. The pastries are nice though.",
                    "publishedAtDate": "2026-08-28",
                },
                {
                    "stars": 5,
                    "text": "Lovely pastries and a sunny terrace.",
                    "publishedAtDate": "2026-08-01",
                },
                {
                    "stars": 3,
                    "text": "Decent food, chaotic service at lunchtime.",
                    "publishedAtDate": "2026-07-20",
                },
            ],
        },
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("rich_minds/google-reviews-insights").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 '{
  "sourceMode": "list",
  "discoveryInput": {
    "startUrls": [
      {
        "url": "https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4"
      }
    ]
  },
  "maxDiscoveryChargeUsd": 0.5,
  "itemsList": [
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 2,
      "text": "Waited 45 minutes past my appointment time and nobody apologised. Front desk never picks up the phone.",
      "publishedAtDate": "2026-09-01",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 1,
      "text": "Called four times to reschedule, no answer, no callback. Went elsewhere.",
      "publishedAtDate": "2026-08-20",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 5,
      "text": "Dr. Patel is wonderful with kids, very gentle.",
      "publishedAtDate": "2026-08-15",
      "responseFromOwnerText": "Thank you!",
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 3,
      "text": "Good dentist but the booking is chaos - double booked twice this year.",
      "publishedAtDate": "2026-08-02",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 4,
      "text": "Clean clinic, friendly hygienist.",
      "publishedAtDate": "2026-07-25",
      "responseFromOwnerText": null,
      "name": "REDACTED"
    },
    {
      "placeId": "ChIJ-bright-smile",
      "title": "Bright Smile Dental",
      "url": "https://www.google.com/maps/place/?q=place_id:ChIJ-bright-smile",
      "totalScore": 4.1,
      "reviewsCount": 87,
      "categoryName": "Dentist",
      "address": "12 Main St, Austin, TX",
      "city": "Austin",
      "countryCode": "US",
      "stars": 2,
      "text": "Overcharged compared to the quote and impossible to reach anyone about it.",
      "publishedAtDate": "2026-07-10",
      "responseFromOwnerText": "We are sorry, please call us.",
      "name": "REDACTED"
    },
    {
      "title": "Python Software Foundation",
      "website": "https://www.python.org",
      "phone": null,
      "totalScore": 4.8,
      "reviewsCount": 120,
      "categoryName": "Non-profit",
      "city": "Wilmington",
      "countryCode": "US",
      "placeId": "ChIJ-psf",
      "reviews": [
        {
          "stars": 5,
          "text": "Great community and documentation."
        },
        {
          "stars": 4,
          "text": "Conference was well organised."
        },
        {
          "stars": 5,
          "text": "Helpful mailing lists."
        }
      ]
    },
    {
      "title": "Corner Café",
      "website": "https://www.mozilla.org",
      "totalScore": 3.6,
      "reviewsCount": 214,
      "categoryName": "Cafe",
      "city": "San Francisco",
      "countryCode": "US",
      "placeId": "ChIJ-corner",
      "reviews": [
        {
          "stars": 1,
          "text": "Cold coffee, rude staff, 20 minute wait for a latte.",
          "publishedAtDate": "2026-09-10"
        },
        {
          "stars": 2,
          "text": "Waited ages, order was wrong, nobody cared.",
          "publishedAtDate": "2026-09-05"
        },
        {
          "stars": 2,
          "text": "Slow service again. The pastries are nice though.",
          "publishedAtDate": "2026-08-28"
        },
        {
          "stars": 5,
          "text": "Lovely pastries and a sunny terrace.",
          "publishedAtDate": "2026-08-01"
        },
        {
          "stars": 3,
          "text": "Decent food, chaotic service at lunchtime.",
          "publishedAtDate": "2026-07-20"
        }
      ]
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call rich_minds/google-reviews-insights --silent --output-dataset

```

## MCP server setup

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

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/Ed58KP7Zz6nq3PQt9/builds/iyhSWFSShfl4L2tUM/openapi.json
