kestrel actors docs

kestrel actors › Guest & customer reviews

Trustpilot Reviews Scraper — Company Reviews & TrustScore

A trustpilot reviews scraper that turns any company profile into structured company reviews: the 1–5 star rating, the headline, the body text, the language it was written in, when it was published and when the experience happened, who wrote it and from which country, whether it is verified, how many readers found it useful, and the company's own public reply. Alongside the reviews it hands you the free company block — TrustScore, the star histogram, the per-language breakdown and the public contact details — so one run returns both the customer feedback and the Trustpilot data about the profile it came from.

Run Trustpilot Reviews Scraper on Apify →

Trustpilot reviews scraper pricing: what one row costs

EventWhat it isPriceCharged for
reviewReview row$0.0007One Trustpilot review: 1-5 rating, title, text, language, review and experience dates, reviewer name, country and review count, verification level and source, likes and the company's reply. Company and status rows are free; rows a filter drops are never billed.

Pay per review row. company and status rows are free, and so is any company that turns out to have no reviews or no profile at all. Filters run before billing, so the rows you filter out cost nothing.

One run pays a small fixed overhead: a headless browser solves the site's bot challenge once, which takes five to twenty seconds of compute and a megabyte or so of proxy traffic. Every page after that is fetched without a browser, so the overhead is amortised across the whole run — it is noticeable on a twenty-review test and invisible on a thousand-review harvest. The token is re-solved every four minutes because the site stops honouring it at about five.

Trustpilot reviews scraper input reference

Every field of Trustpilot Reviews, straight from the actor's input schema.

