# Review Intelligence Analyzer - Google Reviews Sales Signals (`santamaria-automations/review-intelligence-analyzer`) Actor

Analyze a business's Google Maps reviews with an LLM and return structured intelligence a sales team can act on: overall sentiment, complaint themes, praise themes, owner-response tone, red flags and opportunity signals. Bring your own LLM key (Gemini, Groq, OpenRouter). Pay-per-result.

- **URL**: https://apify.com/santamaria-automations/review-intelligence-analyzer.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Lead generation, AI, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 analyzed places

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

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

## What's an Apify Actor?

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

## How to integrate an Actor?

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

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

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

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

# README

## Review Intelligence Analyzer

Turn a business's Google Maps reviews into structured intelligence a sales team can act on. Feed in place records with `user_reviews[]` populated and get back overall sentiment, complaint themes, praise themes, owner-response tone, red flags and opportunity signals. Bring your own LLM key (Gemini has a generous free tier).

Pair with the [Google Maps Scraper](https://apify.com/santamaria-automations/google-maps-scraper) run with `includeReviews: true`, and get one intelligence row per business ready to prioritize outbound.

### What It Does

Given a Google Maps place record with `user_reviews[]` populated, the actor asks an LLM to analyze the reviews and return:

- `overall_sentiment` - one of `strongly_positive`, `positive`, `mixed`, `negative`, `strongly_negative`
- `sentiment_score` - a number between -1.0 and +1.0
- `complaint_themes[]` - up to 5 objects `{theme, frequency, sample_quote}` when reviews contain recurring complaints
- `praise_themes[]` - up to 5 objects with the same shape when reviews contain recurring praise
- `owner_tone` - one of `professional`, `defensive`, `dismissive`, `absent`, `mixed`
- `red_flags[]` - subset of `fake_review_pattern`, `recent_1_star_cluster`, `no_owner_response`, `hostile_owner_response`, `rating_drop_recent`, `language_barrier`
- `opportunity_signals[]` - subset of `ready_for_promotion`, `high_repeat_customer`, `asks_for_specific_service`, `seasonal_demand`, `underrated_gem`

The LLM only references what actually appears in the reviews. Sample quotes are verbatim snippets, never paraphrased. Themes below 2 occurrences are dropped.

### When To Use

- Prioritize outbound: skip businesses with `strongly_positive` sentiment and empty `red_flags`, prioritize those with `no_owner_response` or `recent_1_star_cluster`.
- Sharper cold email: fold `complaint_themes[0].theme` or an `opportunity_signals` value into your opener.
- Reputation risk audits: flag agency clients whose review streams show `hostile_owner_response` or a `rating_drop_recent`.
- Discovery for the "underrated gem" ICP.

### Input

Two shapes are accepted and can be mixed in one run.

Flat places list (natural shape, pipe the google-maps-scraper output directly):

```json
{
  "places": [
    {
      "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
      "title": "Example Coffee House",
      "category": "Coffee shop",
      "rating": 4.6,
      "review_count": 1240,
      "complete_address": { "city": "Berlin", "country": "Germany" },
      "user_reviews": [
        { "rating": 5, "text": "...", "published_at": "2026-05-01", "response_from_owner": null },
        { "rating": 2, "text": "...", "published_at": "2026-04-15", "response_from_owner": "..." }
      ]
    }
  ],
  "geminiApiKey": "AIza..."
}
```

Companies shape (with a `company_id` passthrough for join-back to your CRM):

```json
{
  "companies": [
    { "company_id": "acme-42", "place": { "place_id": "ChIJ...", "title": "Example Company", "user_reviews": [] } }
  ],
  "geminiApiKey": "AIza..."
}
```

`maxReviewsSampled` (default 30, min 5, max 60) caps how many reviews per place go into the LLM prompt. The sampler blends most-recent, highest-rated and lowest-rated reviews so both praise and complaint edges are represented.

### LLM Configuration

You must supply at least one LLM key. All three providers are supported:

| Provider | Free tier | Get a key |
|----------|-----------|-----------|
| Gemini | Yes (generous) | https://aistudio.google.com/app/apikey |
| Groq | Yes | https://console.groq.com/keys |
| OpenRouter | Pay-as-you-go, cheap | https://openrouter.ai/keys |

Set `llmProvider` to pick the primary, `fallbackProvider` and `fallback2Provider` for the chain. Same-provider transient errors (5xx, timeouts) get one retry. Auth and quota errors fall through to the next provider.

### Output

One row per input place:

```json
{
  "company_id": "acme-42",
  "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
  "name": "Example Coffee House",
  "analyzed_at": "2026-07-21T10:30:00Z",
  "overall_sentiment": "positive",
  "sentiment_score": 0.62,
  "complaint_themes": [
    { "theme": "slow service on weekends", "frequency": 3, "sample_quote": "waited 20 minutes just to order" }
  ],
  "praise_themes": [
    { "theme": "friendly staff", "frequency": 6, "sample_quote": "the team remembers our order" },
    { "theme": "great pastries", "frequency": 4, "sample_quote": "chocolate croissant was fantastic" }
  ],
  "owner_tone": "professional",
  "red_flags": [],
  "opportunity_signals": ["high_repeat_customer"],
  "reviews_analyzed": 10,
  "llm_provider": "gemini",
  "llm_model": "gemini-2.0-flash",
  "llm_tokens_input": 1240,
  "llm_tokens_output": 340
}
```

Places with no reviews or no LLM key emit a row with `skip_reason` set (`no_reviews`, `no_llm_key`, or `llm_failed`) and no billing charge. Themes and enum arrays default to `[]`, sentiment fields to `null`.

### How To Use It

1. Run [Google Maps Scraper](https://apify.com/santamaria-automations/google-maps-scraper) with `includeReviews: true` to collect places and their reviews.
2. Feed the dataset into this actor as `places` (or wrap each in `companies` for join-back).
3. Set your Gemini key. Optionally add Groq and OpenRouter as fallbacks.
4. Feed the output into your prioritization rules or your outbound sequencer.

### Pricing

Pay-per-result via Apify Pay-Per-Event billing:

| Event | Price | Description |
|-------|-------|-------------|
| Actor start | $0.001 | Charged once per run when there is at least one analyzable place |
| Result | $0.005 | Charged once per analyzed place. Skipped places (no reviews, no key, LLM failure) are NOT billed |

Analyzing 1,000 places costs about $5. LLM API usage is billed by your provider directly, not by this actor.

### Related Actors

Discovery:

- [Google Maps Scraper](https://apify.com/santamaria-automations/google-maps-scraper) - collect places and their reviews in bulk

Enrichment:

- [AI Icebreaker Generator](https://apify.com/santamaria-automations/ai-icebreaker) - one hyper-personalized cold-outreach line per place
- [GBP Completeness Audit](https://apify.com/santamaria-automations/gbp-completeness-audit) - score Google Business Profiles for lead prioritization
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor) - LLM-powered people extraction from company sites

### Notes

- Empty input is free. `enrichment-start` is only billed when there is at least one place with analyzable reviews.
- The proxy configuration field is accepted for schema consistency but is not used by this actor (LLM-only).
- Language: set `outputLanguage: "auto"` to have theme labels and quotes translated back to the business's country language.

### Issues & Feature Requests

If the model keeps under- or over-flagging a class of business, open an issue on the actor's Issues tab and we will look into it.

# Actor input Schema

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

Array of Google Maps place records. Each element is a full place object as emitted by the google-maps-scraper actor with `user_reviews[]` populated (run gmaps with `includeReviews: true`).

## `companies` (type: `array`):

Alternative to `places`. Each entry carries a company\_id (echoed on the output row) plus the place record.

## `maxReviewsSampled` (type: `integer`):

Cap on the number of reviews sent to the LLM per place. Higher = sharper signals but higher per-row token cost. The sampler blends most-recent, highest-rated and lowest-rated reviews so both praise and complaint angles are represented.

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

Primary AI provider. Gemini Flash is fastest and has a generous free tier.

## `fallbackProvider` (type: `string`):

Second-level fallback if the primary provider fails (rate limit, auth error, etc).

## `fallback2Provider` (type: `string`):

Third-level fallback if both primary and first fallback fail.

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

Override the default model. Defaults: Gemini -> gemini-2.0-flash, Groq -> llama-3.3-70b-versatile, OpenRouter -> google/gemini-2.0-flash-001. If your OpenRouter key does not have access to the default paid Gemini model, try a free model like meta-llama/llama-3.1-8b-instruct.

## `geminiApiKey` (type: `string`):

Google Gemini Flash. Best quality/cost ratio, generous free tier. Get a key at https://aistudio.google.com/app/apikey

## `groqApiKey` (type: `string`):

Groq. Ultra-fast inference. Get a key at https://console.groq.com/keys

## `openrouterApiKey` (type: `string`):

OpenRouter. Access to 100+ models. Get a key at https://openrouter.ai/keys

## `outputLanguage` (type: `string`):

Language for the theme labels and sample quotes translated back. Uses standard ISO 639-1 codes: en, de, fr, ja, es, pt, it, ko, zh-CN, ar, nl, pl, sv, da, fi, no, cs, hu, ro, el, tr, th, vi, id, and more. Set to `auto` to match the business's country/language.

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

Not used by this actor (LLM calls only). Accepted for schema consistency with sibling enrichment actors.

## Actor input object example

```json
{
  "places": [
    {
      "place_id": "ChIJExamplePositive1",
      "title": "Example Coffee House",
      "category": "Coffee shop",
      "rating": 4.8,
      "review_count": 1240,
      "complete_address": {
        "city": "Berlin",
        "country": "Germany"
      },
      "user_reviews": [
        {
          "name": "Anna",
          "rating": 5,
          "text": "Best flat white in the neighborhood. Staff remember my name.",
          "published_at": "2026-05-01",
          "response_from_owner": null
        },
        {
          "name": "Ben",
          "rating": 5,
          "text": "Great pastries, always fresh. Cozy atmosphere too.",
          "published_at": "2026-04-15",
          "response_from_owner": null
        },
        {
          "name": "Chris",
          "rating": 4,
          "text": "Excellent coffee, gets crowded on Saturdays but worth the wait.",
          "published_at": "2026-03-20",
          "response_from_owner": null
        }
      ]
    }
  ],
  "maxReviewsSampled": 30,
  "llmProvider": "gemini",
  "outputLanguage": "en",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `reviewIntelligence` (type: `string`):

Dataset of review intelligence rows

# 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": [
        {
            "place_id": "ChIJExamplePositive1",
            "title": "Example Coffee House",
            "category": "Coffee shop",
            "rating": 4.8,
            "review_count": 1240,
            "complete_address": {
                "city": "Berlin",
                "country": "Germany"
            },
            "user_reviews": [
                {
                    "name": "Anna",
                    "rating": 5,
                    "text": "Best flat white in the neighborhood. Staff remember my name.",
                    "published_at": "2026-05-01",
                    "response_from_owner": null
                },
                {
                    "name": "Ben",
                    "rating": 5,
                    "text": "Great pastries, always fresh. Cozy atmosphere too.",
                    "published_at": "2026-04-15",
                    "response_from_owner": null
                },
                {
                    "name": "Chris",
                    "rating": 4,
                    "text": "Excellent coffee, gets crowded on Saturdays but worth the wait.",
                    "published_at": "2026-03-20",
                    "response_from_owner": null
                }
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/review-intelligence-analyzer").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": [{
            "place_id": "ChIJExamplePositive1",
            "title": "Example Coffee House",
            "category": "Coffee shop",
            "rating": 4.8,
            "review_count": 1240,
            "complete_address": {
                "city": "Berlin",
                "country": "Germany",
            },
            "user_reviews": [
                {
                    "name": "Anna",
                    "rating": 5,
                    "text": "Best flat white in the neighborhood. Staff remember my name.",
                    "published_at": "2026-05-01",
                    "response_from_owner": None,
                },
                {
                    "name": "Ben",
                    "rating": 5,
                    "text": "Great pastries, always fresh. Cozy atmosphere too.",
                    "published_at": "2026-04-15",
                    "response_from_owner": None,
                },
                {
                    "name": "Chris",
                    "rating": 4,
                    "text": "Excellent coffee, gets crowded on Saturdays but worth the wait.",
                    "published_at": "2026-03-20",
                    "response_from_owner": None,
                },
            ],
        }] }

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/review-intelligence-analyzer").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": [
    {
      "place_id": "ChIJExamplePositive1",
      "title": "Example Coffee House",
      "category": "Coffee shop",
      "rating": 4.8,
      "review_count": 1240,
      "complete_address": {
        "city": "Berlin",
        "country": "Germany"
      },
      "user_reviews": [
        {
          "name": "Anna",
          "rating": 5,
          "text": "Best flat white in the neighborhood. Staff remember my name.",
          "published_at": "2026-05-01",
          "response_from_owner": null
        },
        {
          "name": "Ben",
          "rating": 5,
          "text": "Great pastries, always fresh. Cozy atmosphere too.",
          "published_at": "2026-04-15",
          "response_from_owner": null
        },
        {
          "name": "Chris",
          "rating": 4,
          "text": "Excellent coffee, gets crowded on Saturdays but worth the wait.",
          "published_at": "2026-03-20",
          "response_from_owner": null
        }
      ]
    }
  ]
}' |
apify call santamaria-automations/review-intelligence-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=santamaria-automations/review-intelligence-analyzer",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/h2PLnw3h4OZaRPfvc/builds/bVgKCD8swpH5UPwff/openapi.json
