Trustpilot Scraper: Reviews, Star Breakdown & Company Stats avatar

Trustpilot Scraper: Reviews, Star Breakdown & Company Stats

Pricing

from $1.20 / 1,000 results

Go to Apify Store
Trustpilot Scraper: Reviews, Star Breakdown & Company Stats

Trustpilot Scraper: Reviews, Star Breakdown & Company Stats

Scrape Trustpilot business profiles and reviews on any country domain: TrustScore, the exact 1-5 star distribution in counts and percentages, reply rate, claim and verification status, contact block, plus reviews with verification badge and company reply. Keyword, category sweep or pasted links.

Pricing

from $1.20 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

Scrape Trustpilot business profiles and their reviews, on any Trustpilot country domain.

Most Trustpilot scrapers give you a list of review rows. This one also gives you the numbers that make those reviews mean something: the exact 1-5 star distribution, the negative and positive share, how often the company actually replies and how fast, whether the profile is claimed, and the full public contact block. Point it at one company, a whole category, or a keyword search.

What you get

Two row types in one dataset, told apart by kind.

kind: "business" - the company profile

FieldWhat it is
identifyingName, displayName, profileUrl, websiteUrl, logoUrlidentity
trustScore, starsthe headline score (0-5) and the rounded star rating
numberOfReviews, numberOfReviewsLast12Monthsvolume, all time and recent
ratingDistributionexact counts per star: {oneStar, twoStar, threeStar, fourStar, fiveStar}
ratingDistributionPercentthe same split as percentages
negativeReviewShare, positiveReviewShare1-2 star and 4-5 star share of all reviews
replyPercentage, averageDaysToReplyhow often, and how fast, the company answers
negativeReviewsWithRepliesCount, totalNegativeReviewsCounthow many complaints got an answer
isClaimed, claimedDate, isClosed, isTemporarilyClosed, isCollectingReviewsprofile status
verifiedByGoogle, verifiedPaymentMethod, verifiedUserIdentity, hasCollectedIncentivisedReviewstrust signals
contactEmail, contactPhone, contactAddress, contactCity, contactZipCode, countryCodethe public contact block
primaryCategoryName, categories, breadcrumbTopLevel/MidLevel/BottomLevelclassification
reviewLanguageshow many reviews exist per language
reviewsScraped, verifiedReviewsScraped, verifiedShareOfScraped, repliedShareOfScrapedstats over the reviews this run actually read (a sample, and labelled as one)

kind: "review" - one row per review

reviewId, reviewUrl, rating, title, text, language, likes, source, isVerified, verificationLevel, verificationSource, experiencedDate, publishedDate, updatedDate, hasReply, replyText, replyPublishedDate, consumerDisplayName, consumerCountryCode, consumerNumberOfReviews, plus all available business enrichment columns, including TrustScore, star distribution, reply statistics, profile status, categories, public contact details and review-sample statistics. These fields repeat on every review row so a review export stands on its own. Review IDs, ratings, text and reviewer fields remain specific to that review. Missing source values stay empty.

Only what the public profile page itself shows is collected. No account, no login, nothing behind a sign-in wall.

Modes

Search mode finds businesses for you.

  • searchType: "keyword" plus query - Trustpilot's own business search, walked forward.
  • searchType: "category" plus category - sweeps every business in a Trustpilot category (the id from the category URL, e.g. book_store).

URL mode reads exactly what you paste, one entry per line, mixed freely:

https://www.trustpilot.com/review/bookshop.org
bookshop.org
https://www.trustpilot.com/categories/book_store
https://www.trustpilot.com/search?query=nike
https://de.trustpilot.com/review/www.example-shop.de

A bare company domain works: it is the same thing Trustpilot uses in its own profile URL.

Review filters (applied by Trustpilot, not by throwing rows away)

Every filter below is pushed into Trustpilot's own review URL, so a narrowed run reads fewer pages instead of downloading everything and discarding most of it.

InputEffect
reviewStarskeep only 1/2/3/4/5-star reviews (multi-select)
reviewLanguageall by default - see the note below
reviewSortrecency or relevance
verifiedOnlyonly reviews Trustpilot marks verified
reviewsSincelast30days / last3months / last6months / last12months
reviewKeywordonly reviews whose text matches a keyword, e.g. refund

Why reviewLanguage defaults to all. Trustpilot itself defaults to the visitor's language and hides the rest. On one profile checked while building this actor, the company had 45,986 reviews but a default English visitor was shown only 30,234 of them. This actor asks for every language unless you narrow it, so numberOfReviews and the review rows agree.

