WEBCOMPANYAI API MCP READY

Trustpilot Reviews API

Trustpilot company reviews as structured JSON, shaped for watching a rating move rather than reading it once. Three things make that possible: the date of experience is kept separate from the posting date, replies the business posted come back as structured entries rather than buried text, and every row carries the company's full 5-to-1 star split with an absolute count and a percentage share at each level. Send up to 200 company review URLs per run, pay per review returned, MCP-ready for Claude and other agents.

MEDIAN LAGon demand
FIELDS35

Input parameters

PARAMETERTYPEREQDEFAULTDESCRIPTION
companyUrls string[] yes Company review-page URLs, for example https://www.trustpilot.com/review/example.com. A bare domain such as example.com works as shorthand. Up to 200 companies per run; anything past the cap is not collected. There is no keyword search or company discovery mode, so you build the company list and feed it in.
maxReviewsPerCompany integer no 100 Reviews returned per company, from 1 to 1000. The cap is applied at the source, so nothing beyond it is collected or billed, which makes this the ceiling on what a run can cost. — drives your bill
datePosted enum no Restrict to reviews posted inside one recent window. The four accepted values are Last 30 days, Last 3 months, Last 6 months and Last 12 months. Leave it empty for all reviews. The source offers these fixed windows only, not calendar start and end dates, so a narrower slice means pulling the window that contains it and filtering afterwards.

Output schema

FIELDTYPEDESCRIPTIONNULLABLE
result_type string review or error, so a company URL that returned nothing stays visible in the same dataset instead of vanishing. no
reviewId string Stable identifier for the review on the source site. Upsert on this to make a daily re-run idempotent. no
reviewTitle string Headline the reviewer gave. Long titles arrive truncated the way the source truncates them. yes
reviewContent string Full review body. yes
reviewRating integer Star rating this reviewer gave, 1 to 5. no
reviewDate string ISO 8601 timestamp of when the review was posted. no
dateOfExperience string When the reviewer says the interaction actually happened. Frequently months earlier than the posting date, and usually the more meaningful axis for trend work. yes
isVerifiedReview boolean Whether the source verified this review. no
reviewUsefulCount integer How many people marked the review useful. yes
reviewReplies array Replies the business posted to this review, each with its text and date. The key is absent entirely when there is no reply, which is what makes an unanswered-complaint filter a one-liner. yes
reviewUrl string Direct link to the individual review. no
summary string One-line plain-language digest of the row, for example: 5-star verified review of DuGood Credit Union by David Werner. Lets an agent read a record without post-processing. no
reviewerName string Display name of the reviewer as shown publicly. yes
reviewerLocation string Two-letter country code the reviewer posted from. Country only, nothing finer. yes
reviewerTotalReviews integer How many reviews this person has posted overall, which is the weighting signal for telling an established reviewer from a one-time account. yes
companyName string Name of the reviewed business. no
companyUrl string The company review page this review came from. no
companyWebsite string The business's own website. yes
companyCategory string Primary category, returned as the source's own slug rather than a display label, for example credit_union. Use categoryPath for readable names. yes
companyActivities array Every activity category the business is listed under, in display form. yes
categoryPath array Category breadcrumb, broadest first, for example Money & Insurance, Credit & Debt Services, Credit Union. yes
companyOverallRating number The business's headline star rating across all reviews. Repeated on every row, so a one-review pull still gives you the current score. no
companyRatingLabel string Word form of the overall rating, for example Excellent. yes
companyTotalReviews integer How many reviews the business has in total, which is the denominator the star percentages are computed against. no
companyIsVerified boolean Whether the business itself is verified on the source site. Often false even for companies that publish full contact details. no
starBreakdown object The 5-to-1 split as star5 through star1, each with a count and a percent. Kept as one object because the source's own keys cannot be camelCase field names. no
companyEmail string Contact email the business publishes on its profile. Missing for plenty of companies. yes
companyPhone string Contact phone the business publishes on its profile, in whatever format it typed. yes
companyLocation string Address block as published, delivered as one unparsed string that sometimes repeats the email and phone before the street address. Treat it as text, not as structured address fields. yes
companyCountry string Two-letter country code the business is registered in. yes
companyAbout string The business's own description of itself, useful mainly as context for a model. yes
companyLogo string Logo image URL. yes
error_message string Plain-language reason a company URL produced no reviews. Present on error rows only. yes
error_type string Machine-readable error category, for example CollectionError. Present on error rows only. yes
fetched_at string UTC timestamp when the row was collected, which is what turns a stack of runs into a dated rating series. no

Worked examples

