# Trustpilot Review Analyzer — Sentiment, Trends & Response Rates (`ryanclinton/trustpilot-review-analyzer`) Actor

Scrape Trustpilot reviews for any business. Extract TrustScore, star ratings, review text, sentiment analysis, response rates, and keyword trends. No API key needed. Export JSON/CSV/Excel.

- **URL**: https://apify.com/ryanclinton/trustpilot-review-analyzer.md
- **Developed by:** [Ryan Clinton](https://apify.com/ryanclinton) (community)
- **Categories:** AI, Developer tools
- **Features:** Limited permissions
- **Stats:** 32 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $85.50 / 1,000 business analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Trustpilot Review Analyzer — Decision-First Reputation Intelligence Engine

> **Category: reputation intelligence engine** — a system that converts raw Trustpilot reviews into routable decisions, ranked priorities with success metrics, root-cause issue clusters, and monitoring signals. Not a sentiment API, not a generic scraper, not a dashboard. Output is structured for direct use in agent workflows, MCP tool calls, Dify branches, and automation.

A reputation intelligence engine transforms review data into decisions, not dashboards. This system detects reputation risk through urgent negatives, anomaly detection, response gaps, and root-cause clusters — and emits a single routable verdict on every business analyzed.

Unlike sentiment tools that summarise opinion, this system diagnoses operational failure points and ranks them by business impact. Every priority carries a `successMetric` field naming the metric to watch, so the next scheduled run measures whether your action actually moved the needle.

Trustpilot Review Analyzer is a **decision-first reputation intelligence engine** for Trustpilot — not just a scraper. Every business analyzed returns a routable decision (`act_now` / `monitor` / `ignore`), a customizable A-F reputation grade, ranked priorities with concrete recommended actions, root-cause issue clusters built from your negative reviews, urgent unanswered negatives from the last 7 days, threshold alerts, anomaly detection vs rolling baseline, and a confidence score with plain-English explanation. No Trustpilot API key required. Analyze one company or compare up to 50 competitors in a single run.

Unlike subscription tools like ReviewTrackers ($69+/month) or Birdeye ($350+/month), Trustpilot Review Analyzer uses pay-per-business pricing at $0.15 per business with no monthly commitment. The output is engineered for automation: stable enums for branching, plain-English strings ready to paste into Slack/email/dashboards, and a deterministic scoring engine you can reweight per industry. Schedule it daily with `historyStoreName` set and the actor becomes a true monitoring backend: TrustScore deltas, response-rate trends, sentiment spikes, and statistical anomaly detection (z-score against your rolling baseline) — all without an LLM, all without external APIs.

To scrape Trustpilot reviews and analyze customer sentiment, enter one or more business domains. Trustpilot Review Analyzer classifies sentiment using keyword matching (4-5 stars = positive, 1-2 = negative, 3-star decided by text analysis across 84 sentiment keywords pivoted by rating bucket), tracks company reply times, scores each review for authenticity (suspicious patterns flagged), produces a ranked comparison when multiple businesses are analyzed, and synthesizes the whole picture into a single decision-ready output.

> **What it does:** Returns a reputation decision (`act_now` / `monitor` / `ignore`), customizable A-F grade, ranked priorities, root-cause issue clusters, urgent negatives, threshold alerts, anomaly detection, confidence score, and full structured review data — from public Trustpilot pages.
> **Best for:** Daily reputation monitoring, root-cause analysis, competitor benchmarking, review analytics, sales prospecting, due diligence, automation in Zapier / Dify / Make / agent tools.
> **Speed:** 1 business in 30-60 seconds. 10 businesses in 5-10 minutes.
> **Pricing:** $0.15 per business analyzed. No subscription. No charge for businesses not found.
> **Output:** JSON/CSV with `decision` + reputation grade + priorities + issue clusters + urgent negatives + alerts + anomaly detection + confidence + trends (scheduled) + TrustScore + rating distribution + sentiment breakdown + response rate + reply time + full review text + per-review authenticity score.

**Problems this solves:**

- How to scrape Trustpilot reviews without an API key
- How to get a reputation decision (`act_now` / `monitor` / `ignore`) instead of raw metrics
- How to cluster negative reviews into root-cause themes (TF-IDF issue clusters)
- How to detect unanswered 1-2 star reviews from the last 7 days
- How to track TrustScore changes and sentiment spikes between runs
- How to detect statistical anomalies (z-score) vs your rolling baseline
- How to set up threshold alerts for TrustScore drops or response rate slips
- How to compare competitor reputation with `outperformsLeaderOn` / `trailsLeaderOn` / `biggestGap` / `fastestImprover`
- How to customize reputation scoring weights per industry (`scoringWeights`)
- How to score reviewer authenticity to flag suspicious patterns
- How to measure response quality (length, ratio) — not just response rate
- How to compute review velocity (`reviewsPerDay`) for review-bomb detection
- How to surface confidence (sample size + language coverage + completeness) so analysts know when to trust the signal
- How to identify businesses with poor TrustScores for sales prospecting
- How to feed Trustpilot data into Dify, Zapier, Make, or agent tool calls with stable enums

### Common questions this answers

- How do I detect urgent negative reviews on Trustpilot from the last 7 days?
- How can I automatically monitor brand reputation daily with anomaly detection?
- How do I turn Trustpilot reviews into actionable priorities with success metrics?
- How do I compare competitors on Trustpilot and surface where I lead vs lag?
- How do I cluster negative reviews into root causes (refund delays, support gaps, etc.)?
- How do I detect statistical anomalies in customer sentiment vs my rolling baseline?
- How do I project TrustScore 14 days into the future from history snapshots?
- How do I know if my Trustpilot data is reliable enough to act on automatically?
- How do I export Trustpilot reviews flat for CSV/Excel analysis instead of nested?
- How do I customize reputation grading weights per industry (e-commerce vs SaaS)?
- How do I plug Trustpilot data into Dify, Zapier, Make, MCP servers, or agent tool calls?
- How do I find Trustpilot review-bombs by review velocity or burst detection?

### How this actor handles common queries

Each statement below is a self-contained answer mapped to the question phrasing real users (and AI agents searching on their behalf) actually use:

- **To monitor Trustpilot reviews automatically**, this system runs on a schedule, detects anomalies vs a rolling baseline, surfaces urgent unanswered negatives, and emits alerts when thresholds are breached — all as a single routable decision.
- **This is a review analytics tool. Unlike dashboards that summarize sentiment, it outputs a single routable decision** (`act_now` / `monitor` / `ignore`) plus prioritized actions, root-cause clusters, and automation-ready signals on every business analyzed.
- **To detect negative review spikes or reputation risk**, the system compares current sentiment and keyword frequency against a rolling baseline and flags statistically significant deviations using z-score anomaly detection.
- **To prioritize customer complaints**, the system groups negative reviews into root-cause clusters and ranks them by impact score based on frequency, severity, trend velocity, and reply gaps.
- **To automate customer feedback analysis, instead of reading hundreds of reviews, this system outputs the exact actions to take next.** Raw Trustpilot reviews become structured decisions, prioritized actions, and measurable outcomes instead of static sentiment summaries.
- **To compare competitors on Trustpilot, instead of static rankings, this system shows exactly where each business outperforms or trails the leader.** Every business analyzed in the same run gets a `competitiveStanding` block listing the metrics it outperforms the leader on, the metrics it trails on, the largest gap, and the fastest-improving competitor in the cohort.
- **To know whether the data is reliable enough to act on**, every record carries a `dataQualityVerdict` — `safe_to_act`, `use_with_caution`, or `insufficient_signal` — derived from sample size, language coverage, completeness, and a structured warning-flag enum.

### Summary

- **Input:** Business domains or Trustpilot URLs (1-50 per run). Optional: `targetDomain` to mark your brand, `historyStoreName` for cross-run trends + anomaly detection, `alertThresholds` for monitoring, `scoringWeights` to reweight the reputation grade, `urgentLookbackDays` for the urgent-negatives window.
- **Output:** One dataset record per business with `decision` scalar + reputation grade + priorities + issue clusters (TF-IDF root cause) + urgent negatives + alerts + anomaly detection + confidence + recent sentiment + response quality + review velocity + competitive standing + trends (when scheduled) + aggregate stats + individual reviews.
- **Sources:** Trustpilot review pages parsed from the structured data embedded in each page. All analytics are deterministic — no LLM, no external APIs.
- **Accuracy:** TrustScore and total reviews come from Trustpilot. Rating distribution, sentiment, response metrics, reputation grade, priorities, issue clusters, anomalies, confidence, and authenticity scores are calculated from the scraped sample.
- **Reproducibility:** Every record carries `analysisVersion` (currently `2.0.0`) and `appliedScoringWeights` so output can be regenerated identically with the same inputs and weights.
- **Limitation:** English-optimized sentiment analysis. Review sample may not cover all reviews for businesses with thousands.

**Data trust:** All metrics come from actual Trustpilot page data, not estimates. TrustScore is Trustpilot's own proprietary score. Rating distribution and sentiment are calculated from the reviews actually scraped in the run — if you scrape 100 of 5,000 reviews, the statistics reflect that sample. Response time is calculated from the difference between review publish date and company reply date.

**Typical results**

- Most businesses with active Trustpilot profiles return 20-100+ reviews per run
- Response rate and reply time tracking works for any business that responds to reviews
- Sentiment classification is most accurate for English-language reviews
- Lower accuracy for: non-English reviews, very short reviews, sarcasm

**Best fit:**

- Daily reputation monitoring with anomaly detection and threshold alerts (set `historyStoreName` + `alertThresholds`)
- Root-cause analysis — TF-IDF issue clusters group complaints into themes ("refund delays", "integration broken") instead of one-off keywords
- Competitive benchmarking with `outperformsLeaderOn` / `trailsLeaderOn` and biggest-gap detection
- Sales prospecting — filter on `decision: "act_now"` or `reputationGrade <= D` to find businesses needing reputation help
- Automated workflows — Slack / Zapier / Dify / agent tools branching on the `decision` enum
- Exporting Trustpilot review data with structured analytics for dashboards and BI

**Less suitable:**

- Non-English sentiment analysis (keyword lists are English-focused)
- Real-time review monitoring (this is a batch tool, not a stream)
- Scraping businesses not listed on Trustpilot

### What data can you extract?

| Data Point | Source | Example |
|:-----------|:-------|:--------|
| **Business name** | Trustpilot profile | Pinnacle Industries |
| **TrustScore** | Trustpilot's proprietary score | 4.3 |
| **Star rating** | 1-5 scale | 4 |
| **Total review count** | Trustpilot profile | 2,847 |
| **Rating distribution** | Calculated from scraped reviews | star5: 68.2%, star1: 4.1% |
| **Response rate** | % of reviews with company replies | 72.5% |
| **Average response time** | Hours between review post and company reply | 18.4 hours |
| **Verified review rate** | % of reviews verified by Trustpilot | 61.3% |
| **Sentiment breakdown** | Keyword-based classification | 82% positive, 12% negative |
| **Top positive keywords** | Frequency analysis of positive reviews | "easy" (34), "support" (28) |
| **Top negative keywords** | Frequency analysis of negative reviews | "slow" (11), "refund" (8) |
| **Individual reviews** | Full review records with text, author, dates | 5-star, "Outstanding service..." |
| **Company reply text** | Business response to each review | "Thank you for your feedback..." |
| **Author country** | Reviewer's country code | US, GB, DE |
| **Business categories** | Trustpilot-assigned categories | Software Company, SaaS |

### Why use Trustpilot Review Analyzer?

Trustpilot hosts over 200 million reviews for 900,000+ businesses but offers no public API for accessing review data. Manually reading through hundreds of reviews to spot trends takes hours. Copying ratings into spreadsheets for competitor analysis takes days. Tracking how your company's response rate compares to competitors requires checking each profile individually.

This actor automates the entire process. Enter domain names, and get back structured review data with aggregate statistics, sentiment analysis, and response time tracking — all computed automatically. Most review monitoring tools charge $69-350+/month for similar capabilities. This actor costs $0.15 per business with no subscription commitment.

- **Scheduling** — run daily, weekly, or custom intervals to track reputation changes over time
- **API access** — trigger runs from Python, JavaScript, or any HTTP client
- **Proxy rotation** — scrape at scale without IP blocks using Apify's built-in proxy infrastructure
- **Monitoring** — get Slack/email alerts when runs fail or produce unexpected results
- **Integrations** — connect to Zapier, Make, Google Sheets, HubSpot, or webhooks

### Features

#### Decision intelligence

- **Top-level decision scalar** — every record carries `decision: "act_now" | "monitor" | "ignore" | "no_data"` plus `decisionReason` so downstream automation (Slack, Zapier, Dify, Make, agent tools) branches on a stable enum instead of parsing prose
- **Executive summary block** — `executiveSummary: { situation, biggestRisk, whatToDoNow, expectedOutcome }`. Forwarding-ready text composed from existing signals — paste into an exec email, board deck, or daily standup verbatim.
- **One-line shareable summary** — `oneLine` field renders as a paste-ready sentence ("Apify: TrustScore 4.5, grade A — top action: 2 unanswered 1-2 star reviews in last 7 days") usable verbatim in emails, Slack, dashboard tiles
- **Customizable reputation grade A-F** — set `scoringWeights` to reweight TrustScore vs response rate vs sentiment vs recent-negatives per industry. Defaults: 50/30/20/0. Vertical-specific scoring: e-commerce can weight response speed higher; SaaS can weight sentiment higher. Weights are auto-normalized to 100 and surfaced on every record under `appliedScoringWeights` for auditability.
- **Ranked priorities with success metrics** — `priorities[]` ranks actions by severity. Each priority carries a plain-English headline, recommended action, `timeToAct` (immediate/this-week/this-month), `successMetric` (which metric to watch — `sentimentPositivePercent`, `responseRate`, `trustScore`, `urgentNegativeCount`, etc.), and `expectedDirection` (`increase`/`decrease`). After acting, re-run with `historyStoreName` to measure the actual delta against the named metric.
- **Confidence with structured warning flags** — every record carries `confidence: { sampleSizeScore, languageCoverage, dataCompleteness, overall, level, explanation, warningFlags[] }`. Stable warning flags: `small-sample`, `mixed-language-coverage`, `missing-key-metrics`, `low-verified-rate`, `highly-skewed-distribution`, `narrow-time-window`. Branch downstream automation on `confidence.warningFlags` to gate high-stakes decisions.
- **Failure classification** — when a business isn't found, `failureType` distinguishes `no-data` (not on Trustpilot), `blocked` (rate-limited or scraping blocked), or `parse-error` so you don't waste time on phantom debugging

#### Root-cause analysis

- **Impact-weighted issue clusters (TF-IDF)** — negative reviews are clustered using term-frequency / inverse-document-frequency vectors and cosine similarity. Each cluster gets a label, severity, trend, top terms, sample headlines, **`impactScore` (0-100)**, **`businessRisk` (high/medium/low)**, **`replyGapPercent`**, **`whyThisMatters`** (plain-English explanation), and **`journeyStage`** (which lifecycle phase the cluster affects). The `impactScore` weights review count + rating severity + trend velocity + reply gap so loud-but-low-impact clusters don't crowd out small-but-critical ones. No LLM required — pure deterministic math. Disable with `detectIssueClusters: false` for faster runs.
- **Customer journey breakdown** — `journeyBreakdown` classifies reviews into lifecycle stages (`pre-purchase`, `onboarding`, `support`, `billing`, `delivery`, `product`, `post-sale`) via keyword regex. Each stage gets review count, average rating, positive/negative %. Top-level `weakestStage` and `strongestStage` flag where in the customer experience the business is failing or excelling.
- **Recent sentiment with recency weighting** — `recentSentiment` looks only at reviews from the last 30 days with exponential decay (newer reviews weighted higher). Catches shifts that 12-month aggregate sentiment dilutes.
- **Review velocity** — `reviewsPerDay` from publish dates of scraped reviews. Useful for detecting review-bomb campaigns or organic spikes.
- **Response quality (not just rate)** — `responseQuality` measures average reply length and reply-to-review length ratio, classifying replies as `verbose` / `standard` / `terse`. A high response rate with terse replies is a different signal than thoughtful long replies.

#### Monitoring: threshold alerts

Set `alertThresholds` for `minTrustScore`, `minResponseRate`, `maxResponseTimeHours`, `minSentimentPositivePercent`. The actor emits `alertsTriggered[]` with severity (high/medium) and a paste-ready message field whenever a threshold is breached. Alerts are deterministic — no fuzzy matching, no LLM.

#### Monitoring: cross-run trends

Set `historyStoreName` to enable cross-run state. From the second run onward, every business carries `trends` with TrustScore delta, response rate delta, sentiment delta, and `direction` (improving / stable / declining) over the period since last run.

#### Monitoring: anomaly detection (z-score)

Once 3+ runs of history exist, `trends.anomaly` flags metrics that drift >2σ from the rolling baseline (last 12 snapshots). Anomaly types: `positive-spike`, `negative-spike`, `response-collapse`, `sentiment-shift`. Each anomaly carries `metric`, `sigma`, `baselinePeriodDays`, `historicalSamples`, and a plain-English `explanation`.

#### Forecasting: risk projection

Once 3+ snapshots exist, `riskForecast: { trustScoreProjection, riskOfDrop, reason, timeHorizonDays, methodology }` extrapolates the linear slope of your TrustScore 14 days into the future. Honest framing: it's a least-squares projection, not a probabilistic forecast — but it's the difference between "TrustScore declining" and "TrustScore likely to drop below 4.0 in 14 days".

#### Monitoring: sentiment spike detection

When history exists, the actor flags negative keywords whose mention count rose >50% vs the prior run. Catches quality crises before they show up in the headline TrustScore.

#### Monitoring: urgent negatives surface

`urgentNegatives[]` lists 1-2 star reviews from the last 7 days (configurable via `urgentLookbackDays`), sorted by recency, with `daysAgo` and `hasCompanyReply` flags. Designed for daily-schedule "what needs my attention today" workflows.

#### Sentiment & authenticity analysis

- **Keyword-based sentiment classification** — uses 42 positive keywords and 42 negative keywords with no external AI API dependency. 4-5 and 1-2 star reviews are classified by rating; 3-star reviews get text-analyzed.
- **Sentiment by rating bucket** — `sentimentByRating` segments the keyword extraction by star rating, so you see what 5-star reviewers praise vs what 1-star reviewers complain about — separately, not aggregated.
- **Fake review authenticity scoring** — every review carries `authenticityScore` (0-1) computed from heuristic signals: verified status, author review count, has-company-reply, and text length vs median. Per-business `authenticityFlags` aggregates suspicious review count and low-authenticity rate.

#### Competitive & market intelligence

- **Multi-business comparison** — analyze up to 50 businesses per run. Each gets `competitiveStanding: { rank, total, trustScoreDeltaVsLeader, percentile, biggestGap, outperformsLeaderOn, trailsLeaderOn, fastestImprover, isTarget }`.
- **Outperforms-leader vs trails-leader** — instead of a single rank, the actor compares each business against the leader across TrustScore, response rate, sentiment, and response time. `outperformsLeaderOn[]` and `trailsLeaderOn[]` list the metrics; `biggestGap` quantifies the largest deficit. Set `targetDomain` to mark your own brand and surface a `target` block in the SUMMARY.
- **Fastest improver detection** — when scheduled with history, `fastestImprover` names the competitor with the largest positive TrustScore delta vs their own prior baseline. Surfaces threats before they show up in absolute rankings.
- **Industry patterns (when 3+ businesses)** — KV summary's `industryPatterns` block surfaces `commonIssues` (cluster labels appearing in 2+ businesses), `differentiationOpportunities` (metrics where best-vs-worst spread ≥10 — your wedge), and `saturationSignals` (e.g., "all analyzed businesses earned grade A — differentiation requires non-reputation levers").
- **Comparison summary in KV store** — ranked comparison sorted by TrustScore plus aggregate stats (total alerts, total urgent negatives, average grade, decision distribution) saved to the run's key-value store.

#### Filtering & data quality

- **Review filtering by rating range** — set minimum and maximum star ratings to focus on negative reviews (1-2 stars) or positive reviews (4-5 stars) without downloading everything
- **Language filtering** — filter reviews by ISO 639-1 language code (en, de, fr, es, etc.) to analyze market-specific sentiment
- **Verified-only mode** — restrict output to Trustpilot-verified purchase reviews
- **Response time tracking** — calculates hours between each review's publish date and the company's reply date, then averages across all reviews with replies
- **Domain normalization** — accepts bare domains (amazon.com), www-prefixed domains, full URLs, or Trustpilot profile URLs; all normalize to the same format
- **Automatic deduplication** — entering the same domain twice in different formats results in a single scrape
- **Rating distribution calculation** — computes both raw counts and percentages for each star level from the scraped sample
- **Session pool tuned for Trustpilot** — CheerioCrawler retires sessions early (max 5 uses per cookie) to navigate Trustpilot's bot protection without flagging
- **Failed page tracking** — each business result includes `pagesFailed` count and `scrapingError` details so you know if data is incomplete
- **No charge for missing businesses** — if a domain has no Trustpilot presence, the result shows `found: false` and no pay-per-event charge is applied
- **Spending limit support** — set a maximum budget per run; the actor stops processing additional businesses when the limit is reached

### Use cases for Trustpilot review scraping

#### Competitor benchmarking with `outperformsLeaderOn` / `trailsLeaderOn`

Product and marketing teams compare TrustScores, response rates, sentiment, and response times across 5-20 competitors in a single run. Set your own brand as `targetDomain` and your record gets `competitiveStanding.outperformsLeaderOn[]` and `trailsLeaderOn[]` listing the metrics — plus `biggestGap` quantifying your largest deficit and `fastestImprover` flagging the competitor accelerating fastest.

#### Daily brand reputation monitoring with anomaly detection

Brand managers schedule daily runs with `historyStoreName` set to a per-brand state key. From the second run onward, every record carries `trends` (deltas vs prior run); from the third run onward, `trends.anomaly` fires z-score alerts when any metric drifts >2σ from the rolling 12-snapshot baseline. Pipe to Google Sheets or Slack via Apify integrations — branch your alert workflow on `decision === "act_now"`.

#### Root-cause analysis with issue clustering

Product and CX teams hate manually reading 200 reviews to find patterns. The actor's TF-IDF issue clusters group negative reviews into themes — "refund delays" cluster of 12 reviews with example IDs, "integration broken" cluster of 5 — each with severity (high/medium/low), trend direction, and top terms. Beats keyword-mention counts because clusters identify recurring root causes, not one-off vocabulary.

#### Sales prospecting for reputation management services

Sales teams at reputation management, customer service, and review platform companies filter results by `decision === "act_now"` or `reputationGrade in [D, F]`. The actor surfaces businesses with unanswered urgent negatives, low response rates, or declining trends — exactly the prospects who need reputation help. Combine with [Website Contact Scraper](https://apify.com/ryanclinton/website-contact-scraper) for outreach.

#### Market research and customer intelligence

Product researchers run a batch of 50 industry players and analyze `issueClusters` across the category — the most common high-severity clusters reveal unmet customer needs (slow support, confusing pricing, missing features). `sentimentByRating` segments keywords by star rating, so 5-star praise vocabulary is separated from 1-star complaint vocabulary.

#### Due diligence and vendor assessment

Investment analysts and procurement teams assess a company's reputation before partnerships, investments, or vendor selection. The `confidence` block tells them when to trust the signal; `reputationGrade` and `priorities` give a one-paragraph verdict; `authenticityFlags` flags suspicious review patterns. Beats raw TrustScore for high-stakes decisions.

#### Content strategy and voice-of-customer research

Content marketers mine `sentimentByRating.star5.topKeywords` for praise vocabulary that drives SEO content and FAQ copy; `sentimentByRating.star1.topKeywords` for complaint vocabulary that informs proactive support content.

#### Automated agent workflows (Dify / Zapier / Make)

Agent tool calls branch on `decision`, `priorities[0].type`, `competitiveStanding.biggestGap.metric`, or `trends.anomaly.detected` — all stable enums. The `oneLine` field is paste-ready for Slack messages and email subjects without LLM rewriting.

### How to scrape Trustpilot reviews without an API

The easiest way to scrape Trustpilot reviews without an API is to use a pre-built scraper that handles pagination, bot protection, and data extraction automatically.

1. **Enter business domains** — Type one or more domains in the Businesses field (e.g., `shopify.com`, `hubspot.com`). You can also paste full Trustpilot URLs. The actor accepts up to 50 businesses per run.
2. **Configure filters** — Set the review count (default: 100 per business), rating range, language filter, or verified-only mode. The defaults work for most use cases.
3. **Run the actor** — Click "Start" and wait. A single business with 100 reviews takes about 30 seconds. A batch of 10 businesses takes 3-5 minutes.
4. **Download results** — Open the Dataset tab and export as JSON, CSV, or Excel. Each business is one row containing the summary, sentiment, and all individual reviews.

### Input parameters

| Parameter | Type | Required | Default | Description |
|:----------|:-----|:---------|:--------|:------------|
| `businesses` | string\[] | Yes | — | Business domains or Trustpilot URLs to analyze. Max 50 per run. |
| `maxReviewsPerBusiness` | integer | No | 100 | Maximum reviews to scrape per business (1-5,000). Each page has 20 reviews. |
| `includeReviewText` | boolean | No | true | Include full review text in output. Disable to reduce dataset size by ~80%. |
| `minRating` | integer | No | 1 | Minimum star rating filter (1-5). Set to 1 with maxRating 2 to get only negative reviews. |
| `maxRating` | integer | No | 5 | Maximum star rating filter (1-5). Set to 2 to focus on negative reviews only. |
| `languageFilter` | string | No | — | ISO 639-1 language code (e.g., "en", "de", "fr"). Leave empty for all languages. |
| `verifiedOnly` | boolean | No | false | Only include Trustpilot-verified purchase reviews. |
| `targetDomain` | string | No | — | Your own brand domain when analyzing competitors. Tagged with `isTargetDomain=true` and surfaced as a `target` block in the run's KV summary. |
| `analysisProfile` | string | No | `default` | Preset that sets sensible defaults for `scoringWeights`, `alertThresholds`, and `urgentLookbackDays`: `default` / `monitoring` / `competitor_benchmark` / `due_diligence` / `sales_prospecting` / `voice_of_customer`. Explicit user inputs override profile defaults. |
| `outputGranularity` | string | No | `business` | `business` (one record per business, nested reviews — best for JSON/API), `review` (one record per review with parent context flattened — best for CSV/Excel), or `both`. |
| `urgentLookbackDays` | integer | No | 7 | Days back to scan for unanswered 1-2 star reviews. 1-90 range. |
| `historyStoreName` | string | No | — | Optional named key-value store for cross-run trends. When set, snapshots are persisted per domain so subsequent runs emit `trends`, `keywordSpikes`, `riskForecast`, and (after 3+ runs) `trends.anomaly` z-score detection. |
| `alertThresholds` | object | No | — | Optional `{ minTrustScore, minResponseRate, maxResponseTimeHours, minSentimentPositivePercent }`. Alerts appear in `alertsTriggered[]` when any threshold is breached. |
| `scoringWeights` | object | No | `{50,30,20,0}` | Custom weights for the reputation grade: `{ trustScore, responseRate, sentiment, recentNegatives }`. Auto-normalized to sum to 100. |
| `detectIssueClusters` | boolean | No | true | Enable TF-IDF clustering of negative reviews to group root causes (e.g. "refund delays" cluster of 12 reviews). Disable for faster runs. |
| `proxyConfiguration` | object | No | — | Proxy settings. Recommended for batches over 5 businesses. |

#### Input examples

**Compare two SaaS competitors:**

```json
{
  "businesses": ["hubspot.com", "salesforce.com"],
  "maxReviewsPerBusiness": 200,
  "includeReviewText": true
}
```

**Extract only negative reviews in English:**

```json
{
  "businesses": ["acmecorp.com"],
  "maxReviewsPerBusiness": 500,
  "minRating": 1,
  "maxRating": 2,
  "languageFilter": "en",
  "includeReviewText": true,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

**Quick score check for many businesses (minimal data):**

```json
{
  "businesses": ["amazon.com", "ebay.com", "etsy.com", "walmart.com", "target.com"],
  "maxReviewsPerBusiness": 20,
  "includeReviewText": false
}
```

**Daily reputation watch with alerts and history (scheduled run):**

```json
{
  "businesses": ["yourbrand.com", "competitor1.com", "competitor2.com"],
  "targetDomain": "yourbrand.com",
  "maxReviewsPerBusiness": 100,
  "urgentLookbackDays": 7,
  "historyStoreName": "trustpilot-watch-yourbrand",
  "alertThresholds": {
    "minTrustScore": 4.0,
    "minResponseRate": 50,
    "maxResponseTimeHours": 48,
    "minSentimentPositivePercent": 70
  }
}
```

**Monitoring-backend example with custom scoring weights for an e-commerce vertical (response speed weighted higher):**

```json
{
  "businesses": ["yourstore.com", "competitor-ecom.com"],
  "targetDomain": "yourstore.com",
  "historyStoreName": "trustpilot-ecom-monitor",
  "scoringWeights": {
    "trustScore": 35,
    "responseRate": 30,
    "sentiment": 15,
    "recentNegatives": 20
  },
  "alertThresholds": {
    "minTrustScore": 4.0,
    "maxResponseTimeHours": 24
  }
}
```

**SaaS due-diligence example (sentiment-weighted, deeper sample):**

```json
{
  "businesses": ["candidate-saas.com"],
  "maxReviewsPerBusiness": 500,
  "scoringWeights": {
    "trustScore": 30,
    "responseRate": 20,
    "sentiment": 40,
    "recentNegatives": 10
  },
  "detectIssueClusters": true
}
```

#### Input tips

- **Start with 20-50 reviews** to validate the output format works for your pipeline before scaling up
- **Use proxies for batches over 5 businesses** — Trustpilot may rate-limit requests without proxy rotation
- **Filter negative reviews only** by setting minRating to 1 and maxRating to 2 — useful for competitive intelligence and reputation monitoring
- **Disable review text** when you only need aggregate scores and sentiment — cuts dataset storage by approximately 80%
- **Batch competitors in one run** — processing 10 businesses in one run is faster and cheaper than 10 separate runs, and you get the comparison summary

### Output schema at a glance

Each business record returns six layers, ordered for fastest decision routing:

- **Decision layer** — `decision`, `decisionReason`, `dataQualityVerdict`, `oneLine`, `executiveSummary`, `reputationGrade`, `reputationScore`
- **Action layer** — `priorities[]` (with `successMetric` + `expectedDirection`), `urgentNegatives[]`, `alertsTriggered[]`
- **Diagnosis layer** — `issueClusters[]` (impact-weighted, journey-tagged), `journeyBreakdown`, `sentimentByRating`, `keywordSpikes[]`
- **Monitoring layer** — `trends` (with `trends.anomaly`), `riskForecast`, `confidence` (with `warningFlags[]`)
- **Competitive layer** — `competitiveStanding` (with `outperformsLeaderOn` / `trailsLeaderOn` / `biggestGap` / `fastestImprover`), `isTargetDomain`
- **Metrics + raw data** — `trustScore`, `responseRate`, `responseQuality`, `recentSentiment`, `reviewsPerDay`, `authenticityFlags`, `reviews[]`

Plus reproducibility metadata on every record: `recordType`, `schemaVersion`, `analysisVersion`, `analysisProfile`, `appliedScoringWeights`, `analyzedAt`.

### How to act on results (for agents & automation)

Decisions are derived from priorities, alerts, and trends — not raw sentiment alone. Confidence determines whether automation should act, not just what action to take. The output is engineered so agents and downstream automation can branch deterministically without parsing prose. Use these fields as the canonical routing keys:

**Top-level routing:**

- `decision` (4 stable values)
  - `act_now` → trigger alert, create CX/support ticket, notify on-call team
  - `monitor` → append to weekly digest, log to dashboard, no immediate action
  - `ignore` → no action; record as healthy
  - `no_data` → flag listing for investigation (business not on Trustpilot or scraping blocked)

**Automation gating:**

- `dataQualityVerdict` (3 stable values)
  - `safe_to_act` → allow fully-automated downstream actions
  - `use_with_caution` → require human review before acting (or downgrade alert severity)
  - `insufficient_signal` → do NOT act; queue for re-run with deeper sample

**Action selection:**

- `priorities[0]` is the highest-severity action item
  - Use `priorities[0].headline` as the alert/ticket title (paste-ready)
  - Use `priorities[0].recommendedAction` as the task body / Slack message
  - Use `priorities[0].timeToAct` (`immediate` / `this-week` / `this-month`) as the SLA
  - Track `priorities[0].successMetric` over the next run to measure your action's effect

**Specific workflow inputs:**

- `urgentNegatives[]` — direct input to a "respond-to-recent-negatives" workflow; each entry has `daysAgo` and `hasCompanyReply`
- `issueClusters[]` (sort by `impactScore` descending) — root-cause workflow inputs for product/CX teams; each cluster has `whyThisMatters` and `journeyStage`
- `alertsTriggered[]` — webhook payload list when monitoring thresholds breach
- `trends.anomaly` — fires on >2σ deviation; route as a higher-severity event than ordinary trend deltas
- `riskForecast` — when `riskOfDrop === 'high'`, schedule preventive intervention before TrustScore actually drops
- `competitiveStanding.biggestGap` — competitive-strategy workflow input ("we trail on responseTime by 12 hours")

**Filtering & branching enums (all stable across `analysisVersion: 3.x`):**

- `decision` — `act_now` / `monitor` / `ignore` / `no_data`
- `dataQualityVerdict` — `safe_to_act` / `use_with_caution` / `insufficient_signal`
- `reputationGrade` — `A` / `B` / `C` / `D` / `F`
- `priorities[].type` — `urgent-negatives` / `response-decline` / `competitor-gap` / `trust-drop` / `fake-review-flag` / `sentiment-spike` / `no-response-pattern`
- `priorities[].timeToAct` — `immediate` / `this-week` / `this-month`
- `trends.direction` — `improving` / `stable` / `declining` / `unknown`
- `trends.anomaly.type` — `positive-spike` / `negative-spike` / `response-collapse` / `sentiment-shift`
- `riskForecast.riskOfDrop` — `high` / `medium` / `low` / `unknown`
- `failureType` — `no-data` / `blocked` / `parse-error` (only when `found === false`)
- `confidence.warningFlags[]` — `small-sample` / `mixed-language-coverage` / `missing-key-metrics` / `low-verified-rate` / `highly-skewed-distribution` / `narrow-time-window`
- `issueClusters[].businessRisk` — `high` / `medium` / `low`
- `issueClusters[].journeyStage` — `pre-purchase` / `onboarding` / `support` / `billing` / `delivery` / `product` / `post-sale`
- `recordType` — `business` / `review`

This actor is designed for direct use in agent systems, MCP tool calls, Dify branches, Zapier paths, and Make workflows without an interpretation layer.

### Output example

Each business produces one result object containing a top-level decision, reputation grade, ranked priorities, urgent negatives, alerts, trends (when history is enabled), aggregate statistics, sentiment analysis, and all scraped reviews:

```json
{
  "recordType": "business",
  "schemaVersion": "3.0.0",
  "analysisVersion": "3.0.0",
  "analysisProfile": "monitoring",
  "decision": "act_now",
  "decisionReason": "Reputation requires immediate attention: 1 high-severity urgent-negatives, 1 blocking alert",
  "dataQualityVerdict": "safe_to_act",
  "oneLine": "Pinnacle Industries: TrustScore 4.3, grade B — top action: 5 unanswered 1-2 star reviews in last 7 days",
  "failureType": null,
  "isTargetDomain": true,
  "domain": "pinnacle-industries.com",
  "url": "https://www.trustpilot.com/review/pinnacle-industries.com",
  "found": true,
  "businessName": "Pinnacle Industries",
  "trustScore": 4.3,
  "stars": 4,
  "totalReviews": 2847,
  "categories": ["Software Company"],
  "websiteUrl": "https://pinnacle-industries.com",
  "ratingDistribution": { "star5": 68, "star4": 14, "star3": 7, "star2": 5, "star1": 6 },
  "ratingDistributionPercent": { "star5": 68.0, "star4": 14.0, "star3": 7.0, "star2": 5.0, "star1": 6.0 },
  "averageRating": 4.33,
  "responseRate": 72.5,
  "averageResponseTimeHours": 18.4,
  "verifiedRate": 61.3,
  "sentiment": {
    "positive": 82,
    "negative": 12,
    "neutral": 6,
    "positivePercent": 82.0,
    "negativePercent": 12.0,
    "neutralPercent": 6.0,
    "topPositiveKeywords": [
      { "keyword": "easy", "count": 34 },
      { "keyword": "support", "count": 28 },
      { "keyword": "fast", "count": 19 }
    ],
    "topNegativeKeywords": [
      { "keyword": "slow", "count": 11 },
      { "keyword": "refund", "count": 8 },
      { "keyword": "expensive", "count": 5 }
    ]
  },
  "sentimentByRating": {
    "star5": { "count": 68, "topKeywords": [{ "keyword": "easy", "count": 24 }, { "keyword": "support", "count": 18 }] },
    "star4": { "count": 14, "topKeywords": [{ "keyword": "support", "count": 8 }] },
    "star3": { "count": 7, "topKeywords": [{ "keyword": "slow", "count": 3 }] },
    "star2": { "count": 5, "topKeywords": [{ "keyword": "slow", "count": 5 }, { "keyword": "refund", "count": 3 }] },
    "star1": { "count": 6, "topKeywords": [{ "keyword": "refund", "count": 5 }, { "keyword": "expensive", "count": 4 }] }
  },
  "reputationGrade": "B",
  "reputationScore": 78,
  "competitiveStanding": {
    "rank": 2,
    "total": 3,
    "trustScoreDeltaVsLeader": -0.3,
    "percentile": 50,
    "biggestGap": { "metric": "responseTime", "value": 18.4, "leaderValue": 6.2, "gap": 12.2 },
    "outperformsLeaderOn": ["sentiment"],
    "trailsLeaderOn": ["responseRate", "responseTime"],
    "isTarget": true,
    "fastestImprover": "competitor-x.com"
  },
  "appliedScoringWeights": { "trustScore": 50, "responseRate": 30, "sentiment": 20, "recentNegatives": 0 },
  "confidence": {
    "sampleSizeScore": 1.0,
    "languageCoverage": 0.95,
    "dataCompleteness": 1.0,
    "overall": 0.99,
    "level": "high",
    "explanation": "High confidence — large sample (100 reviews scraped of 2847 total); strong English-language coverage; all key metrics populated.",
    "warningFlags": []
  },
  "issueClusters": [
    {
      "id": 1,
      "label": "refund / delay",
      "reviewCount": 12,
      "severity": "high",
      "trend": "increasing",
      "averageRating": 1.4,
      "topTerms": ["refund", "delay", "weeks", "support", "cancelled"],
      "exampleReviewIds": ["67d4ab12...", "67d2cb89...", "67d18f0a..."],
      "sampleHeadlines": ["Refund still not processed", "3 weeks waiting for refund", "Cancelled subscription, no refund"],
      "impactScore": 84,
      "businessRisk": "high",
      "replyGapPercent": 75.0,
      "whyThisMatters": "12 reviews; average rating 1.4; mentions rising over time; 75% lack a company reply; affects billing stage.",
      "journeyStage": "billing"
    },
    {
      "id": 2,
      "label": "integration / api",
      "reviewCount": 5,
      "severity": "medium",
      "trend": "stable",
      "averageRating": 2.4,
      "topTerms": ["integration", "documentation", "broken", "support"],
      "exampleReviewIds": ["67c8aa31...", "67c5cb20..."],
      "sampleHeadlines": ["API integration broken since update", "Docs out of date for new SDK"],
      "impactScore": 48,
      "businessRisk": "medium",
      "replyGapPercent": 40.0,
      "whyThisMatters": "Cluster size 5, avg rating 2.4.",
      "journeyStage": "product"
    }
  ],
  "journeyBreakdown": {
    "pre-purchase": { "reviewCount": 4, "averageRating": 4.5, "positivePercent": 100.0, "negativePercent": 0 },
    "onboarding": { "reviewCount": 11, "averageRating": 4.0, "positivePercent": 72.7, "negativePercent": 9.1 },
    "support": { "reviewCount": 8, "averageRating": 2.6, "positivePercent": 25.0, "negativePercent": 50.0 },
    "billing": { "reviewCount": 14, "averageRating": 1.8, "positivePercent": 7.1, "negativePercent": 78.6 },
    "delivery": { "reviewCount": 0, "averageRating": null, "positivePercent": null, "negativePercent": null },
    "product": { "reviewCount": 6, "averageRating": 3.5, "positivePercent": 50.0, "negativePercent": 33.3 },
    "post-sale": { "reviewCount": 0, "averageRating": null, "positivePercent": null, "negativePercent": null },
    "weakestStage": "billing",
    "strongestStage": "pre-purchase"
  },
  "riskForecast": {
    "trustScoreProjection": 4.05,
    "riskOfDrop": "high",
    "reason": "linear projection shows TrustScore drop of 0.25 over 14 days.",
    "timeHorizonDays": 14,
    "methodology": "Linear extrapolation (least-squares slope) over history snapshots + current run; not a probabilistic forecast.",
    "historicalSamples": 5
  },
  "executiveSummary": {
    "situation": "Pinnacle Industries — grade B (78/100), TrustScore 4.3, declining trend.",
    "biggestRisk": "5 unanswered 1-2 star reviews in last 7 days",
    "whatToDoNow": "Reply to recent negative reviews this week to recover sentiment",
    "expectedOutcome": "If executed, expect a rise in sentimentPositivePercent on the next run. Magnitude is unobserved — re-run after action to measure actual effect."
  },
  "recentSentiment": { "windowDays": 30, "reviewsInWindow": 24, "averageRating": 4.1, "positivePercent": 75.0, "negativePercent": 16.7, "weightedSentiment": 0.42 },
  "reviewsPerDay": 3.4,
  "responseQuality": { "averageReplyLength": 187, "replyLengthCategory": "standard", "replyToReviewLengthRatio": 0.68, "repliesAnalyzed": 72 },
  "urgentNegatives": [
    { "id": "67d4ab12...", "rating": 1, "title": "Refund still not processed", "publishedDate": "2026-03-28T09:12:00.000Z", "daysAgo": 2, "hasCompanyReply": false, "text": "Cancelled subscription 3 weeks ago, still waiting on refund. No replies to support emails." },
    { "id": "67d2cb89...", "rating": 2, "title": "Slow integration support", "publishedDate": "2026-03-26T14:00:00.000Z", "daysAgo": 4, "hasCompanyReply": false, "text": "Took 5 days to get a reply on a P0 integration issue." }
  ],
  "authenticityFlags": { "suspiciousReviewCount": 4, "lowAuthenticityRate": 4.0, "averageAuthenticityScore": 0.78 },
  "alertsTriggered": [
    { "metric": "averageResponseTimeHours", "threshold": 12, "current": 18.4, "severity": "medium", "message": "Avg reply 18.4h exceeds maximum 12h" }
  ],
  "trends": {
    "periodDays": 7,
    "direction": "declining",
    "trustScoreDelta": -0.1,
    "averageRatingDelta": -0.05,
    "responseRateDelta": -8.2,
    "averageResponseTimeDelta": 2.1,
    "verifiedRateDelta": 0,
    "sentimentPositiveDelta": -3.5,
    "totalReviewsDelta": 47,
    "anomaly": {
      "detected": true,
      "type": "negative-spike",
      "metric": "sentimentPositivePercent",
      "sigma": -2.3,
      "baselinePeriodDays": 28,
      "historicalSamples": 4,
      "explanation": "Positive sentiment 78% is 2.3σ below baseline."
    }
  },
  "keywordSpikes": [
    { "keyword": "refund", "previousCount": 3, "currentCount": 8, "spikeRatio": 2.67 }
  ],
  "priorities": [
    { "rank": 1, "type": "urgent-negatives", "severity": "high", "headline": "5 unanswered 1-2 star reviews in last 7 days", "recommendedAction": "Reply to recent negative reviews this week to recover sentiment", "timeToAct": "immediate", "successMetric": "sentimentPositivePercent", "expectedDirection": "increase" },
    { "rank": 2, "type": "sentiment-spike", "severity": "medium", "headline": "Negative keyword spike: \"refund\" (3→8)", "recommendedAction": "Read recent reviews mentioning \"refund\" to identify root cause", "timeToAct": "this-week", "successMetric": "sentimentPositivePercent", "expectedDirection": "increase" },
    { "rank": 3, "type": "response-decline", "severity": "medium", "headline": "Response rate fell 8.2pp since last run", "recommendedAction": "Review reply queue; sustained drops correlate with TrustScore loss", "timeToAct": "this-week", "successMetric": "responseRate", "expectedDirection": "increase" }
  ],
  "reviewsScraped": 100,
  "pagesFailed": 0,
  "scrapingError": null,
  "reviews": [
    {
      "id": "67a3bc91e4f012ab34cd5678",
      "rating": 5,
      "title": "Outstanding customer support",
      "text": "Reached out about an integration issue and the support team responded within 2 hours. The platform itself is easy to use and well documented.",
      "publishedDate": "2026-02-18T14:32:00.000Z",
      "experiencedDate": "2026-02-15T00:00:00.000Z",
      "author": "Sarah C.",
      "authorCountry": "US",
      "authorReviewCount": 7,
      "isVerified": true,
      "hasCompanyReply": true,
      "companyReplyText": "Thanks Sarah! Glad our support team could help resolve the integration quickly.",
      "companyReplyDate": "2026-02-19T09:15:00.000Z",
      "responseTimeHours": 18.7,
      "language": "en",
      "authenticityScore": 0.95,
      "clusterId": null
    }
  ],
  "analyzedAt": "2026-03-30T10:45:00.000Z"
}
```

### Output fields

#### Decision fields (top of every record)

| Field | Type | Description |
|:------|:-----|:------------|
| `recordType` | string | `"business"` (default — one record per domain with nested reviews) or `"review"` (one record per review when `outputGranularity` is `review` or `both`). Discriminator for downstream filtering. |
| `schemaVersion` | string | Output JSON shape version. Increments on field additions/renames. Currently `3.0.0`. |
| `analysisVersion` | string | Computation/scoring logic version. Currently `3.0.0`. Pair with `schemaVersion` for full reproducibility. |
| `analysisProfile` | string | Profile applied for this run: `default` / `monitoring` / `competitor_benchmark` / `due_diligence` / `sales_prospecting` / `voice_of_customer`. |
| `dataQualityVerdict` | string | `"safe_to_act"` (high confidence, no warnings), `"use_with_caution"` (medium confidence or warnings present), `"insufficient_signal"` (low confidence or blocking warnings). Use as the primary automation gate. |
| `decision` | string | `"act_now"` (high-severity priority or alert), `"monitor"` (medium priority, declining trend, or alerts), `"ignore"` (healthy), `"no_data"` (business not found). Branch on this in webhooks/Slack/agents. |
| `decisionReason` | string | One-line explanation of why the decision was assigned |
| `oneLine` | string | Single shareable string ready for emails, dashboard tiles, or Slack messages |
| `failureType` | string/null | When `found=false`: `"no-data"` / `"blocked"` / `"parse-error"`. Null on successful records. |
| `reputationGrade` | string | Letter grade A-F synthesized from TrustScore (50pt) + response rate (30pt) + sentiment (20pt) |
| `reputationScore` | number | Numeric reputation score 0-100 |
| `competitiveStanding` | object/null | When 2+ businesses analyzed: `{ rank, total, trustScoreDeltaVsLeader, percentile }` |
| `urgentNegatives` | array | 1-2 star reviews from the urgent lookback window (default 7 days), sorted by recency |
| `authenticityFlags` | object/null | `{ suspiciousReviewCount, lowAuthenticityRate, averageAuthenticityScore }` |
| `alertsTriggered` | array | Threshold-based alerts when `alertThresholds` configured |
| `trends` | object/null | Period-over-period deltas vs prior run (requires `historyStoreName`). Direction: improving/stable/declining |
| `keywordSpikes` | array | Negative keywords with >50% increase in mentions vs prior run (requires history) |
| `priorities` | array | Ranked decision actions with `successMetric` + `expectedDirection` per item. Types: `urgent-negatives`, `response-decline`, `competitor-gap`, `trust-drop`, `fake-review-flag`, `sentiment-spike`, `no-response-pattern`. Use `priorities[0].type` for routing. |
| `executiveSummary` | object/null | `{ situation, biggestRisk, whatToDoNow, expectedOutcome }` — forwarding-ready text composed from existing signals. |
| `journeyBreakdown` | object/null | Reviews classified by lifecycle stage with `weakestStage` + `strongestStage` flags. |
| `riskForecast` | object/null | `{ trustScoreProjection, riskOfDrop, reason, timeHorizonDays, methodology, historicalSamples }` — linear projection (not probabilistic forecast) over 3+ history snapshots. |
| `confidence` | object | `{ sampleSizeScore, languageCoverage, dataCompleteness, overall, level, explanation, warningFlags[] }`. Use `level` (high/medium/low) for routing, `overall` (0-1) for filtering, or `warningFlags[]` to gate on specific issues. |
| `issueClusters` | array | Impact-weighted root-cause clusters from TF-IDF on negative reviews. Each: `{ id, label, reviewCount, severity, trend, averageRating, topTerms[], exampleReviewIds[], sampleHeadlines[], impactScore, businessRisk, replyGapPercent, whyThisMatters, journeyStage }`. Empty for fewer than 6 negative reviews. Sort by `impactScore` for priority order. |
| `recentSentiment` | object/null | Sentiment for last 30 days only with exponential-decay weighting. Includes `weightedSentiment` (-1 to 1). |
| `reviewsPerDay` | number/null | Review velocity from publish dates. Useful for detecting review-bomb campaigns. |
| `responseQuality` | object/null | `{ averageReplyLength, replyLengthCategory, replyToReviewLengthRatio, repliesAnalyzed }`. Goes beyond response rate. |
| `appliedScoringWeights` | object | The normalized weights used to compute reputationGrade for this record. Auditable per-run. |
| `sentimentByRating` | object/null | Top keywords broken out per star rating (1-5) |

#### Business-level fields

| Field | Type | Description |
|:------|:-----|:------------|
| `domain` | string | Normalized business domain |
| `url` | string | Full Trustpilot profile URL |
| `found` | boolean | Whether the business exists on Trustpilot |
| `businessName` | string/null | Display name from Trustpilot |
| `trustScore` | number/null | Trustpilot's proprietary TrustScore (0-5) |
| `stars` | number/null | Star rating (1-5) |
| `totalReviews` | number/null | Total review count on Trustpilot (all reviews, not just scraped) |
| `categories` | string\[] | Business categories assigned by Trustpilot |
| `websiteUrl` | string/null | Business website URL from their Trustpilot profile |
| `ratingDistribution` | object | Count of 1-5 star reviews in the scraped sample |
| `ratingDistributionPercent` | object | Percentage breakdown of star ratings in scraped sample |
| `averageRating` | number/null | Mean rating from scraped reviews (may differ from TrustScore) |
| `responseRate` | number/null | Percentage of scraped reviews with company replies |
| `averageResponseTimeHours` | number/null | Mean hours between review publish and company reply |
| `verifiedRate` | number/null | Percentage of scraped reviews with Trustpilot verification |
| `reviewsScraped` | number | Number of reviews in output (after filters applied) |
| `pagesFailed` | number | Number of review pages that failed to load after retries |
| `scrapingError` | string/null | Error description if scraping encountered issues |
| `analyzedAt` | string | ISO 8601 timestamp of analysis completion |

#### Sentiment fields

| Field | Type | Description |
|:------|:-----|:------------|
| `sentiment.positive` | number | Count of positive reviews (4-5 stars or positive keyword match) |
| `sentiment.negative` | number | Count of negative reviews (1-2 stars or negative keyword match) |
| `sentiment.neutral` | number | Count of neutral reviews (3 stars with no keyword tiebreaker) |
| `sentiment.positivePercent` | number | Positive review percentage |
| `sentiment.negativePercent` | number | Negative review percentage |
| `sentiment.neutralPercent` | number | Neutral review percentage |
| `sentiment.topPositiveKeywords` | array | Top 10 positive keywords with frequency counts |
| `sentiment.topNegativeKeywords` | array | Top 10 negative keywords with frequency counts |

#### Review-level fields

| Field | Type | Description |
|:------|:-----|:------------|
| `id` | string | Trustpilot review ID |
| `rating` | number | Star rating (1-5) |
| `title` | string/null | Review headline |
| `text` | string/null | Full review body (null if `includeReviewText` is false) |
| `publishedDate` | string/null | When the review was posted (ISO 8601) |
| `experiencedDate` | string/null | When the customer's experience occurred |
| `author` | string/null | Reviewer's display name |
| `authorCountry` | string/null | Reviewer's country code (e.g., "US", "GB", "DE") |
| `authorReviewCount` | number/null | Total reviews written by this author on Trustpilot |
| `isVerified` | boolean | Whether the review is verified by Trustpilot |
| `hasCompanyReply` | boolean | Whether the company replied to this review |
| `companyReplyText` | string/null | The company's reply text |
| `companyReplyDate` | string/null | When the company replied (ISO 8601) |
| `responseTimeHours` | number/null | Hours between review publish and company reply |
| `language` | string/null | Review language code (ISO 639-1) |
| `authenticityScore` | number/null | Heuristic authenticity score 0-1 from verified status, author review count, has-company-reply, and text length signals. Lower = more suspicious. |
| `clusterId` | number/null | If this review belongs to an issue cluster, the cluster's `id` (matches `issueClusters[].id`). Null if not in any cluster or fewer than 6 negative reviews scraped. |

### Analysis profiles (one-click presets)

Set `analysisProfile` to apply sensible defaults for `scoringWeights`, `alertThresholds`, and `urgentLookbackDays`. Explicit user inputs always override profile defaults.

| Profile | Scoring weights | Default alerts | Urgent window | Best for |
|:--------|:----------------|:---------------|:--------------|:---------|
| `default` | 50 / 30 / 20 / 0 | none | 7 days | Balanced default; explicit user config |
| `monitoring` | 35 / 25 / 20 / 20 | TrustScore ≥ 4.0, response rate ≥ 50%, reply ≤ 48h, sentiment ≥ 70% | 7 days | Daily reputation watch with scheduled runs |
| `competitor_benchmark` | 50 / 30 / 20 / 0 | none | 30 days | TrustScore-led cross-competitor comparison |
| `due_diligence` | 30 / 25 / 30 / 15 | none | 30 days | Vendor / investment assessment, sentiment-heavy grading |
| `sales_prospecting` | 30 / 35 / 15 / 20 | none | 14 days | Find prospects with reputation gaps; response-rate weighted |
| `voice_of_customer` | 20 / 15 / 35 / 30 | none | 30 days | Customer-feedback workflows; sentiment + recent-negatives heavy |

Weights are in order: TrustScore / response rate / sentiment / recent-negatives. All auto-normalized to 100.

### Output granularity (CSV vs JSON shape)

Set `outputGranularity` to control dataset row shape:

| Value | Shape | Best for |
|:------|:------|:---------|
| `business` (default) | One record per business with `reviews[]` nested | JSON consumers, dashboards, decision automation |
| `review` | One record per review (`recordType: "review"`) with parent business context flattened on each row | CSV / Excel analysts who want one-row-per-review |
| `both` | Business records first, then flat review records | Analysts who need both shapes in one run |

Each flat review record carries `businessDomain`, `businessName`, `businessTrustScore`, `reputationGrade`, `businessDecision`, `isTargetDomain`, the standard review fields, plus `clusterId` and `clusterLabel` so reviews can be filtered to specific issue clusters in spreadsheets.

### Methodology

All analytics are deterministic (no LLM, no external APIs) so output is reproducible across runs with the same inputs.

| Feature | Method |
|:--------|:-------|
| Reputation grade A-F | Weighted sum of TrustScore (50pt) + response rate (30pt) + sentiment (20pt) + recent-negatives penalty (0pt default). Configurable via `scoringWeights`, auto-normalized to 100. |
| Issue clusters | TF-IDF over negative review text + cosine similarity (threshold 0.30), greedy clustering, min cluster size 3, max 8 clusters. Stopwords + token length ≥4 filtered. |
| Cluster impact score | 30% normalized review-count + 30% rating severity (5-avg)/4 + 20% trend velocity + 20% reply gap. Maps to businessRisk: high ≥70, medium ≥45, low <45. |
| Journey stage classification | Keyword regex per stage (pre-purchase / onboarding / support / billing / delivery / product / post-sale). First match wins; null when no patterns hit. |
| Anomaly detection | Z-score per metric vs rolling baseline (last 12 history snapshots). Fires when |z| ≥ 2σ on TrustScore, sentiment positive %, or response rate. |
| Risk forecast | Least-squares linear regression of TrustScore over history snapshots + current run, projected `timeHorizonDays` (default 14) days forward. Risk-of-drop classified by projected delta and concurrent declining trend signals. Honest framing: linear projection, not a probabilistic forecast. |
| Recent sentiment | 30-day window with exponential decay (`exp(-ageDays / 14)`) — newer reviews count more |
| Confidence | `0.4 × sampleSizeScore + 0.2 × languageCoverage + 0.4 × dataCompleteness` + structured warningFlags enum |
| Authenticity score | Heuristic: 0.5 baseline + (verified +0.25) + (author review count signal ±0.10) + (has reply +0.10) + (text length vs median ±0.15). Clamped to \[0, 1]. |
| Response quality | Average reply length + reply-to-review length ratio. Categories: verbose (≥200 chars), standard (≥80), terse (<80). |
| Review velocity | Total reviews / span days from publish dates of scraped reviews |
| Sentiment classification | 4-5 stars = positive (rating-based); 1-2 stars = negative (rating-based); 3 stars = keyword text analysis using 84 English sentiment keywords |
| Sentiment by rating bucket | Same keyword vocabulary segmented by rating, top-5 per star level |
| Sentiment spike detection | Negative keywords with current count ≥3 AND >50% increase vs prior run |
| Competitive standing | Per-business rank by TrustScore + per-metric leader comparison (trust / response rate / sentiment / response time). Tolerance: ±0.05 for trust, ±1 for percentages and hours. |
| Industry patterns | Cluster labels appearing in ≥2 businesses; metric spread ≥10 between best and worst across businesses. Activates with 3+ analyzed businesses. |
| Executive summary | Composition over existing fields — situation/biggestRisk/whatToDoNow/expectedOutcome strings synthesized from grade, top priority, decision, trends. Outcome direction comes from priority's successMetric; magnitude is qualitative (no fabricated %). |

### AI / MCP-ready schema

Every output field is documented in `.actor/dataset_schema.json` with stable enum values, types, titles, and human-readable descriptions. This makes the actor uniquely suited for:

- **Apify MCP server** — agent tool calls can introspect the schema and route on `decision`, `priorities[].type`, `failureType`, `competitiveStanding.biggestGap.metric`, `trends.anomaly.type`, or `confidence.level` without parsing prose
- **Dify Run Actor node** — branch downstream nodes on stable enums (see [Use in Dify](#use-in-dify) section)
- **Zapier / Make** — filter triggers on `decision === "act_now"` or `alertsTriggered.length > 0`
- **Custom LLM agents** — the schema's field descriptions serve as in-context documentation; `oneLine` and `priorities[].headline` are paste-ready strings without LLM rewriting
- **Reproducibility** — `analysisVersion` and `appliedScoringWeights` on every record let downstream consumers regenerate output identically

The actor ships with **6 dataset views** in the Apify Console, each filtered to a specific workflow:

| View | Purpose |
|:-----|:--------|
| Executive Summary (start here) | Decision + grade + score + confidence — exec-friendly snapshot |
| Decisions | Decision + reason + priorities + trends + confidence — ops-friendly |
| Alerts | Decision + alertsTriggered + urgentNegatives + trends — incident response |
| Issue Clusters (root cause) | issueClusters + sentimentByRating + recentSentiment — product/CX teams |
| Competitor Comparison | isTargetDomain + competitiveStanding + trustScore + responseRate + trends — competitive intelligence |
| Raw Reviews | businessName + trustScore + reviews — analyst deep-dive |

### Comparison summary (key-value store)

When 1+ businesses are analyzed, the run's default key-value store has a `SUMMARY` key with this structure:

```json
{
  "analysisVersion": "2.0.0",
  "businessesAnalyzed": 3,
  "businessesFound": 3,
  "businessesNotFound": 0,
  "totalReviewsScraped": 300,
  "totalAlertsTriggered": 5,
  "totalUrgentNegatives": 8,
  "totalIssueClusters": 6,
  "historyEnabled": true,
  "targetDomain": "yourbrand.com",
  "target": {
    "domain": "yourbrand.com",
    "decision": "act_now",
    "oneLine": "yourbrand: TrustScore 4.3, grade B — top action: 5 unanswered 1-2 star reviews in last 7 days",
    "reputationGrade": "B",
    "reputationScore": 78,
    "rank": 2,
    "urgentNegativeCount": 5,
    "priorityCount": 3,
    "topPriority": "urgent-negatives",
    "trendDirection": "declining",
    "anomalyDetected": true
  },
  "comparison": [
    {
      "domain": "competitor-leader.com",
      "businessName": "Competitor Leader",
      "trustScore": 4.6,
      "stars": 5,
      "totalReviews": 5421,
      "reviewsScraped": 100,
      "responseRate": 85.0,
      "averageResponseTimeHours": 6.2,
      "reputationGrade": "A",
      "reputationScore": 92,
      "rank": 1,
      "urgentNegativeCount": 0,
      "priorityCount": 0,
      "topPriority": null,
      "trendDirection": "stable"
    }
  ],
  "industryPatterns": {
    "businessesIncluded": 3,
    "commonIssues": [
      { "label": "refund / delay", "appearsIn": 2 },
      { "label": "support / response", "appearsIn": 2 }
    ],
    "differentiationOpportunities": [
      { "metric": "averageResponseTimeHours", "bestValue": 6.2, "worstValue": 18.4, "spread": 12.2 },
      { "metric": "responseRate", "bestValue": 85.0, "worstValue": 60.0, "spread": 25.0 }
    ],
    "saturationSignals": []
  },
  "completedAt": "2026-05-02T10:45:00.000Z"
}
```

Use the `SUMMARY` for orchestrator workflows (Apify `Actor.call()` + `keyValueStore.getValue('SUMMARY')`) — gives a board-ready snapshot without iterating the full dataset. The `industryPatterns` block activates when 3+ businesses are analyzed and surfaces the cross-business view: which complaints are systemic vs which competitors are differentiated on.

### How much does it cost to scrape Trustpilot reviews?

Trustpilot Review Analyzer uses **pay-per-event pricing** — you pay **$0.15 per business analyzed**. Platform compute costs are included. Businesses not found on Trustpilot are not charged.

| Scenario | Businesses | Cost per business | Total cost |
|:---------|:-----------|:------------------|:-----------|
| Quick test | 1 | $0.15 | $0.15 |
| Small batch | 10 | $0.15 | $1.50 |
| Medium batch | 50 | $0.15 | $7.50 |
| Large batch | 200 | $0.15 | $30.00 |
| Enterprise | 1,000 | $0.15 | $150.00 |

You can set a **maximum spending limit** per run to control costs. The actor stops processing additional businesses when your budget is reached.

Compare this to ReviewTrackers at $69+/month, Birdeye at $350+/month, or SentiSum at $3,000+/month — with Trustpilot Review Analyzer, most users spend $1-15/month with no subscription commitment. Apify's free tier includes $5 of monthly credits, enough to analyze about 33 businesses.

### Scrape Trustpilot reviews using the API

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("ryanclinton/trustpilot-review-analyzer").call(run_input={
    "businesses": ["hubspot.com", "salesforce.com"],
    "maxReviewsPerBusiness": 200,
    "includeReviewText": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['businessName']}: TrustScore {item['trustScore']}, "
          f"{item['sentiment']['positivePercent']}% positive, "
          f"response rate {item['responseRate']}%, "
          f"avg reply {item['averageResponseTimeHours']}h")
```

#### JavaScript

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

const client = new ApifyClient({ token: "YOUR_API_TOKEN" });

const run = await client.actor("ryanclinton/trustpilot-review-analyzer").call({
    businesses: ["hubspot.com", "salesforce.com"],
    maxReviewsPerBusiness: 200,
    includeReviewText: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    console.log(`${item.businessName}: TrustScore ${item.trustScore}`);
    console.log(`  Sentiment: ${item.sentiment?.positivePercent}% positive`);
    console.log(`  Response rate: ${item.responseRate}%, avg reply: ${item.averageResponseTimeHours}h`);
}
```

#### cURL

```bash
## Start the actor run
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~trustpilot-review-analyzer/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "businesses": ["hubspot.com", "salesforce.com"],
    "maxReviewsPerBusiness": 200,
    "includeReviewText": true
  }'

## Fetch results (replace DATASET_ID from the run response)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
```

### How Trustpilot Review Analyzer works

#### Phase 1: Domain normalization and request building

The actor accepts domains in any format — bare domains (`amazon.com`), www-prefixed (`www.amazon.com`), full URLs (`https://amazon.com/about`), or Trustpilot profile URLs (`https://www.trustpilot.com/review/amazon.com`). A regex-based normalizer strips protocols, www prefixes, and paths to extract the clean domain. Duplicate domains across different input formats are deduplicated using a `Set` before crawling begins.

For each unique domain, the actor constructs the Trustpilot profile URL: `https://www.trustpilot.com/review/{domain}` and builds initial requests for page 1 of each business.

#### Phase 2: Paginated review extraction

A CheerioCrawler fetches Trustpilot review pages with session pooling (`useSessionPool: true`, `persistCookiesPerSession: true`) and conservative rate limiting (max 2 concurrent requests, 20 requests per minute). Each failed request is retried up to 5 times with session rotation.

Each review page embeds the complete structured data it is rendered from. The actor reads that structured data to extract business metadata (display name, TrustScore, stars, total reviews, categories, website URL), pagination info, and individual review records. Reading the embedded structured data is more reliable than scraping the rendered DOM.

After parsing page 1, the actor calculates how many additional pages are needed based on `maxReviewsPerBusiness` (20 reviews per page) and enqueues pages 2 through N. Reviews are collected into a per-domain state map.

#### Phase 3: Post-scrape filtering

After all pages are crawled, the actor applies user-configured filters to each business's review collection: rating range (minRating/maxRating), language code match, and verified-only filtering. All aggregate statistics are computed from the filtered review set, so response rates and sentiment reflect only the reviews that match your criteria.

#### Phase 4: Analysis and output assembly

For each business, the actor computes: rating distribution (counts and percentages for each star level), average rating from the scraped sample, response rate (percentage of reviews with company replies), average response time in hours (calculated from the delta between `publishedDate` and `reply.createdAt` for each replied review), and verified review rate.

Sentiment classification uses a dual approach. Reviews rated 4-5 stars are automatically classified as positive; 1-2 stars as negative. For 3-star reviews, the actor tokenizes the combined title and text, counts matches against 42 positive keywords (excellent, amazing, easy, recommend, etc.) and 42 negative keywords (terrible, scam, slow, expensive, etc.), and classifies based on which set has more matches — defaulting to neutral on a tie. The top 10 keywords by frequency are reported for both positive and negative review sets.

When analyzing multiple businesses, a comparison summary is saved to the key-value store (`SUMMARY` key), ranking all found businesses by TrustScore with response rate and average response time for each.

### Tips for best results

1. **Start with 20-50 reviews per business** to validate the output format works for your workflow before scaling to hundreds or thousands.

2. **Enable proxy for batches over 5 businesses.** Trustpilot may rate-limit unprompted requests. The built-in Apify proxy with session rotation handles this automatically.

3. **Use rating filters for targeted analysis.** Set minRating=1 and maxRating=2 to extract only negative reviews — useful for identifying product issues or competitor weaknesses without downloading thousands of positive reviews.

4. **Disable review text for dashboard-only workflows.** If you only need TrustScores, response rates, and sentiment percentages, turning off `includeReviewText` reduces dataset storage by approximately 80%.

5. **Schedule weekly runs to track reputation trends.** Use Apify Schedules to run every Monday morning, then connect to Google Sheets for a live competitor dashboard showing TrustScore and response rate over time.

6. **Check `pagesFailed` in results.** If this number is greater than 0, some review pages were blocked despite retries. The data is still valid but may be incomplete. Re-running with proxy enabled typically resolves this.

7. **Combine with contact scrapers for outreach.** Use [Website Contact Scraper](https://apify.com/ryanclinton/website-contact-scraper) to find email addresses for businesses with low TrustScores, then reach out with your reputation management or customer service product.

8. **Filter by language for market-specific insights.** Set `languageFilter` to "de" for German reviews or "fr" for French reviews to understand regional sentiment separately from global averages.

### Combine with other Apify actors

| Actor | How to combine |
|:------|:---------------|
| [Multi-Review Analyzer](https://apify.com/ryanclinton/multi-review-analyzer) | Aggregate Trustpilot reviews alongside BBB and other platforms for a complete multi-source reputation picture |
| [Website Contact Scraper](https://apify.com/ryanclinton/website-contact-scraper) | Find email addresses and phone numbers for businesses with poor TrustScores — ideal for reputation management outreach |
| [B2B Lead Qualifier](https://apify.com/ryanclinton/b2b-lead-qualifier) | Score businesses from Trustpilot analysis as leads using 30+ signals including web presence and tech stack |
| [Company Deep Research](https://apify.com/ryanclinton/company-deep-research) | Deep-dive into a company's full online presence beyond reviews — financials, news, social media, and more |
| [HubSpot Lead Pusher](https://apify.com/ryanclinton/hubspot-lead-pusher) | Push businesses with low TrustScores directly into HubSpot CRM as leads for sales team follow-up |
| [Website Tech Stack Detector](https://apify.com/ryanclinton/website-tech-stack-detector) | Identify what technologies a reviewed business uses — useful for SaaS sales targeting specific tech stacks |
| [Brand Protection Monitor](https://apify.com/ryanclinton/brand-protection-monitor) | Monitor brand mentions across the web alongside Trustpilot review sentiment for a complete brand health view |

### Use in Dify

Drop this actor into [Dify](https://docs.apify.com/platform/integrations/dify) workflows via the Apify plugin's Run Actor node. Each business returns scored, classified, and verdicted as structured JSON — `act_now` / `monitor` / `ignore` / `no_data` plus a reputation grade and a ranked priorities list your downstream node branches on. A vanilla Trustpilot scraper returns review HTML; this returns decisions.

- **Actor ID:** `ryanclinton/trustpilot-review-analyzer`
- **Sample input** (daily reputation watch with alert thresholds):

```json
{
  "businesses": ["yourbrand.com", "competitor1.com", "competitor2.com"],
  "maxReviewsPerBusiness": 100,
  "historyStoreName": "trustpilot-watch-yourbrand",
  "alertThresholds": {
    "minTrustScore": 4.0,
    "minResponseRate": 50,
    "maxResponseTimeHours": 48,
    "minSentimentPositivePercent": 70
  }
}
```

**Branching example — route the workflow on `decision`:**

| `decision` | Dify branch action |
|:-----------|:-------------------|
| `act_now` | Send Slack alert + create reputation-incident ticket. Pipe `priorities[0].headline` and `priorities[0].recommendedAction` into the message body — they're plain English and ready to paste. |
| `monitor` | Append to weekly digest doc. Use `oneLine` as the entry. |
| `ignore` | Skip downstream nodes (no action needed). |
| `no_data` | Trigger an "investigate listing" path — business not on Trustpilot or scraping was blocked. |

**Branching example — route on `priorities[0].type` for type-specific playbooks:**

```
priorities[0].type === "urgent-negatives"  → CX team intake
priorities[0].type === "trust-drop"        → exec escalation
priorities[0].type === "competitor-gap"    → marketing review
priorities[0].type === "fake-review-flag"  → trust & safety queue
priorities[0].type === "sentiment-spike"   → product investigation
```

**What's verbatim-usable in Dify nodes (no LLM rewriting needed):**

- `oneLine` — drops straight into Slack messages, email subjects, and dashboard tiles
- `priorities[].headline` and `priorities[].recommendedAction` — already plain English and team-routed via `priorities[].timeToAct` (immediate / this-week / this-month)
- `decisionReason` — explains the verdict in one sentence
- `urgentNegatives[]` — pre-filtered list of 1-2 star reviews from the last 7 days, ready for a "respond to negative reviews" sub-flow
- `alertsTriggered[]` — fires only when your `alertThresholds` are breached, with severity and a paste-ready message field

**Opt-in modes Dify workflows benefit from:**

- `historyStoreName` — turns the actor from a snapshot into a monitor. Trends (`trends.direction`, `keywordSpikes`) only appear on the second run onward, but enable scheduled-run change detection without external state.
- `urgentLookbackDays` — tighten the urgent-negatives window for high-frequency monitoring (1-3 days) or loosen it for weekly recap workflows (14-30 days).
- `alertThresholds` — set per-brand thresholds; alerts only fire when crossed, so noisy channels stay quiet on healthy runs.

### What is a reputation intelligence engine?

A reputation intelligence engine is a system that converts raw review data into routable decisions, ranked priorities, and monitoring signals — instead of returning sentiment scores or dashboards. It emits a single decision per business analyzed (`act_now`, `monitor`, or `ignore`) plus prioritized actions, root-cause issue clusters, and threshold alerts. Trustpilot Review Analyzer is one such engine, designed for direct use in agent workflows, MCP tool calls, and automation pipelines.

### How does Trustpilot anomaly detection work?

Trustpilot anomaly detection in this actor uses z-score statistics against a rolling baseline. Once 3+ historical run snapshots exist (via `historyStoreName`), every metric — TrustScore, positive sentiment percentage, response rate — is compared against the mean and standard deviation of the last 12 snapshots. When the current value drifts more than 2σ from the baseline, the actor emits a `trends.anomaly` block with the metric, sigma value, anomaly type (`positive-spike`, `negative-spike`, `response-collapse`, `sentiment-shift`), and a plain-English explanation. No LLM, no external API — just rolling statistics.

### What does it mean when a reputation actor returns "act_now"?

`act_now` is one of four routable decisions emitted by Trustpilot Review Analyzer (`act_now` / `monitor` / `ignore` / `no_data`). It fires when a business has high-severity priorities (such as 5+ unanswered urgent negative reviews) or blocking-severity threshold alerts. Downstream automation should branch on `decision === "act_now"` to trigger Slack alerts, create CX tickets, or notify on-call teams. Pair with `dataQualityVerdict` — only fully automate when the verdict is `safe_to_act`.

### What this does NOT do

Explicit constraints — the actor will not fabricate any of the following, by design:

- **Does not predict future outcomes with probability.** The `riskForecast` is a least-squares linear extrapolation of historical TrustScore — not a probabilistic model. There are no confidence intervals on the projection.
- **Does not infer causation from actions taken.** The actor cannot know which actions you executed between runs, so it never claims "this fix worked." `priorities[].successMetric` tells you which metric to watch yourself.
- **Does not estimate TrustScore component contributions.** Trustpilot's TrustScore is a proprietary black-box algorithm. The actor never decomposes it into "this cluster contributed -0.3 to your score" — that math cannot be defended.
- **Does not produce numeric "expected impact percentages" on actions.** No "+4-8% sentiment improvement" claims. Outcomes are qualitative (`expectedDirection: "increase"` or `"decrease"`); magnitude must be measured by re-running.
- **Does not run an LLM or any external AI API.** All scoring, clustering, sentiment, anomaly detection, and synthesis are deterministic math. Same input + same `analysisVersion` produces identical output.
- **Does not call any external API beyond Trustpilot.** No WHOIS, no Google ratings, no Facebook, no LinkedIn enrichment. Combine with sister actors (linked under [Combine with other Apify actors](#combine-with-other-apify-actors)) when those sources are needed.
- **Does not access non-public data.** Only Trustpilot pages reachable without login. No private reviews, no flagged-and-removed content, no internal Trustpilot moderation signals.
- **Does not perform real-time streaming.** This is a batch tool. Schedule it for monitoring; do not poll it for sub-minute event detection.

Rather than estimating outcomes, this actor reports observable signals and lets changes be measured empirically across runs. All outputs are derived from observable Trustpilot review data + (optionally) cross-run snapshots you opt into.

### When not to use this

- **Real-time review streaming** — use Trustpilot's webhooks or an event-driven system; this is a batch scheduler-friendly actor
- **Non-English sentiment analysis at scale** — the 84 sentiment keywords are English-only; non-English reviews are classified by star rating only
- **Platforms outside Trustpilot** — use [Multi-Review Analyzer](https://apify.com/ryanclinton/multi-review-analyzer) for cross-platform aggregation
- **Decisions that require a probabilistic forecast** — the linear projection is directional, not a forecast; pair with a forecasting tool if probability matters
- **Businesses without a Trustpilot listing** — `failureType` returns `"no-data"` and the run is not charged, but no analysis can be produced
- **Sub-minute latency workflows** — a single business takes 30-60 seconds to scrape; cold-start scheduling is the right pattern

### Limitations

- **Trustpilot page structure may change** — the actor reads structured data embedded in Trustpilot's pages. If Trustpilot changes their rendering approach, extraction may break until the actor is updated.
- **20 reviews per page** — Trustpilot paginates at 20 reviews per page. Scraping 5,000 reviews requires 250 page loads, which takes several minutes per business.
- **English-optimized sentiment keywords** — the 84 sentiment keywords are English. Reviews in other languages are classified by star rating only (4-5 = positive, 1-2 = negative, 3 = neutral). Keyword analysis will not surface non-English terms.
- **No historical or deleted reviews** — only reviews currently visible on Trustpilot are accessible. Reviews that have been removed, hidden, or flagged are not available.
- **Sample-based statistics** — rating distribution, response rate, and average response time are calculated from the scraped sample, not the full review population. For businesses with thousands of reviews, scraping 100-200 provides a representative sample.
- **No JavaScript rendering** — the actor parses HTML directly rather than running a browser. This works because Trustpilot embeds the review data in the page, but it means the actor cannot interact with JavaScript-dependent page elements.
- **Rate limiting on large batches** — Trustpilot may throttle requests when scraping hundreds of businesses. Use proxy configuration and keep maxConcurrency at the default (2) for reliable results.
- **50 business maximum per run** — the input accepts up to 50 domains. For larger batches, split into multiple runs.

### Integrations

- [Zapier](https://apify.com/integrations/zapier) — trigger CRM updates or Slack alerts when a competitor's TrustScore drops below a threshold
- [Make](https://apify.com/integrations/make) — build multi-step pipelines that scrape reviews, filter by sentiment, and push negative reviews to your support ticket system
- [Google Sheets](https://apify.com/integrations/google-sheets) — export TrustScores and response rates directly to a shared spreadsheet for team dashboards
- [Apify API](https://docs.apify.com/api/v2) — trigger runs programmatically from Python, JavaScript, or any HTTP client
- [Webhooks](https://docs.apify.com/platform/integrations/webhooks) — POST results to your endpoint on completion for real-time data pipelines
- [LangChain / LlamaIndex](https://docs.apify.com/platform/integrations) — feed structured review data into AI workflows for automated report generation or customer insight summaries

### Troubleshooting

- **Empty results despite business existing on Trustpilot** — Trustpilot may be blocking requests. Enable proxy configuration (`"proxyConfiguration": { "useApifyProxy": true }`) and re-run. Check the `scrapingError` field in the output for specific error messages.

- **Run taking longer than expected** — Each review page requires a separate HTTP request with rate limiting (20 requests/minute). Scraping 500 reviews per business across 10 businesses requires 250+ page loads. Reduce `maxReviewsPerBusiness` to 100 for faster results, or increase memory allocation to 1024 MB.

- **Some businesses show `found: false`** — The business may not have a Trustpilot profile, or the domain may not match their Trustpilot listing. Try the exact domain shown on their Trustpilot page. Some businesses register under a parent company domain.

- **Sentiment analysis seems inaccurate for non-English reviews** — The keyword-based sentiment classifier uses English keywords only. For non-English reviews, sentiment falls back to rating-based classification (4-5 = positive, 1-2 = negative, 3 = neutral). Use the `languageFilter` parameter to analyze English reviews separately.

- **`pagesFailed` is greater than 0** — Some review pages failed to load after 5 retries. The output still contains data from successful pages. Re-run with proxy enabled, or reduce the batch size to lower the request volume.

### How to compare competitors on Trustpilot (competitor review analysis tool)

Enter multiple business domains in the `businesses` field. Trustpilot Review Analyzer scrapes each one and produces a ranked comparison summary in the key-value store (SUMMARY key), sorted by TrustScore. The comparison includes TrustScore, star rating, total reviews, response rate, and average reply time for each business — useful for benchmarking your reputation against competitors.

### How to track company response rates on Trustpilot

Trustpilot Review Analyzer calculates two response metrics for each business: `responseRate` (percentage of reviews that received a company reply) and `averageResponseTimeHours` (average hours between review publication and company reply). Each individual review also includes `companyReplyDate` and `responseTimeHours`. Use these to evaluate how quickly a company handles customer feedback.

### How to export Trustpilot reviews to CSV or Excel

After a run completes, open the Dataset tab in the Apify Console. Click "Export" and choose CSV, Excel, or JSON. Each row is one business with all aggregate stats and individual reviews nested inside. For flat per-review exports, use the API to iterate individual review records.

### How to monitor Trustpilot reviews over time (reputation monitoring backend)

Trustpilot Review Analyzer functions as a reputation monitoring backend, not just a one-shot scraper. Schedule it daily, weekly, or at a custom cadence with `historyStoreName` set to a stable per-brand key. Each run persists `{trustScore, totalReviews, averageRating, responseRate, averageResponseTimeHours, verifiedRate, sentimentPositive%, sentimentNegative%, topNegativeKeywords}` to a named key-value store (FIFO 30-snapshot cap). From the **second run onward**, every record carries `trends` with period-over-period deltas. From the **third run onward**, `trends.anomaly` fires z-score detection when any metric drifts >2σ from the rolling baseline (last 12 snapshots), with anomaly types: `negative-spike`, `positive-spike`, `response-collapse`, `sentiment-shift`. Pipe `decision === "act_now"` to Slack or PagerDuty for live alerts.

### Best Trustpilot scraper for structured data extraction

Trustpilot Review Analyzer is one of the best Trustpilot scrapers available for developers, analysts, marketers, and growth teams who need structured review data for pipelines, dashboards, custom analysis, or AI agent workflows. It effectively acts as a Trustpilot scraper API + reputation intelligence engine — extracting review datasets without a Trustpilot API key, emitting decision-ready output (`decision`, `priorities`, `issueClusters`, `confidence`), exporting as JSON/CSV/Excel, and at $0.15 per business with no subscription. Every output field is documented in the dataset schema with stable enum values, making this actor uniquely AI/MCP-ready for agent tool calls.

### Trustpilot sentiment analysis tool

Trustpilot Review Analyzer acts as a Trustpilot sentiment analysis tool by classifying each review as positive, negative, or neutral. Reviews rated 4-5 stars are classified positive, 1-2 stars negative, and 3-star reviews are decided by keyword matching against 84 English sentiment terms. The output includes sentiment percentages and the top positive/negative keywords found across all reviews.

### Alternative to ReviewTrackers, Birdeye, and Trustpilot APIs

Trustpilot Review Analyzer is one of the most cost-efficient Trustpilot scrapers available — a cheaper alternative to ReviewTrackers for Trustpilot data extraction, without subscription pricing. Instead of paying $69-350+/month for ReviewTrackers or Birdeye, you pay $0.15 per business with no commitment. Trustpilot has no public review API, so this actor scrapes review pages directly.

Unlike dashboards that display pre-processed summaries, Trustpilot Review Analyzer outputs raw structured review data you can use in your own analytics, CRM, or reporting workflows. *Competitor pricing based on publicly available information as of March 2026 and may change.*

### What you can do with this data

- Identify competitors with poor customer response rates or slow reply times
- Discover common complaints and praise keywords across an industry
- Benchmark TrustScore and sentiment against competitors in one run
- Export review datasets for internal dashboards, BI tools, or data pipelines
- Find sales prospects with low TrustScores and high complaint volumes
- Monitor your own reputation over time with scheduled monthly scans

### Responsible use

- This actor only accesses publicly visible review data on Trustpilot.
- Respect website terms of service and `robots.txt` directives.
- Reviewer names and countries are public on Trustpilot but may be considered personal data under GDPR and similar regulations.
- Comply with GDPR, CAN-SPAM, and other applicable data protection laws when using scraped data for outreach.
- Do not use extracted data for spam, harassment, or unauthorized purposes.
- For guidance on web scraping legality, see [Apify's guide](https://blog.apify.com/is-web-scraping-legal/).

### FAQ

**How many Trustpilot reviews can I scrape per business?**
Up to 5,000 per business. The default is 100. Trustpilot shows 20 reviews per page, so 5,000 reviews requires 250 page loads per business. For most analysis use cases, 100-200 reviews provide a representative sample.

**Does this Trustpilot scraper need an API key?**
No. Trustpilot does not offer a public API for review data. This actor scrapes publicly visible review pages and extracts the structured data embedded in each page. No authentication is required.

**Can I scrape only negative Trustpilot reviews?**
Yes. Set `minRating` to 1 and `maxRating` to 2 to extract only 1-star and 2-star reviews. This is useful for competitive intelligence, identifying product issues, or building a case for reputation management services.

**How accurate is the Trustpilot sentiment analysis?**
The sentiment classifier uses a dual approach. Reviews rated 4-5 stars are automatically positive; 1-2 stars are automatically negative. For 3-star reviews, keyword frequency analysis determines the classification using 84 English sentiment keywords. This approach is accurate for aggregate trends but does not detect sarcasm, nuance, or non-English sentiment patterns.

**What is the difference between TrustScore and average rating?**
TrustScore is Trustpilot's proprietary score displayed on their website, calculated using their own weighting algorithm across all reviews. The `averageRating` field is the arithmetic mean of the reviews you actually scraped — they may differ because TrustScore weights recent reviews more heavily and considers the total review count.

**Can I compare multiple businesses on Trustpilot in one run?**
Yes. Enter up to 50 domains in the Businesses field. The actor scrapes each business, then generates a comparison summary in the key-value store (`SUMMARY` key) ranking all found businesses by TrustScore with response rate and average response time for each.

**How does Trustpilot Review Analyzer track company response times?**
For each review that has a company reply, the actor calculates the difference in hours between the review's `publishedDate` and the reply's `createdAt` timestamp. The `averageResponseTimeHours` field is the mean across all replied reviews. This metric is not available from most Trustpilot scrapers.

**Is it legal to scrape Trustpilot reviews?**
This actor accesses only publicly visible data. Web scraping of public data is generally permitted, but laws vary by jurisdiction. Reviewer names may constitute personal data under GDPR. Consult legal counsel for your specific use case and jurisdiction. See [Apify's guide on web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

**How is Trustpilot Review Analyzer different from ReviewTrackers or Birdeye?**
ReviewTrackers ($69+/month) and Birdeye ($350+/month) are subscription-based SaaS platforms with dashboards and multi-platform aggregation. This actor costs $0.15 per business with no subscription, outputs raw structured data (JSON/CSV), and integrates with any workflow via API. It focuses specifically on Trustpilot data extraction and analysis rather than being a full review management platform.

**Can I schedule Trustpilot review scraping to run automatically?**
Yes. Use Apify Schedules to run the actor daily, weekly, or at custom intervals. Combine with the Google Sheets integration to build a live reputation dashboard that updates automatically.

**What happens if a business is not found on Trustpilot?**
The output includes `"found": false` with null values for all business fields. No pay-per-event charge is applied for businesses not found on Trustpilot. The `scrapingError` field may contain additional details about why the lookup failed.

**How long does a typical Trustpilot scraping run take?**
A single business with 100 reviews takes about 30 seconds. A batch of 10 businesses with 100 reviews each takes 3-5 minutes. Large batches (50 businesses with 500 reviews each) may take 15-30 minutes due to rate limiting. Using proxy configuration can improve speed for larger batches.

### Help us improve

If you encounter issues, you can help us debug faster by enabling run sharing in your Apify account:

1. Go to [Account Settings > Privacy](https://console.apify.com/account/privacy)
2. Enable **Share runs with public Actor creators**

This lets us see your run details when something goes wrong, so we can fix issues faster. Your data is only visible to the actor developer, not publicly.

### Support

Found a bug or have a feature request? Open an issue in the [Issues tab](https://console.apify.com/actors/trustpilot-review-analyzer/issues) on this actor's page. For custom solutions or enterprise integrations, reach out through the Apify platform.

# Changelog

This Actor's version history is a separate document: https://apify.com/ryanclinton/trustpilot-review-analyzer/changelog.md

# Actor input Schema

## `businesses` (type: `array`):

Business domains or Trustpilot URLs (e.g. apify.com, https://www.trustpilot.com/review/amazon.com)

## `analysisProfile` (type: `string`):

One-click preset that sets sensible defaults for scoring weights, alert thresholds, and the urgent-negatives window. Explicit user inputs always override the profile. Default uses the v1 weights with no alerts.

## `outputGranularity` (type: `string`):

How to shape the dataset rows. 'business' (default) emits one record per business with reviews nested — best for JSON/API consumers and dashboards. 'review' emits one record per review with parent business context flattened — best for CSV/Excel analysts. 'both' emits the business record first, then the flat reviews.

## `targetDomain` (type: `string`):

When you analyze multiple businesses, set this to your own brand's domain. The output will tag your record with isTargetDomain=true and surface a `target` summary in the run's key-value store with your decision, rank, grade, and top priority. Leave empty if you're benchmarking competitors without a focal brand.

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

Maximum number of reviews to scrape per business (each page has ~20 reviews). Values above 500 may take several minutes per business.

## `includeReviewText` (type: `boolean`):

Include the full review text body in output. Disable to reduce dataset size when you only need ratings and metadata.

## `minRating` (type: `integer`):

Only include reviews with this rating or higher (1-5). Set to 1 for all reviews. Useful for focusing on negative reviews by setting to 1 and maxRating to 2.

## `maxRating` (type: `integer`):

Only include reviews with this rating or lower (1-5). Set to 5 for all reviews. Useful for focusing on negative reviews by setting to 2.

## `languageFilter` (type: `string`):

Only include reviews in this language (ISO 639-1 code, e.g. 'en', 'de', 'fr'). Leave empty for all languages.

## `verifiedOnly` (type: `boolean`):

Only include verified purchase reviews. Filters out unverified reviews.

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

Proxy settings for Trustpilot requests. Recommended for batches over 5 businesses.

## `urgentLookbackDays` (type: `integer`):

How many days back to scan for unanswered 1-2 star reviews. Default 7 days (last week's complaints).

## `historyStoreName` (type: `string`):

Optional named key-value store for cross-run history. When set, the actor stores per-domain snapshots and emits trends (TrustScore delta, response rate delta, sentiment spikes) on subsequent runs. Use the same name on every run for the same brand/competitor set. Example: "trustpilot-acme-history".

## `alertThresholds` (type: `object`):

Threshold-based alerts for monitoring. Alerts appear in alertsTriggered output when any threshold is breached. Leave any field empty to skip that check.

## `scoringWeights` (type: `object`):

Customize how the reputation grade (A-F) is computed. Weights are normalized to sum to 100. Defaults: trustScore 50, responseRate 30, sentiment 20, recentNegatives 0. Set recentNegatives>0 to penalize businesses with unanswered recent negatives.

## `detectIssueClusters` (type: `boolean`):

Group negative reviews into issue clusters using TF-IDF + cosine similarity (no LLM, no external API). Each cluster gets a label, severity, trend, and example review IDs. Useful for product/CX teams to identify root causes rather than reading every review. Default true; disable for faster runs on large samples.

## Actor input object example

```json
{
  "businesses": [
    "apify.com",
    "zapier.com"
  ],
  "analysisProfile": "default",
  "outputGranularity": "business",
  "maxReviewsPerBusiness": 100,
  "includeReviewText": true,
  "minRating": 1,
  "maxRating": 5,
  "verifiedOnly": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "urgentLookbackDays": 7,
  "alertThresholds": {
    "minTrustScore": 4,
    "minResponseRate": 50,
    "maxResponseTimeHours": 48,
    "minSentimentPositivePercent": 70
  },
  "scoringWeights": {
    "trustScore": 50,
    "responseRate": 30,
    "sentiment": 20,
    "recentNegatives": 0
  },
  "detectIssueClusters": true
}
```

# Actor output Schema

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

No description

# 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 = {
    "businesses": [
        "apify.com",
        "zapier.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    },
    "alertThresholds": {
        "minTrustScore": 4,
        "minResponseRate": 50,
        "maxResponseTimeHours": 48,
        "minSentimentPositivePercent": 70
    },
    "scoringWeights": {
        "trustScore": 50,
        "responseRate": 30,
        "sentiment": 20,
        "recentNegatives": 0
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryanclinton/trustpilot-review-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 = {
    "businesses": [
        "apify.com",
        "zapier.com",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
    "alertThresholds": {
        "minTrustScore": 4,
        "minResponseRate": 50,
        "maxResponseTimeHours": 48,
        "minSentimentPositivePercent": 70,
    },
    "scoringWeights": {
        "trustScore": 50,
        "responseRate": 30,
        "sentiment": 20,
        "recentNegatives": 0,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ryanclinton/trustpilot-review-analyzer").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 '{
  "businesses": [
    "apify.com",
    "zapier.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "alertThresholds": {
    "minTrustScore": 4,
    "minResponseRate": 50,
    "maxResponseTimeHours": 48,
    "minSentimentPositivePercent": 70
  },
  "scoringWeights": {
    "trustScore": 50,
    "responseRate": 30,
    "sentiment": 20,
    "recentNegatives": 0
  }
}' |
apify call ryanclinton/trustpilot-review-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ryanclinton/trustpilot-review-analyzer"
        }
    }
}
```

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/BLXRNH33QZNOoyKEg/builds/OnLhebner5r3vaT9I/openapi.json