Limits and cost controls

  • maxItems - the run cap, counting business rows and review rows together. Default 50, 0 = no limit.
  • maxReviewsPerBusiness - a per-business budget (20 reviews per page). Default 20, 0 = every review.
  • maxPages - upper bound per category / search / review list. Default 0 = as deep as Trustpilot serves.
  • minTrustScore - skip businesses below a TrustScore.
  • fetchDetails - Search mode only. Off, businesses ship with just what the listing card carries.

Resume and recurring updates

  • resumeFromRunId continues ONE interrupted run. Paste the previous run or dataset id; rows it already collected are not returned and not billed again.
  • incrementalMode is for a schedule. The first run marks everything NEW; later runs return only NEW, UPDATED and REAPPEARED, with changedFields, firstSeenAt and lastSeenAt. emitUnchanged and emitExpired add UNCHANGED / EXPIRED rows (and bill them), both off by default. EXPIRED is only produced after a run that fully scanned the tracked scope: never when maxItems capped it, never when a page could not be read, and never on a resumed run.

State is kept separately per search and per review-filter setup, so a 5-star campaign never mixes its baseline with an all-stars one. stateKey lets you name a campaign or deliberately share one.

Send results into your apps (MCP connectors)

Set mcpConnectors to pipe every returned row into the tools you already use over Model Context Protocol. Authorize a connector under Apify → Settings → API & Integrations, then select it here. Notion gets a page per item (set notionParentPageUrl); other connectors get a best-effort write or digest. maxNotifyListings caps how many rows go to each connector. None of this changes the dataset.

Connection

Trustpilot refuses ordinary connections on every route. The actor tries the connection you configure in proxyConfiguration first and, only once that one has been refused on this run, switches to Apify Proxy's enhanced connection tier and stays there for the rest of the run, so the wasted first probe is paid once per run rather than once per page. Keep Apify Proxy enabled. If your plan cannot open that tier, the run fails with a clear message instead of quietly returning zero rows.

Pricing

You are charged for:

  • Result - each row returned, business profile or review.
  • Business profile enrichment - once per business returned in Search mode whose own profile page was read (that is, when fetchDetails or scrapeReviews is on). Never charged for a pasted profile link, never charged for a row incremental mode suppressed.
  • Actor Start - once per run.

Sample output (illustrative, not a real business or reviewer)

{
"kind": "business",
"recordId": "business:example-shop.test",
"identifyingName": "example-shop.test",
"displayName": "Example Shop",
"profileUrl": "https://www.trustpilot.com/review/example-shop.test",
"trustScore": 4.3,
"stars": 4,
"numberOfReviews": 1000,
"ratingDistribution": { "oneStar": 100, "twoStar": 50, "threeStar": 50, "fourStar": 200, "fiveStar": 600 },
"ratingDistributionPercent": { "oneStar": 10.0, "twoStar": 5.0, "threeStar": 5.0, "fourStar": 20.0, "fiveStar": 60.0 },
"negativeReviewShare": 15.0,
"positiveReviewShare": 80.0,
"replyPercentage": 62,
"averageDaysToReply": 2,
"isClaimed": true,
"primaryCategoryName": "Book Store",
"contactEmail": "support@example-shop.test",
"contactPhone": "(555) 010-0100",
"reviewsScraped": 20,
"verifiedShareOfScraped": 85.0,
"changeType": "NEW"
}
{
"kind": "review",
"recordId": "review:00000000000000000000000",
"reviewId": "00000000000000000000000",
"reviewUrl": "https://www.trustpilot.com/reviews/00000000000000000000000",
"businessIdentifyingName": "example-shop.test",
"rating": 5,
"title": "Sample review title",
"text": "Sample review body. This is not a real customer review.",
"language": "en",
"isVerified": true,
"verificationLevel": "verified",
"experiencedDate": "2026-01-01T00:00:00.000Z",
"publishedDate": "2026-01-02T00:00:00.000Z",
"hasReply": true,
"replyText": "Sample company reply.",
"consumerDisplayName": "Sample Reviewer",
"consumerCountryCode": "US",
"changeType": "NEW"
}

Notes

  • Reviews are public content. Reviewer rows carry only what Trustpilot itself publishes on the page: a display name, a country, a public review counter and the review text. Nothing is collected that needs an account, and nothing is inferred beyond the page.
  • verifiedShareOfScraped and repliedShareOfScraped describe the reviews this run read, not the whole review base. ratingDistribution is exact, straight from Trustpilot.
  • Country domains (uk., de., fr., nl., dk., it., es., ...) share one grammar. Set site, or just paste a link on that domain.

Local development

python3.12 -m venv .venv && .venv/bin/pip install -r requirements.txt
PATH=.venv/bin:$PATH apify run --purge
.venv/bin/python -m pytest tests/ -q