FieldTypeDefaultWhat it does
companyDomainsarray[]The domain a company is listed under on Trustpilot — the part after trustpilot.com/review/, e.g. www.booking.com, www.monzo.com, ryanair.com. A company's own website URL works too (the domain is taken from it), and Trustpilot's own canonical spelling is followed automatically, so monzo.com resolves to www.monzo.com.
startUrlsarray[]Trustpilot company pages, e.g. https://www.trustpilot.com/review/www.booking.com — any query string is ignored (set the filters below instead), and a country subdomain such as uk.trustpilot.com is read as the same profile.
maxReviewsPerCompanyinteger1000 = as deep as Trustpilot lets an anonymous visitor go. Trustpilot stops paging after 200 reviews of any one filtered view, so this actor walks the five star bands separately and merges them: up to 1000 reviews per company per run, newest first. N = the first N in the order below. The main cost control. Range 0-1000.
sortstring (enum)"most_recent"most_recent = newest first (the order a monitoring schedule wants); most_relevant = Trustpilot's own relevance order. One of: most_recent, most_relevant.
deepPagingbooleantrueOn (the default): when more than 200 reviews are asked for, each star rating is fetched as its own filtered view — 1, 2, 3, 4 and 5 stars each have their own 200-review allowance — and the results are merged and de-duplicated, so up to 1000 reviews come back per company. Off: one view only, so never more than 200 reviews and never more than 10 page requests per company.
languagesstring"all"all = every language, and the default here (Trustpilot's own page shows English only, which hides most reviews of a global brand). Or one language code — en, de, fr, es, it, nl, da, sv … — applied by Trustpilot itself, so reviews in other languages are never fetched and never billed. The company row lists how many reviews each language holds.
minRatinginteger00 = any. 1-5 = keep only reviews rated at or above this. Combine with maxRating for a band, e.g. minRating 1 and maxRating 2 for a complaints feed. Range 0-5.
maxRatinginteger00 = any. 1-5 = keep only reviews rated at or below this. maxRating 2 on a 125,000-review brand fetches and bills only the 1- and 2-star rows, because the star filter is Trustpilot's own URL parameter and runs on their servers. Range 0-5.
dateRangestring (enum)"all"Trustpilot's own date filter, applied server-side. all = no limit. One of: all, last30days, last3months, last6months, last12months.
sinceDatestring""Keep only reviews published on or after this date: YYYY-MM-DD, or relative so a schedule never goes stale — "7 days", "2 weeks", "1 month". With most_recent order the walk stops at the first page that is older than the cut, so a daily run reads one or two pages.
verifiedOnlybooleanfalseKeep only reviews Trustpilot marks as verified (invited after a real transaction, or identity-checked). Applied by Trustpilot, so unverified reviews are never fetched or billed.
keywordstring""Keep only reviews mentioning this word or phrase — refund, delivery, cancellation, chargeback. This is Trustpilot's own review search, so non-matching reviews are never fetched or billed.
requireTextbooleanfalseDrop reviews that carry only a star rating and a title, before billing.
includeCompanyRowbooleantrueOne free row per company: TrustScore, stars, total reviews, reviews in the last 12 months, the 1-5 star histogram, the per-language breakdown, categories, website, country, the public contact details Trustpilot shows, and the claimed/closed/verification flags.
sessionsinteger2How many proxy sessions (egress IPs) fetch pages in parallel. Each is paced separately. 2 is plenty for a handful of companies; raise it for long lists. Range 1-8.
perIpnumber1Pace for each session. 1 request per second per IP is what Trustpilot tolerates comfortably; higher values earn retries, not speed. Range 0.2-2.
proxyConfigurationobject{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}Apify Proxy with the RESIDENTIAL group (the default, and required: the headless browser that solves the WAF challenge runs through it). Once the token exists it is honoured from any IP, so the page fetches themselves are not fussy.

Example input

{
  "companyDomains": ["www.booking.com", "www.expedia.com", "www.agoda.com"],
  "maxReviewsPerCompany": 60,
  "sort": "most_recent",
  "minRating": 1,
  "maxRating": 2,
  "sinceDate": "2 days",
  "requireText": true,
  "languages": "all"
}
{
  "companyDomains": ["www.monzo.com"],
  "maxReviewsPerCompany": 1000,
  "deepPaging": true,
  "requireText": true,
  "languages": "en",
  "includeCompanyRow": true
}

Trustpilot reviews scraper output fields

One row per Trustpilot review (charged), plus a free company context row and a free status row per company.

Dataset views in the Apify Console: Overview, Reviews, Complaints, Companies, Status.

FieldTypeWhat it holds
typestringreview | company | status
review_idstringTrustpilot's review id (stable across runs; also the last part of the review URL)
company_domainstringThe domain the profile is listed under, e.g. www.booking.com
company_namestringDisplay name of the company on Trustpilot
ratinginteger1-5 stars
titlestringReview headline
textstringReview body (null when the reviewer left only a rating and a title)
languagestringISO code of the language the review was written in
review_datestringYYYY-MM-DD the review was published
experience_datestringYYYY-MM-DD of the experience the reviewer is describing
updated_datestringYYYY-MM-DD the reviewer last edited the review
reviewer_namestringDisplay name of the reviewer
reviewer_idstringTrustpilot consumer id
reviewer_countrystringTwo-letter country code of the reviewer
reviewer_reviewsintegerHow many reviews that consumer has written in total
verifiedbooleanTrustpilot's verified badge
verification_levelstringverified | not-verified | invited …, Trustpilot's own label
sourcestringOrganic, Invitation, BusinessGeneratedLink … — how the review was collected
likesintegerHow many readers found the review useful
reply_textstringThe company's public reply
reply_datestringYYYY-MM-DD the reply was published
locationstringBranch or location the review is attached to, for multi-location profiles
urlstringPermalink: the review on a review row, the profile on a company row
company_idstringTrustpilot business unit id
trust_scorenumberTrustScore, 1.0-5.0
starsnumberThe rounded star rating Trustpilot displays
review_countintegerTotal reviews on the profile
reviews_last_12_monthsintegerReviews published in the last twelve months
review_count_filteredintegerHow many reviews match this run's filters, as Trustpilot counts them
ratingsobjectStar histogram: {one, two, three, four, five} counts
review_languagesarray[{code, name, count}] — how many reviews each language holds
categoriesarrayTrustpilot category names the company is listed in
websitestringThe company's website as Trustpilot has it
country_codestringTwo-letter country code of the company
emailstringPublic contact email on the Trustpilot profile
phonestringPublic contact phone on the Trustpilot profile
addressstringPublic postal address on the Trustpilot profile
is_claimedbooleanThe company has claimed its profile
is_closedbooleanThe profile is closed or temporarily closed
is_collectingbooleanThe company actively invites customers to review it
verified_paymentbooleanTrustpilot verified the company's payment method
verified_identitybooleanTrustpilot verified the company's identity
reviews_fetchedintegerReviews this run read for the company before the actor-side filters
targetstringThe input this status row is about
statusstringok | no_reviews | not_found | error
reviewsintegerReview rows delivered for this company
filteredintegerReviews fetched but dropped by requireText / minRating / maxRating / verifiedOnly (never charged)
pagesintegerReview pages read for this company
totalintegerTrustpilot's own count of reviews matching this run's filters
cappedbooleanTrue when the walk stopped at Trustpilot's anonymous paging wall rather than at the end of the reviews
duplicatesinteger1 when another input already covered this company
errorstringWhy this company produced nothing
fetched_atstringUTC timestamp of the fetch

Trustpilot reviews scraper in Python, JavaScript and curl

Python

from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("kestrel/trustpilot-reviews-scraper").call(run_input={
    "companyDomains": ["www.booking.com"],
    "maxReviewsPerCompany": 200,
    "sort": "most_recent",
    "languages": "all",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "review":
        print(row["rating"], row["review_date"], row["title"])

JavaScript (Node)

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('kestrel/trustpilot-reviews-scraper').call({
    companyDomains: ['www.monzo.com'],
    maxReviewsPerCompany: 100,
    minRating: 1,
    maxRating: 2,
    requireText: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'review').length, 'reviews');

curl

curl -X POST "https://api.apify.com/v2/acts/kestrel~trustpilot-reviews-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"companyDomains":["www.booking.com"],"maxReviewsPerCompany":40,"sort":"most_recent"}'

The same three calls are runnable files in the examples repository: examples/trustpilot-reviews-scraper.py|.js|.sh.

Limits and honest notes

  • 200 reviews per filtered view is the platform's wall for anonymous visitors, and 1,000 per company per run is the practical ceiling once the five star views are combined. If you need more, narrow with dateRange or languages and run again — each combination has its own allowance.
  • The bot challenge is solved with a real browser once per run and refreshed every four minutes. If a run is very short, that fixed cost is a real share of it.
  • verifiedOnly reflects the platform's own badge, which many companies never use; some large profiles have only a handful of verified reviews.
  • Reviews are returned as written, never translated.
  • location is only populated for profiles that run multiple branches.

FAQ

Does it need a Trustpilot API key or login?

No. There is no account, no key and no cookie to paste. It reads the same public pages a visitor sees.

Can I download Trustpilot reviews as CSV or Excel?

Yes. Every run writes an Apify dataset, so a Trustpilot review export is one click: Trustpilot reviews CSV, Excel, JSON, XML or RSS from the Console, or straight from the API. The Reviews view is already trimmed to the fields most people want.

How do I get only Trustpilot negative reviews?

Set minRating: 1 and maxRating: 2 — that is how you pull Trustpilot reviews by rating. That becomes the site's own star filter, so the four- and five-star rows are never downloaded and never billed. Add requireText: true to drop the rating-only rows.

How far back can I go?

As far as 200 reviews per filtered view takes you — a few weeks on a very busy brand, years on a quiet one. Use dateRange to aim a window, and sinceDate to stop a scheduled run as soon as it reaches material it already has.

Which companies can I scrape?

Any profile that exists. Give the domain exactly as the profile lists it. If the profile does not exist you get a free status row with not_found — you are never charged for a miss, and it is never reported as "no reviews".

Does it include the company's replies?

Yes: reply_text and reply_date on every review that has one. Response rate and median response delay are both computable from a single run.

What is TrustScore, and where do I find it?

TrustScore is the platform's weighted score out of five, and it lives on the free company row as trust_score, next to stars, review_count and the full ratings histogram. You are never billed for it.

Can I use this for review sentiment analysis?

Yes, and requireText: true plus a single languages value is the combination to use — it gives a model clean, one-language input with no rating-only rows to skew the corpus.

How fast is it?

About one page (20 reviews) per second per session, two sessions by default, plus the one-off browser bootstrap. A 1,000-review company takes a couple of minutes; a hundred small profiles take about the same.

What does bulk work cost?

Cost scales with delivered rows, not with companies, which is what makes bulk company reviews practical. A hundred profiles at 50 recent reviews each is 5,000 rows; the same hundred profiles at minRating: 1, maxRating: 2 is a fraction of that, because the rest are never fetched.

How to use Trustpilot Reviews Scraper

Ready-made runs you can open and start

Each one is a saved input on the Apify Store — open it, press Start, and it runs with the fields already filled in. All 163 across the suite.

Ready-made runWhat it does
Trustpilot Negative Reviews for Any CompanyOne- and two-star Trustpilot reviews of one travel brand, newest first, with the company's reply beside each - filtered on Trustpilot's side, not after.
Download Trustpilot Reviews to CSVSeven hundred newest Trustpilot reviews of one company, past the 200-review wall, with rating, text, dates, reviewer country and reply as CSV or JSON.
Trustpilot Reviews by Rating: Five Stars OnlyThree hundred five-star Trustpilot reviews with written text for one company: what customers praise, in their own words, with country and date.
Trustpilot Reviews by Date: Last 30 DaysOnly the last thirty days of Trustpilot reviews for one brand, filtered by Trustpilot itself, with the free company row's TrustScore as the baseline.
Trustpilot Competitor Reviews: Five NeobanksFive challenger banks compared on Trustpilot: TrustScore, stars, review totals and the star histogram per brand, with a hundred newest reviews each.
Customer Feedback Mentioning Refunds on TrustpilotOnly Trustpilot reviews that mention a refund for one travel booking site, searched on Trustpilot's side so nothing else is billed - swap in any keyword.
Verified Customer Reviews Only from TrustpilotOnly Trustpilot reviews marked verified - invited after a real order or identity-checked - for one meal-kit brand; unverified rows are never billed.
German-Language Trustpilot Reviews Only (de)Only German-language Trustpilot reviews of one retailer's German site, filtered by Trustpilot itself - the reviews the English page never shows you.
Reputation Monitoring on Trustpilot, Weekly FeedThe last seven days of Trustpilot reviews for three airlines, the walk stopping at the date cut - a weekly schedule that reads a page or two per brand.
TrustScore and Star Rating for Five RetailersTrustScore, stars, review totals, histogram and contact details for five online marketplaces in one free company row each, plus twenty reviews apiece.
Trustpilot Review Export in Most-Relevant OrderTwo hundred Trustpilot reviews of one brand in Trustpilot's own most-relevant order - the reviews a prospective customer actually reads first.
Review Sentiment Analysis Dataset from TrustpilotSix hundred English Trustpilot reviews of one brand across all five star bands, text required - a star-labelled corpus for sentiment analysis.

Run Trustpilot Reviews Scraper

The actor lives on the Apify Store, where the pricing tab carries the live per-row price and the input form has every field above: apify.com/kestrel/trustpilot-reviews-scraper