Arcadium Data Scrapers
Home / Guides / Trustpilot Reviews Scraper

How to use Trustpilot Reviews Scraper

Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.

$0.52 per 1,000 reviews on the Free plan, down to $0.27 on higher plans (live Apify price on 2026-11-02).

1. In the Apify Store (no code)

  1. Open arcadium/trustpilot-reviews and sign in to Apify (a free account works).
  2. Fill in the input form. The fields below are the ones the example uses.
  3. Set a maximum cost per run in the run options if you want a hard cap.
  4. Start the run. Rows appear in the Output tab as they arrive.
  5. Export the dataset as JSON, CSV or Excel, or connect an integration.
Input fieldTypeDescription
companiesarrayCompany domains (bestbuy.com, www.zalando.co.uk) or Trustpilot review pages (https://www.trustpilot.com/review/www.bestbuy.com, any country subdomain). One per line. Inputs that are not a domain produce a free error row. The field names companyUrls, companyDomains, companyDomain and startUrls are accepted too.
maxReviewsPerCompanyintegerMaximum number of reviews to collect for each company (up to 50,000; 0 = as many as the site shows). Trustpilot shows at most 200 reviews per filter combination; above that the actor reads further combinations (see 'More than 200 reviews per company'). Default: 100.
sortstringNewest first (recency) or Trustpilot's most relevant first (relevance). Newest first enables the date stop and the incremental mode. Default: recency.
verifiedbooleanOnly reviews Trustpilot marks as verified.
withRepliesbooleanOnly reviews the company has replied to.
includeCompanyInfobooleanAdd one free row per company (rowType 'company'): TrustScore, star rating, review count, star split, review counts by language, categories, reply rate, claimed status. No contact details.
splitFiltersbooleanTrustpilot shows anonymous visitors at most 200 reviews (10 pages) per filter combination. When you ask for more, the actor also reads each star rating on its own, the other sort order and date windows, and drops repeats. The coverage row says when the site's limit was reached. Default: on.
companySortstringOrder of companies in a category: Trustpilot's most relevant, most reviews first, or most recently reviewed first. Decides which companies a limit keeps.
claimedOnlybooleanOnly companies that have claimed their Trustpilot profile (Trustpilot's own filter).
maxCompaniesPerCategoryintegerMaximum companies read from each category in each country (up to 10,000, Trustpilot's own limit per category and country; list sub-categories to go further). Default: 200.
onlyNewReviewsbooleanSkip reviews delivered by earlier runs that used the same state key, and do not charge for them. Forces newest-first order.

Example input:

{
  "companies": [
    "www.bestbuy.com"
  ],
  "maxReviewsPerCompany": 20,
  "sort": "recency",
  "verified": false,
  "withReplies": false,
  "includeCompanyInfo": true,
  "splitFilters": true,
  "companySort": "most_relevant",
  "claimedOnly": false,
  "maxCompaniesPerCategory": 20,
  "onlyNewReviews": false
}

2. Over the Apify API

The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).

curl -X POST "https://api.apify.com/v2/acts/arcadium~trustpilot-reviews/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"companies":["www.bestbuy.com"],"maxReviewsPerCompany":20,"sort":"recency","verified":false,"withReplies":false,"includeCompanyInfo":true,"splitFilters":true,"companySort":"most_relevant","claimedOnly":false,"maxCompaniesPerCategory":20,"onlyNewReviews":false}'

3. From JavaScript

// npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/trustpilot-reviews').call({
  "companies": [
    "www.bestbuy.com"
  ],
  "maxReviewsPerCompany": 20,
  "sort": "recency",
  "verified": false,
  "withReplies": false,
  "includeCompanyInfo": true,
  "splitFilters": true,
  "companySort": "most_relevant",
  "claimedOnly": false,
  "maxCompaniesPerCategory": 20,
  "onlyNewReviews": false
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

4. From Python

# pip install apify-client
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/trustpilot-reviews").call(run_input={
    "companies": ["www.bestbuy.com"],
    "maxReviewsPerCompany": 20,
    "sort": "recency",
    "verified": False,
    "withReplies": False,
    "includeCompanyInfo": True,
    "splitFilters": True,
    "companySort": "most_relevant",
    "claimedOnly": False,
    "maxCompaniesPerCategory": 20,
    "onlyNewReviews": False,
})
items = client.dataset(run.default_dataset_id).list_items().items  # apify-client 3.x returns a Run object
print(items)

5. In n8n

Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.

{
  "nodes": [
    {
      "name": "Run arcadium/trustpilot-reviews",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        0,
        0
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/arcadium~trustpilot-reviews/run-sync-get-dataset-items",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\"companies\":[\"www.bestbuy.com\"],\"maxReviewsPerCompany\":20,\"sort\":\"recency\",\"verified\":false,\"withReplies\":false,\"includeCompanyInfo\":true,\"splitFilters\":true,\"companySort\":\"most_relevant\",\"claimedOnly\":false,\"maxCompaniesPerCategory\":20,\"onlyNewReviews\":false}",
        "options": {
          "timeout": 300000
        }
      }
    }
  ],
  "connections": {}
}

