🎉 Premium Proxies · 3-Day Free TrialClaim Now →
Guides

How to Scrape Trustpilot Reviews with Proxies

Learn to scrape Trustpilot reviews with proxies: extract rating, text, date, reviewer, and company replies as JSON, paginate at scale, and stay GDPR-compliant.

S SparkProxy 0 20 min read
Share
How to Scrape Trustpilot Reviews with Proxies

To scrape Trustpilot reviews reliably, you have to solve two problems most tutorials skip. Trustpilot rebuilds its HTML class names on nearly every deploy, and it also hides a clean, structured copy of every review in a JSON blob that sits right there in the page source. Chase the CSS selectors and your parser breaks within weeks. Read the JSON instead and you get the rating, review text, dates, reviewer, and the company's reply in one shot. This guide walks the full pipeline for public review data: the fields worth pulling, how to get past Cloudflare and the login wall, how to paginate to the page cap, how to prep the text for sentiment analysis, and how to stay on the right side of GDPR when reviewer names are involved. Every request runs through the SparkProxy Scraping API, so the anti-bot layer is one parameter instead of an infrastructure project you babysit.

What review data you can extract (fields reference)

A public Trustpilot review page (reachable at /review/, for example /review/sparkproxy.io) exposes a consistent set of fields per review. Because Trustpilot is a Next.js app, every one of these fields lives inside the embedded __NEXT_DATA__ JSON, which is far more stable than the visible DOM. Here is the reference set worth pulling, with the JSON key and a CSS fallback for each.

FieldJSON key (in `__NEXT_DATA__`)CSS fallback (attribute selector)Notes
Rating`rating``[data-service-review-rating]`Integer 1 to 5
Review title`title``[data-service-review-title-typography]`Short headline the reviewer wrote
Review text`text``[data-service-review-text-typography]`Body; can be empty on rating-only reviews
Date published`dates.publishedDate``time[datetime]`ISO 8601, UTC
Date of experience`dates.experiencedDate`"Date of experience" labelWhen the customer used the service
Reviewer name`consumer.displayName``[data-consumer-name-typography]`Personal data (see GDPR)
Reviewer country`consumer.countryCode``[data-consumer-country-typography]`ISO 3166-1 alpha-2
Reviewer review count`consumer.numberOfReviews``[data-consumer-reviews-count-typography]`Signal of a genuine vs throwaway account
Verification label`labels.verification`Green "Verified" badgeFlags invited vs organic reviews
Company reply`reply.message`Reply block under the review`null` when the business has not answered
Reply date`reply.publishedDate`Timestamp in the reply blockISO 8601, UTC
Review ID`id``data-review-id`Stable primary key for deduping

The review ID is the anchor. Store it as your primary key so re-running a scrape updates existing rows instead of duplicating them. The exact JSON keys are current as of mid-2026; Trustpilot can rename them, so treat the table as a starting point and inspect the blob (the next sections show a resilient way to find the array even if the path moves).

Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

Why Trustpilot is hard to scrape

Trustpilot is not the hardest target on the public web, but it has four traits that break naive scrapers.

Cloudflare in front. Trustpilot sits behind Cloudflare, which fingerprints the TLS handshake and can serve a "Checking your browser" challenge or a 403 before you ever see a review. A plain requests.get from a datacenter IP gets flagged fast.

CSS class names that churn. Trustpilot uses Next.js CSS Modules, which generate hashed class names like styles_reviewCardInner__EwDq2. That hash changes on nearly every frontend deploy, roughly every few weeks. Any scraper keyed on those classes silently returns empty fields the morning after a deploy.

A login wall on deep pages. Trustpilot serves review pages openly for roughly the first 10 pages, then starts prompting you to log in for older reviews. You cannot page past that anonymously.

Rate limiting. Request pages too fast, past roughly 20 page loads per minute, and you draw 429s and temporary blocks.

SignalWhat you will seeHow to handle it
Cloudflare challenge403 or a "Checking your browser" interstitialRoute through residential IPs (`premium_proxy=true`); add `render_js` + `stealth` if still challenged
CSS module churnClass selectors return nothing after a deployParse the `__NEXT_DATA__` JSON, not the class names
Login wallReviews stop after about 10 pages, a "Log in" prompt appearsStay within the cap; narrow with star, date, and language filters
Rate limiting429 or slowdowns past ~20 page requests/minutePace 3 to 5 seconds between pages; back off on 429

A managed scraping API absorbs the first and last of these for you. The class-churn problem is solved by reading the JSON, and the login wall is a hard limit you plan around with filters. If you want the proxy-side theory behind clearing Cloudflare, How to Avoid Getting Your Proxy Blocked goes deep on TLS fingerprinting and header consistency.

Set up the SparkProxy Scraping API

The SparkProxy Scraping API takes a target URL and handles the proxy, rotation, and anti-bot layer for you. You send one request, you get the HTML back. For Trustpilot, the parameter choice is a little different from a JavaScript-heavy site, and it saves you credits.

Here is the key point most guides miss: the reviews are server-side rendered into __NEXT_DATA__, so you do not need a headless browser to read them. The full first page of reviews is already in the initial HTML. That means you can often run with render_js=false, which is cheaper (1 credit on a rotating proxy, or 10 credits on a premium residential proxy, versus 25 for a rendered premium request). Two parameters carry the weight:

  • premium_proxy=true: routes through residential IPs, which clear Trustpilot's Cloudflare where datacenter IPs get challenged.
  • render_js=false: skip the browser, because the data is in the SSR JSON. Only turn this on (true) plus stealth=true if you hit a persistent Cloudflare challenge.

The base endpoint is https://scrape.sparkproxy.io/api/v1 and auth is a single header, X-API-Key. A minimal request in cURL:

curl -G "https://scrape.sparkproxy.io/api/v1" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "url=https://www.trustpilot.com/review/sparkproxy.io" \
  --data-urlencode "render_js=false" \
  --data-urlencode "premium_proxy=true"

Full parameter list and response fields live in the Scraping API docs. If you are weighing this against running your own residential pool, Web Scraping API vs Self-Managed Proxies lays out the trade-off.

Wrap the call so every request carries the Trustpilot-specific parameters and a page number:

import requests

API = "https://scrape.sparkproxy.io/api/v1"
API_KEY = "YOUR_API_KEY"

def fetch_reviews_page(domain: str, page: int = 1) -> str:
    """Fetch one Trustpilot review page. Reviews are server-rendered into
    __NEXT_DATA__, so render_js can stay off (cheaper). Escalate if challenged."""
    resp = requests.get(
        API,
        headers={"X-API-Key": API_KEY},
        params={
            "url": f"https://www.trustpilot.com/review/{domain}?page={page}",
            "render_js": "false",      # data is in the SSR JSON, no browser needed
            "premium_proxy": "true",   # residential IPs clear Trustpilot's Cloudflare
        },
        timeout=60,
    )
    resp.raise_for_status()
    return resp.text

Get the reviews as JSON with __NEXT_DATA__

Every Trustpilot page ships a