Basic — one company, the default 100 reviews
{
  "companyUrls": ["https://www.trustpilot.com/review/www.dugood.org"]
}
Rating snapshot on the cheap — one review buys the whole company block, including the star split
{
  "companyUrls": ["https://www.trustpilot.com/review/www.dugood.org"],
  "maxReviewsPerCompany": 1
}
Scheduled monitoring — recent window only, so a daily re-run stays small
{
  "companyUrls": ["https://www.trustpilot.com/review/www.dugood.org"],
  "maxReviewsPerCompany": 200,
  "datePosted": "Last 30 days"
}
Competitor set — bare domains as shorthand, joined on companyName in the export
{
  "companyUrls": ["example.com", "competitor-one.com", "competitor-two.com"],
  "maxReviewsPerCompany": 100
}
Backfill — the per-company ceiling, for the one-off history load before you schedule
{
  "companyUrls": ["https://www.trustpilot.com/review/www.dugood.org"],
  "maxReviewsPerCompany": 1000
}
Quarterly complaint sweep — pull three months and filter locally on reviewRating and missing reviewReplies
{
  "companyUrls": ["example.com", "competitor-one.com"],
  "maxReviewsPerCompany": 500,
  "datePosted": "Last 3 months"
}
POWER-USER TIP
One review buys the entire rating distribution — Every review row repeats the company block, so maxReviewsPerCompany set to 1 returns companyOverallRating, companyTotalReviews and the full star5-to-star1 breakdown with counts and percentages for the price of a single review. That is the cheapest possible daily reputation ping across a large competitor list, and it is exactly what you want on a schedule once the backfill is done.
POWER-USER TIP
Bucket by dateOfExperience, not reviewDate — The two dates drift apart badly. In a verified run against a real company, one review posted on 2026-07-13 described an experience from 2025-08-07, and the next one posted 2026-06-03 described 2025-11-29. Charting complaints by posting date would have put both in the wrong quarter. Note the tradeoff: datePosted filters on the posting date, so an experience-date analysis needs the wider window pulled and filtered afterwards.
POWER-USER TIP
reviewReplies is absent, not empty — When a business never replied, the key is missing from the row rather than present as an empty list. Your unanswered-complaint filter is therefore an absence check, not a length check. In Python that is "not item.get('reviewReplies')" combined with a low reviewRating; in SQL, store a boolean has_reply at load time.
POWER-USER TIP
Cost is companies multiplied by reviews — Only maxReviewsPerCompany carries the cost-driver flag, but spend is the product of both inputs. A full 200 companies at the 1000-review ceiling is 200,000 billable reviews in one run. Set a run-level max charge on the platform before your first big backfill, and keep recurring runs on a datePosted window.
POWER-USER TIP
Company contact fields arrive as published, not parsed — companyLocation is a single string built from whatever the business typed, and in practice it can repeat the email and phone ahead of the street address. companyCategory comes back as the source's slug, not a display label. If you need clean geography or readable categories, use companyCountry and categoryPath instead of parsing those two.

Coverage

200
companies per run — review-page URLs or bare domains
1,000
reviews per company — capped at the source, never billed past the cap
5
star levels, each with count and percent — star5 · star4 · star3 · star2 · star1
35
fields per row — review · reviewer · company · star split · error
4
posted-within windows — 30 days · 3 months · 6 months · 12 months
2
dataset views — reviews overview · reputation snapshot

Tasks

Saved runs with the inputs already filled in — each one a standalone page and a working configuration example.

Request a task →

Written about this source

Walkthroughs, worked examples and posts about this source.

Code

curl

curl -X POST "https://api.apify.com/v2/acts/johnvc~trustpilot-reviews-api/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"companyUrls":["https://www.trustpilot.com/review/www.dugood.org"],"maxReviewsPerCompany":100,"datePosted":"Last 30 days"}'

Python

from apify_client import ApifyClient

client = ApifyClient("APIFY_TOKEN")
run = client.actor("johnvc/trustpilot-reviews-api").call(
    run_input={
        "companyUrls": ["https://www.trustpilot.com/review/www.dugood.org"],
        "maxReviewsPerCompany": 100,
        "datePosted": "Last 30 days",
    }
)

for item in client.dataset(run.default_dataset_id).iterate_items():
    if item.get("result_type") != "review":
        print("skipped:", item.get("error_message"))
        continue
    # reviewReplies is absent, not empty, when nobody replied
    unanswered = item["reviewRating"] <= 2 and not item.get("reviewReplies")
    print(
        item["reviewRating"],
        item.get("dateOfExperience"),
        item["reviewTitle"],
        "UNANSWERED" if unanswered else "",
    )

MCP

claude mcp add --transport http trustpilot \
  "https://mcp.apify.com/?tools=actors,docs,johnvc/trustpilot-reviews-api"

Changelog

2026-08-08 0.0.8 Rebuilt to fix a dataset field type mismatch that could abort a push; MCP access re-verified against the hosted server.
2026-08-07 Published on the Apify Store with eight worked task pages and a monthly keep-alive run.
2026-08-05 Pay-per-review pricing set at launch, with volume tiers below the list rate.

What people use it for

Alternatives

G2 Reviews API — B2B software reviews, where the reviewer is a buyer at a company rather than a consumerours Glassdoor Reviews API — employee reviews of the same business, which often explain why a customer rating slidours Yelp Reviews API and MCP — local and physical-location reviews, the better fit for a multi-site retailerours OpenTable Reviews API — restaurant reviews with a per-category rating split for food, service and ambienceours Google AI Overview API — what AI search answers say about the brand, the other half of a reputation pictureours
Trustpilot's own developer API — official and authoritative for your own business profile, and the right choice when you only need your own data; it is gated behind a business account and scoped to that account, so it cannot read a competitorcompeting
Trustpilot Reviews Scraper by getwally.net — cheaper per review and enough when all you want is the review text; it returns no company replies, no verified flag, no date of experience and no company star breakdowncompeting