# Trustpilot Reviews Scraper — Reviews, Ratings & Company Data (`zkill3r/trustpilot-reviews-scraper`) Actor

Scrape Trustpilot reviews and company profiles: rating, text, dates, reviewer, verification, replies, TrustScore, rating distribution and contacts. Filters by stars, language, date, verified, replies. Beats the 200-review cap by splitting. From $0.30 per 1,000 reviews.

- **URL**: https://apify.com/zkill3r/trustpilot-reviews-scraper.md
- **Developed by:** [Zee Lex](https://apify.com/zkill3r) (community)
- **Categories:** E-commerce, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.30 / 1,000 reviews

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 Reviews Scraper — Reviews, Ratings & Company Data

Scrape public Trustpilot **reviews** and **company profiles** with no login. **$0.50 per 1,000 reviews** on the Free plan (down to $0.30 on Gold), no start fee.

Trustpilot is protected by AWS WAF. The scraper solves the check once per proxy session in a headless browser, then reads pages over fast plain HTTP, so runs are quick and cheap (about 300 reviews per minute).

- **Reviews:** star rating, title, text, language, published / experience / updated dates, verification label, likes, reviewer (name, country, review count, avatar) and the company's reply.
- **Companies:** TrustScore, stars, total reviews, rating distribution 1–5, categories, website, email, phone, address, claimed / verified status, logo, and reply behaviour (reply rate, average days to reply).
- **Filters:** star ratings, languages, date range, verified only, with company reply only, sort (most recent / most relevant), and "reviews since".
- **Discovery:** search Trustpilot for companies, or list companies from category pages (country, minimum TrustScore and verified filters).
- **Past the ~200-review limit:** when you ask for more reviews than Trustpilot pages without login, the scraper splits the query by star rating and then by language (see Limitations).

### Input examples

**A single company** (the prefill)

```json
{ "startUrls": ["https://www.trustpilot.com/review/www.apple.com"], "maxReviewsPerCompany": 20 }
```

**Plain domains and any country site**

```json
{ "startUrls": ["amazon.com", "https://uk.trustpilot.com/review/www.argos.co.uk", "de.trustpilot.com/review/zalando.de"], "maxReviewsPerCompany": 500 }
```

**Only 1-star reviews from the last 3 months, in English**

```json
{
  "startUrls": ["www.example-airline.com"],
  "stars": ["1"],
  "languages": ["en"],
  "dateRange": "last3months",
  "maxReviewsPerCompany": 1000
}
```

**Search companies, then 50 reviews from each of the top 5**

```json
{ "searchQueries": ["vpn", "web hosting"], "maxCompaniesPerSearch": 5, "maxReviewsPerCompany": 50 }
```

**Category lead list** (company items only, no reviews)

```json
{
  "categoryUrls": ["https://www.trustpilot.com/categories/electronics_technology"],
  "categoryCountry": "US",
  "categoryMinRating": "4",
  "maxCompaniesPerSearch": 100,
  "includeReviews": false
}
```

**Monitoring: new reviews since a date**

```json
{ "startUrls": ["www.example-shop.com"], "sortBy": "recency", "reviewsSince": "2026-10-01", "maxReviewsPerCompany": 5000 }
```

### Output samples

Values below are invented.

**Review**

```json
{
  "type": "review",
  "reviewId": "6f1c2a9e8b7d4c3a2b1e0f9d",
  "url": "https://www.trustpilot.com/reviews/6f1c2a9e8b7d4c3a2b1e0f9d",
  "companyName": "Example Electronics",
  "companyDomain": "www.example-electronics.com",
  "companyUrl": "https://www.trustpilot.com/review/www.example-electronics.com",
  "rating": 1,
  "title": "Order arrived two weeks late",
  "text": "The order arrived late and nobody answered my emails.",
  "language": "en",
  "publishedAt": "2026-10-27T09:14:02.000Z",
  "experiencedAt": "2026-10-24",
  "updatedAt": null,
  "isVerified": true,
  "verificationSource": "invitation",
  "verificationLevel": "invited",
  "isPending": false,
  "isEdited": false,
  "likes": 2,
  "reviewerName": "Jordan P.",
  "reviewerId": "8371b3f6e3308e4460413db2",
  "reviewerCountry": "GB",
  "reviewerReviewCount": 7,
  "reviewerImageUrl": null,
  "reply": { "text": "Sorry about the delay, Jordan. We've sent you a voucher.", "publishedAt": "2026-10-27T15:40:00.000Z", "updatedAt": null },
  "source": "www.example-electronics.com",
  "scrapedAt": "2026-10-28T11:25:26.339Z"
}
```

**Company**

```json
{
  "type": "company",
  "businessUnitId": "4b70b35164d5581b2fa5eb4a",
  "name": "Example Electronics",
  "domain": "www.example-electronics.com",
  "url": "https://www.trustpilot.com/review/www.example-electronics.com",
  "trustScore": 4.3,
  "stars": 4.5,
  "totalReviews": 400,
  "ratingDistribution": { "1": 40, "2": 30, "3": 50, "4": 80, "5": 200 },
  "categories": ["Electronics Store", "Computer Store"],
  "primaryCategory": "Electronics Store",
  "description": null,
  "website": "https://www.example-electronics.com",
  "email": "support@example-electronics.com",
  "phone": "+1 555 0100",
  "address": { "street": "12 Example Street", "city": "Springfield", "zip": "99999", "country": "US" },
  "isClaimed": true,
  "isClosed": false,
  "verifiedBusiness": true,
  "logoUrl": "https://s3-eu-west-1.amazonaws.com/tpd/logos/4b70b35164d5581b2fa5eb4a/0x0.png",
  "replyBehavior": { "replyPercentage": 91.7, "averageDaysToReply": 1.4, "lastReplyToNegativeReview": "2026-10-20T08:15:00.000Z", "negativeReviewsWithRepliesCount": 88, "totalNegativeReviewsCount": 96 },
  "dataSource": "review_page",
  "source": "www.example-electronics.com"
}
```

**Status** (free)

```json
{ "type": "status", "input": "missing-shop.com", "company": "missing-shop.com", "status": "not_found", "message": "No Trustpilot profile for \"missing-shop.com\"." }
```

`status` is one of:

- `not_found`: there is no profile.
- `no_reviews`: the company exists but has no reviews matching your filters.
- `blocked`: requests were still refused (403/429/challenge) after 4 retries.
- `error`: anything else.

Each run also stores a **RUN_SUMMARY** record. Per input it gives reviews saved, pages, splits used, blocks, proxy escalations and status, and per company each slice with its pages and why it stopped. It also gives totals, the percentage of each field that came back empty, and an overall status of `ok`, `partial`, `no_results` or `failed`.

### Use cases

- **Reputation monitoring:** schedule a daily run with `reviewsSince` and get only the new reviews.
- **Competitor analysis:** compare TrustScore, rating distribution, reply rate and complaint themes across competitors.
- **Sentiment and AI datasets:** collect clean, deduplicated review text with ratings, languages and dates.
- **Customer service QA:** export negative reviews with and without replies (`stars: ["1","2"]`, `withRepliesOnly`).
- **Lead generation:** list companies by category and country with website, email, phone and claimed status.

### How it works and limitations

- **Page cap and splitting.** Without login, Trustpilot serves only **10 pages × 20 reviews (200 reviews) per filter combination**; page 11 redirects to the login page.
  - When a company needs more than that, the scraper runs the same query once per star rating (1★ … 5★). Star buckets with 0 reviews are skipped when the rating distribution is known.
  - A star bucket that is still over the cap is split by language, using the languages Trustpilot lists for the company or a default list of 12 common languages.
  - Overlapping results are removed by `reviewId`.
  - **The most reachable is about 200 reviews per star per language.** For a very large company (for example 100k 5★ English reviews) you get the newest ~200 of each slice, not the full history.
  - With `reviewsSince` and "Most recent", the scraper only splits if the cap is actually hit before that date.
- **Country sites.** `uk.`, `de.`, `fr.` and other country URLs are read through www.trustpilot.com. The company data is the same; use `languages` to choose review languages.
- **`maxCompaniesPerSearch`** also applies to category pages.
- **Listing data.** With `includeReviews: false`, companies from search and category pages come from the listing data (`dataSource: "listing"`). That data has no rating distribution, claimed status or reply behaviour. Company URLs always use the full profile page.
- **Dates.** `experiencedAt` is a date (YYYY-MM-DD) and the other dates are ISO timestamps. "Reviews since" uses the published date.
- **Only public reviews are collected.** Reviews Trustpilot hides, removes or holds as pending don't appear.
- **Proxy.** Trustpilot blocks datacenter IPs outright (HTTP 403), so **RESIDENTIAL proxy is the default** and is required. On a 403/429 the scraper gets a new proxy session and a fresh WAF token, with backoff, up to 4 retries.
- **Not found.** An unknown company returns a free `status` item with `not_found`, confirmed once on a new session.
- **Category filters.** Trustpilot accepts `trustscore=4.5` and `3.0`/`4.0` style values; "claimed profiles only" uses Trustpilot's `claimed` filter (there is no "verified company" filter on category pages).
- **Replies filter.** `withRepliesOnly` and `verifiedOnly` use Trustpilot's own `replies=true` / `verified=true` filters.
- **Run timeout.** The scraper stops 30 seconds before the run's timeout, saves what it has and exits successfully.
- **Layout changes.** Trustpilot changes its pages from time to time. All JSON paths and URL patterns are kept in `src/mappings.ts`.

### Pricing

Pay per event. You only pay for results; there is no start fee and status items are free.

| Event | Free | Bronze | Silver | Gold+ |
|---|---|---|---|---|
| `review`, per 1,000 reviews | $0.50 | $0.45 | $0.38 | $0.30 |
| `company`, per 1,000 company items | $2.00 | $1.80 | $1.60 | $1.40 |

Example: 1,000 reviews of one company cost about $0.50 on the Free plan. The run stops cleanly once your maximum charge is reached.

### Development

```bash
npm install
npm test                  # unit tests on synthetic fixtures (+ live-capture tests when captured)
npm run mock-server       # offline Trustpilot mock on :4598 (see the header of test/mock-server.ts)
TP_BASE_URL=http://127.0.0.1:4598 npm start   # end-to-end against the mock, proxyConfiguration {"useApifyProxy": false}
npm run capture-fixtures  # save real Trustpilot responses to test/fixtures/live/ (needs network)
npm run fixtures          # regenerate the synthetic fixtures
```

# Actor input Schema

## `startUrls` (type: `array`):

Trustpilot company pages on any country site (https://www.trustpilot.com/review/<domain>, uk., de., fr., …) or plain domains like amazon.com. Search and category URLs also work here.

## `searchQueries` (type: `array`):

Optional. Search Trustpilot for companies (like its search box) and scrape the top matches.

## `categoryUrls` (type: `array`):

Optional. Category pages (https://www.trustpilot.com/categories/<slug>, or just the slug) to list companies from. Each company becomes a company item, plus its reviews when "Include reviews" is on.

## `maxCompaniesPerSearch` (type: `integer`):

How many companies to take from each search query and each category page, in Trustpilot's order.

## `categoryCountry` (type: `string`):

Optional 2-letter country code for category pages (e.g. US, GB, DE): only companies from that country.

## `categoryMinRating` (type: `string`):

Only list category companies with at least this TrustScore.

## `categoryVerifiedOnly` (type: `boolean`):

Only list companies that have claimed their Trustpilot profile (Trustpilot's 'claimed' filter).

## `includeReviews` (type: `boolean`):

Scrape reviews (one item per review, charged as "review").

## `maxReviewsPerCompany` (type: `integer`):

Maximum reviews saved per company. Beyond ~200 (Trustpilot's page cap) the scraper splits the query by star rating and then by language automatically.

## `stars` (type: `array`):

Only reviews with these star ratings (1-5). Empty = all ratings.

## `languages` (type: `array`):

Review languages as ISO codes (en, de, fr, …), or "all" (default). Trustpilot's country sites default to their own language, so the scraper always sends this explicitly.

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

Only reviews Trustpilot labels as verified.

## `withRepliesOnly` (type: `boolean`):

Only reviews the company has replied to.

## `dateRange` (type: `string`):

Trustpilot's own date filter.

## `sortBy` (type: `string`):

"Most recent" (needed for "Reviews since" to stop early) or Trustpilot's "Most relevant".

## `reviewsSince` (type: `string`):

Optional ISO date (e.g. 2026-10-01). Reviews published before it are skipped; with "Most recent" paging stops as soon as older reviews appear.

## `includeCompanyInfo` (type: `boolean`):

One company item per company (TrustScore, rating distribution, categories, contact details, claimed/verified, reply behaviour), charged as "company".

## `maxConcurrency` (type: `integer`):

Parallel requests. Lower it if RUN_SUMMARY shows many blocks.

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

Trustpilot blocks datacenter IPs (HTTP 403 from AWS WAF), so RESIDENTIAL proxy is the default and recommended. The Actor solves the WAF check once per proxy session in a headless browser, then fetches pages over fast plain HTTP. On a block it gets a new session and token (max 4 retries).

## Actor input object example

```json
{
  "startUrls": [
    "https://www.trustpilot.com/review/www.apple.com"
  ],
  "maxCompaniesPerSearch": 10,
  "categoryMinRating": "any",
  "categoryVerifiedOnly": false,
  "includeReviews": true,
  "maxReviewsPerCompany": 20,
  "languages": [
    "all"
  ],
  "verifiedOnly": false,
  "withRepliesOnly": false,
  "dateRange": "all",
  "sortBy": "recency",
  "includeCompanyInfo": true,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Reviews, companies and free status items (field "type").

## `allFields` (type: `string`):

Every field of every item.

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

Per input: reviews saved, pages, splits used, blocks, proxy escalations, status; totals; % missing per field; overall status.

# 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 = {
    "startUrls": [
        "https://www.trustpilot.com/review/www.apple.com"
    ],
    "maxReviewsPerCompany": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zkill3r/trustpilot-reviews-scraper").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 = {
    "startUrls": ["https://www.trustpilot.com/review/www.apple.com"],
    "maxReviewsPerCompany": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("zkill3r/trustpilot-reviews-scraper").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 '{
  "startUrls": [
    "https://www.trustpilot.com/review/www.apple.com"
  ],
  "maxReviewsPerCompany": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call zkill3r/trustpilot-reviews-scraper --silent --output-dataset

```

## MCP server setup

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

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/fUgR0ms7Y4wGQdw9r/builds/3h3kbU15IG9Qu3mal/openapi.json
