# Review Weakness Intelligence (`apium/review-weakness-intelligence`) Actor

Scrapes a business's Google Maps reviews (and optionally Trustpilot) and outputs themed complaint categories with sentiment and example quotes instead of a wall of raw reviews.

- **URL**: https://apify.com/apium/review-weakness-intelligence.md
- **Developed by:** [Tommi Sullivan](https://apify.com/apium) (community)
- **Categories:** Marketing, AI
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 result items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## Review Weakness Intelligence — What Customers Actually Complain About

**Turn a pile of reviews into a ranked list of complaints.** Point it at a business (Google Maps, optionally Trustpilot) and instead of dumping raw reviews, it clusters them into themes — "slow service", "billing surprises", "rude staff" — with a sentiment read, mention counts, and example quotes. The output is a CX/competitive-intel brief, not a review export.

> Keywords: review analysis, customer complaint analysis, voice of customer, google reviews sentiment, trustpilot analysis, competitor weakness research.

---

### Why this actor

Every other review scraper hands you 500 raw rows and leaves the reading to you. This one does the synthesis:

- **Theme clustering** groups reviews by what they're about using a transparent keyword/topic method (no black-box ML) — clearly labeled so you can trust and tune it.
- **Sentiment + severity** per theme, so the worst problems float to the top.
- **Example quotes** per theme, so a human can sanity-check instantly.
- **Two sources** — Google Maps reviews (via Places API) and optionally a Trustpilot URL — merged into one themed view.

Use it to audit your own business, or to find a competitor's soft spots before a pitch.

---

### What it does

1. Resolves the business: search by `businessName` + `location`, or use a provided `placeId` directly.
2. Fetches Place Details reviews (up to `maxReviews`).
3. Optionally fetches Trustpilot reviews from `trustpilotUrl`.
4. Clusters combined reviews into themes (keyword/topic), scores sentiment, keeps themes with at least `minMentionsPerTheme` mentions.
5. Pushes one record per theme per source and charges per pushed result.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `businessName` | string | — | **required** |
| `location` | string | — | helps resolve the right place |
| `placeId` | string | — | use directly instead of searching |
| `trustpilotUrl` | string | — | optional second source |
| `maxReviews` | integer | 50 | cap on reviews pulled |
| `minMentionsPerTheme` | integer | 2 | drop themes below this |
| `googlePlacesApiKey` | string (secret) | — | **required** — Places API (New) key |
| `proxyConfiguration` | object | — | optional Apify proxy |

### Output (per theme, per source)

`theme`, `source` (`google_maps` / `trustpilot`), `mention_count`, `sentiment`, `severity`, `example_quotes`, `sample_ratings`.

### Notes & honesty

- Theme clustering is a **transparent keyword/topic method**, not an LLM — good for scale and cost, not perfect nuance. Tune keywords in `theming.py`.
- Google Place Details typically returns a **limited** number of reviews per call — `maxReviews` is bounded by what the API exposes (marked `TODO-VERIFY` in `places_client.py`).
- Trustpilot parsing in `trustpilot_client.py` is best-effort and marked `TODO-VERIFY` — confirm against a live page before production.
- Original implementation; not derived from any other actor's code.

# Actor input Schema

## `businessName` (type: `string`):

The business to analyze, e.g. 'Joe's Pizza Austin'. Used both as a label in the output and, combined with 'location', as the Google Places search query.
## `location` (type: `string`):

City/area to disambiguate the business search, e.g. 'Austin, TX'.
## `placeId` (type: `string`):

If you already know the exact Google Place ID, provide it here to skip the text-search disambiguation step entirely.
## `trustpilotUrl` (type: `string`):

Optional: a Trustpilot business review page URL (e.g. https://www.trustpilot.com/review/example.com) to include Trustpilot reviews alongside Google Maps reviews in the theme analysis.
## `maxReviews` (type: `integer`):

Cap on how many reviews are pulled and analyzed per source (Google Maps / Trustpilot). Google's Places API (New) exposes at most ~5 reviews per place in the standard response (TODO-VERIFY); Trustpilot pages typically expose more per page.
## `minMentionsPerTheme` (type: `integer`):

Only output a complaint theme if it was mentioned in at least this many reviews. Filters out one-off noise.
## `googlePlacesApiKey` (type: `string`):

Your Google Cloud Places API key (Places API (New) must be enabled, billing required). TODO-VERIFY: exact enabled-API name/billing tier, and the ~5-review-per-place limit — confirm in Google Cloud Console. Get one at https://console.cloud.google.com/apis/credentials.
## `proxyConfiguration` (type: `object`):

Proxy used only for the optional Trustpilot page fetch (Trustpilot is a public review page, not a JSON API, and may rate-limit datacenter IPs at volume). Google Places API calls go direct. Leave default unless Trustpilot fetches start failing.

## Actor input object example

```json
{
  "businessName": "Joe's Pizza Austin",
  "location": "Austin, TX",
  "maxReviews": 50,
  "minMentionsPerTheme": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
````

# 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 = {
    "businessName": "Joe's Pizza Austin",
    "location": "Austin, TX",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apium/review-weakness-intelligence").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 = {
    "businessName": "Joe's Pizza Austin",
    "location": "Austin, TX",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("apium/review-weakness-intelligence").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 '{
  "businessName": "Joe'\''s Pizza Austin",
  "location": "Austin, TX",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call apium/review-weakness-intelligence --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Review Weakness Intelligence",
        "description": "Scrapes a business's Google Maps reviews (and optionally Trustpilot) and outputs themed complaint categories with sentiment and example quotes instead of a wall of raw reviews.",
        "version": "0.1",
        "x-build-id": "a6BXcZhU1sdCgr3mh"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/apium~review-weakness-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-apium-review-weakness-intelligence",
                "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/apium~review-weakness-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-apium-review-weakness-intelligence",
                "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/apium~review-weakness-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-apium-review-weakness-intelligence",
                "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": [
                    "businessName",
                    "googlePlacesApiKey"
                ],
                "properties": {
                    "businessName": {
                        "title": "Business name",
                        "type": "string",
                        "description": "The business to analyze, e.g. 'Joe's Pizza Austin'. Used both as a label in the output and, combined with 'location', as the Google Places search query."
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "City/area to disambiguate the business search, e.g. 'Austin, TX'."
                    },
                    "placeId": {
                        "title": "Google Place ID (optional, skips search)",
                        "type": "string",
                        "description": "If you already know the exact Google Place ID, provide it here to skip the text-search disambiguation step entirely."
                    },
                    "trustpilotUrl": {
                        "title": "Trustpilot business URL (optional)",
                        "type": "string",
                        "description": "Optional: a Trustpilot business review page URL (e.g. https://www.trustpilot.com/review/example.com) to include Trustpilot reviews alongside Google Maps reviews in the theme analysis."
                    },
                    "maxReviews": {
                        "title": "Max reviews to analyze per source",
                        "minimum": 5,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Cap on how many reviews are pulled and analyzed per source (Google Maps / Trustpilot). Google's Places API (New) exposes at most ~5 reviews per place in the standard response (TODO-VERIFY); Trustpilot pages typically expose more per page.",
                        "default": 50
                    },
                    "minMentionsPerTheme": {
                        "title": "Minimum mentions to report a theme",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Only output a complaint theme if it was mentioned in at least this many reviews. Filters out one-off noise.",
                        "default": 2
                    },
                    "googlePlacesApiKey": {
                        "title": "Google Places API key",
                        "type": "string",
                        "description": "Your Google Cloud Places API key (Places API (New) must be enabled, billing required). TODO-VERIFY: exact enabled-API name/billing tier, and the ~5-review-per-place limit — confirm in Google Cloud Console. Get one at https://console.cloud.google.com/apis/credentials."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy used only for the optional Trustpilot page fetch (Trustpilot is a public review page, not a JSON API, and may rate-limit datacenter IPs at volume). Google Places API calls go direct. Leave default unless Trustpilot fetches start failing.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