Ready-made workflow to import:

6. From an AI assistant (MCP)

Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:

{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=arcadium/trustpilot-reviews",
      "headers": {
        "Authorization": "Bearer <APIFY_TOKEN>"
      }
    }
  }
}

More on the MCP page.

7. From LangChain

# pip install langchain-apify   (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("arcadium/trustpilot-reviews")
rows = tool.invoke({"run_input": {
    "companies": ["www.bestbuy.com"],
    "maxReviewsPerCompany": 20,
    "sort": "recency",
    "verified": False,
    "withReplies": False,
    "includeCompanyInfo": True,
    "splitFilters": True,
    "companySort": "most_relevant",
    "claimedOnly": False,
    "maxCompaniesPerCategory": 20,
    "onlyNewReviews": False,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])

Sample output

One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.

{
  "rowType": "company",
  "source": "category",
  "businessUnitId": "5d2f4f05dc509f00010c9b44",
  "entityId": "itrustcapital.com",
  "name": "iTrustCapital",
  "url": "https://www.trustpilot.com/review/itrustcapital.com",
  "trustScore": 5,
  "stars": 5,
  "reviewCount": 9946,
  "primaryCategory": "Software Company",
  "country": "US",
  "hasConsumerAlert": true,
  "alertType": "InfoHighRiskInvestment",
  "listingCategory": "electronics_technology",
  "listingCountry": "US",
  "listingRank": 1
}
FieldWhat it holds
rowTypeKind of row. Filter on this first. Values: 'company': one row per company with TrustScore, stars, review count and categories (free with reviews; charged as the 'company' event in company mode: categories, or includeReviews false). 'review': one review (charged). 'coverage': stated total vs delivered and why reading stopped, per company or per category and country (free). 'error': an input could not be read; see code and message (free). 'watch-summary': watch mode counts (free).
platformSource site, always 'trustpilot'.
productNameCompany name as shown on Trustpilot.
productUrlThe company's Trustpilot page, e.g. https://www.trustpilot.com/review/www.bestbuy.com.
entityIdThe company's Trustpilot domain (identifyingName), e.g. 'www.bestbuy.com'.
reviewIdStable review id in the form '<Platform>___<native id>'. Use it to deduplicate between runs.
reviewIdSource'native' when the id comes from the site, 'derived' when it is a hash of the content (less stable).
reviewUrlLink to the single review, null when the site has none.
titleReview headline, null when the site has none.
textReview text in the language it was written in. Null when the review has no text.
prosNot used on Trustpilot, always null (shared review model).
consNot used on Trustpilot, always null (shared review model).
ratingOverallStar rating of the review, 1 to 5.
ratingsNot used on Trustpilot, always an empty object (shared review model).
dateDate the review was published, ISO yyyy-mm-dd. Date of experience: extras.experiencedDate.
reviewerRoleNot used on Trustpilot, always null (shared review model).
reviewerIndustryNot used on Trustpilot, always null (shared review model).
reviewerCompanySizeNot used on Trustpilot, always null (shared review model).
reviewerTimeUsedNot used on Trustpilot, always null (shared review model).
switchedFromNot used on Trustpilot, always null (shared review model).
alternativesConsideredNot used on Trustpilot, always null (shared review model).
reasonForChoosingNot used on Trustpilot, always null (shared review model).
reasonForSwitchingNot used on Trustpilot, always null (shared review model).
adviceToOthersNot used on Trustpilot, always null (shared review model).
incentivizedNot used on Trustpilot, always null (shared review model).
incentiveNot used on Trustpilot, always null (shared review model).
reviewerVerifiedTrue when Trustpilot marks the review as verified. No identity data is output.
vendorResponseThe company's public reply, null when there is none. The reviewer's name is removed from it. Reply date: extras.vendorResponseDate.
helpfulVotesNumber of 'useful' votes (likes) on the review.
languageLanguage of the review text as a two-letter code, null if unknown.
countryCompany rows: ISO two-letter country of the company (from the profile, or mapped from the category listing). Review rows: always null.
productSummary of the reviewed entity repeated on each row: { platform, entityId, name, url, rating, reviewCount, category, vendor, website }. rating and reviewCount are the site's overall figures.
extrasTrustpilot extras: nativeId, publishedAt (full timestamp), experiencedDate, updatedDate, verificationLevel, verificationSource, reviewSource, hasReply, vendorResponseDate, vendorResponseUpdatedDate, businessLocation.
businessUnitIdCompany rows: Trustpilot's internal id for the company.
nameCompany rows: company name.
urlCompany rows: the company's Trustpilot page.
websiteCompany rows: the company's website as listed on Trustpilot.
trustScoreCompany rows: TrustScore, 1.0 to 5.0.
starsCompany rows: star rating shown on the profile (half stars).
reviewCountCompany rows: total number of reviews Trustpilot states.
reviewCountLast12MonthsCompany rows: reviews in the last 12 months.
starSplitCompany rows: number of reviews per star rating, { '1': n, '2': n, '3': n, '4': n, '5': n }.
languagesCompany rows: number of reviews per language code, e.g. { en: 6842, fr: 162 }.
primaryCategoryCompany rows: the company's main Trustpilot category.
categoriesCompany rows: every category, [{ id, name, isPrimary }].
categoryPathCompany rows: category path from top level down, e.g. ['Shopping & Fashion', 'Clothing Store'].
isClaimedCompany rows: true when the company has claimed its Trustpilot profile.
claimedDateCompany rows: date the profile was claimed (yyyy-mm-dd), null if unknown.
isClosedCompany rows: true when Trustpilot marks the business as closed.
isCollectingReviewsCompany rows: true when the company invites customers to review.
usesPaidFeaturesCompany rows: true when the company uses Trustpilot's paid features.
hasCollectedIncentivisedReviewsCompany rows: true when Trustpilot says the company collected incentivised reviews.
replyPercentageCompany rows: share of negative reviews the company replied to, in percent.
averageDaysToReplyCompany rows: average days the company takes to reply to negative reviews.
negativeReviewsWithRepliesCompany rows: negative reviews with a company reply.
negativeReviewsTotalCompany rows: negative reviews in Trustpilot's reply statistics.
lastReplyToNegativeReviewCompany rows: date of the latest reply to a negative review (yyyy-mm-dd).
hasConsumerAlertCompany rows: true when Trustpilot shows a consumer alert on the profile.
locationsCountCompany rows: number of business locations on Trustpilot.
scrapedAtISO timestamp of when the row was collected.
statedCoverage rows: total the site states for the entity, null when it does not say.
deliveredCoverage rows: number of rows delivered for the entity in this run.
skippedSeenCoverage rows: items skipped because an earlier run already delivered them (only-new mode).
duplicatesCoverage rows: repeats the site returned that were dropped.
stopReasonCoverage rows: why reading stopped. limit (your maximum reached), end (no more pages), dateFrom (older than your date), onlyNew (reached already delivered items), budget (run charge limit), cap (site-side depth limit), error (ended by a failure), filter (ended with a filter active).
capSourceCoverage rows: who limited the result, 'user' (your maximum or budget) or 'site' (a limit of the website). Null if nobody.
shortfallCoverage rows: true when the result may be incomplete: fewer rows than the site states with no maximum or filter set, an error, or the site's paging changed during the run. shortfallReason says which.
shortfallReasonCoverage rows: why shortfall is true. below_stated (fewer rows than the site states, no maximum or filter), error (ended by a failure), unstable_paging (the site changed its list while it was read, so rows inside the range read may be missing even though your maximum or date ended the run). Null when shortfall is false.
pagingGapsCoverage rows: number of pages the site served inconsistently that could not be repaired by re-reading. Above 0 means shortfallReason unstable_paging.
inputError and coverage rows: the input (URL, id or search text) the row is about. Example: 'https://www.example.com/page'.
codeError rows: machine-readable reason. One of invalid_input (fix the input), not_found (page does not exist), blocked (site refused, retry later), unavailable (temporary error, retry later), filter_unsupported (the filter cannot be applied on this site), no_match (name search found nothing).
messageError rows: short human-readable explanation. Do not parse it, use code.
sourceCompany rows: 'profile' (read from the company's review page: every company field) or 'category' (read from a category listing: profile-only fields such as starSplit and reply statistics are null).
cityCompany rows from a category: the company's city as Trustpilot lists it. Never a street address. Null on profile rows.
isVerifiedCompany rows from a profile: true when Trustpilot shows any business verification (identity, Google, payment method). Null on category rows.
alertTypeCompany rows: Trustpilot's consumer alert type, e.g. 'InfoHighRiskInvestment'; null without an alert.
isGamblingRelatedCompany rows from a category: Trustpilot marks the company as gambling related.
isRecommendedInCategoriesCompany rows from a category: Trustpilot marks the company as recommended in its categories.
listingCategoryCompany rows from a category: the category id the row was listed in, e.g. 'bank'.
listingCountryCompany rows from a category: the country filter of that listing (ISO two-letter).
listingRankCompany rows from a category: 1-based position in that listing, in the requested company order.
changeWatch mode only: why the row was delivered. type 'new' or 'changed'; fields lists changed fields with old -> new; previousCheckAt is when the compared snapshot was saved.
scopeWatch-summary rows: 'companies' for the company-row summary; absent on the review summary.
categoryIdCoverage rows of company mode: the category id read.
listedCoverage rows of company mode: companies read from the listing, repeats included (delivered = new to this run).

Tutorials

Schedule it

In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.