# Trustpilot Business Leads Scraper — Email, Phone & TrustScore (`scrapersdelight/trustpilot-business-leads-scraper`) Actor

Trustpilot business profiles as leads by category + country or domain list: published email, phone, street address, website, TrustScore, reviews, star distribution, claimed/verified flags, reply rate. Filter by TrustScore band. Only rows with a contact are charged. $0.18 per 1,000 businesses.

- **URL**: https://apify.com/scrapersdelight/trustpilot-business-leads-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 5 total users, 5 monthly users, 98.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.18 / 1,000 per business returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Trustpilot Business Leads Scraper — Email, Phone & TrustScore

Turn Trustpilot into a B2B lead list. Pick a Trustpilot **category** and a **country** (or paste a list of **domains**) and get **one row per business** — not per review — with the contact block the business published on its Trustpilot profile (**email, phone, street address, postal code, city**), its **website**, **TrustScore**, review count, **1–5 star distribution**, **claimed** and **verified** flags, **reply rate to negative reviews**, and the dates of its most recent reviews.

**$0.18 per 1,000 businesses.** With the default settings you are charged **only for businesses that publish an email or a phone number** — a business with no contact is skipped and never billed.

### Who uses it

- **Reputation-management and review-generation SaaS** (Birdeye / Podium / Reviews.io type): find businesses with a weak TrustScore, a low reply rate or few recent reviews — `maxTrustScore: 3.5`, `maxReviews: 50` — and reach them on their own published email and phone.
- **Outbound agencies**: every e-commerce shop, broker, installer or agency Trustpilot lists in a category, per country, with a reachable contact.
- **B2B list brokers and data teams**: category × country business lists with Trustpilot's own id for deduplication, and a `profileUrl` for every row.
- **Competitor monitoring**: paste your competitors' domains and schedule the run to track TrustScore, star distribution and reply behaviour over time.

### What one row looks like

A real row from a run on 2026-09-23 (`categories: ["home_garden"]`, `countries: ["GB"]`), unedited:

```json
{
  "businessUnitId": "4dc3c01e00006400050fa99f",
  "name": "National Shower Spares",
  "domain": "showerspares.com",
  "website": "https://www.showerspares.com/",
  "email": "support@showerspares.com",
  "phone": "01452 619836",
  "address": "Units 16-17 Bamel Way, Gloucester Business Park, Brockworth",
  "city": "Gloucester",
  "postalCode": "GL3 4BH",
  "countryCode": "GB",
  "countryName": "United Kingdom",
  "hasContact": true,
  "trustScore": 4.9,
  "stars": 5,
  "reviewCount": 62281,
  "reviewsLast12Months": 5084,
  "starDistribution": { "five": 58993, "four": 2219, "three": 386, "two": 182, "one": 501 },
  "primaryCategory": "Bathroom Remodeler",
  "categories": [
    { "id": "bathroom_remodeler", "name": "Bathroom Remodeler", "isPrimary": true },
    { "id": "bathroom_supply_store", "name": "Bathroom Supply Store", "isPrimary": false },
    { "id": "plumbing_supply_store", "name": "Plumbing Supply Store", "isPrimary": false }
  ],
  "categoryBreadcrumb": ["Home & Garden", "Bathroom & Kitchen", "Bathroom Remodeler"],
  "isClaimed": true,
  "claimedDate": "2014-05-20T12:29:39.000Z",
  "isVerifiedCompany": true,
  "verification": { "paymentMethod": false, "userIdentity": false, "google": true, "persona": false },
  "usesPaidFeatures": true,
  "isCollectingReviews": true,
  "isClosed": false,
  "consumerAlert": false,
  "replyPercentage": 99.4,
  "averageDaysToReply": 2.25,
  "negativeReviewsTotal": 160,
  "negativeReviewsReplied": 159,
  "lastReplyToNegativeReview": "2026-09-22 15:46:48 UTC",
  "lastReviewDate": "2026-09-23T01:09:17.000Z",
  "recentReviews": [
    { "date": "2026-09-23T01:09:17.000Z", "rating": 5, "title": "Product quality good", "replied": false },
    { "date": "2026-09-23T00:34:16.000Z", "rating": 5, "title": "Excellent service all round spoke to…", "replied": false },
    { "date": "2026-09-22T23:39:00.000Z", "rating": 5, "title": "Excellent service", "replied": false }
  ],
  "facebookUrl": "https://www.facebook.com/NationalShowerSpares",
  "logoUrl": "https://s3-eu-west-1.amazonaws.com/tpd/logos/4dc3c01e00006400050fa99f/0x0.png",
  "profileUrl": "https://www.trustpilot.com/review/showerspares.com",
  "profileDetails": true,
  "source": { "type": "category", "category": "bathroom_kitchen", "country": "GB", "location": null },
  "scrapedAt": "2026-09-23T06:07:10.238Z"
}
```

### Every field

| Field | What it is |
|---|---|
| `businessUnitId` | Trustpilot's own id for the business — stable, use it to dedupe across runs. Never billed twice in one run. |
| `name`, `domain` | Display name and the domain Trustpilot files the profile under. |
| `website` | The business's website as Trustpilot lists it. |
| `email`, `phone` | From the business's published **Contact info** block, exactly as published (phones are never reformatted or "repaired"). `null` when not published. |
| `address`, `city`, `postalCode` | Street address, city and postal code from the same block. |
| `countryCode` | Trustpilot's country for the business (ISO-2). |
| `countryName` | Country of the published contact address (only when the business published one). |
| `hasContact` | `true` when there is an email or a phone. |
| `trustScore`, `stars`, `reviewCount` | TrustScore (0–5, one decimal), star rating shown (half steps) and total reviews. |
| `reviewsLast12Months` | Reviews received in the last 12 months — a direct read of how active the profile is. |
| `starDistribution` | Count of 5/4/3/2/1-star reviews (sums to `reviewCount`). |
| `primaryCategory`, `categories`, `categoryBreadcrumb` | Trustpilot categories (each with Trustpilot's `rank` of the business in it, `outOf` businesses ranked) and the category path. |
| `isClaimed`, `claimedDate` | Whether the business has claimed its profile, and when. |
| `isVerifiedCompany`, `verification` | Trustpilot's business verification (payment method, identity, Google, Persona). |
| `usesPaidFeatures` | Whether the business is on a paid Trustpilot plan. |
| `isCollectingReviews`, `isClosed`, `consumerAlert` | Actively inviting reviews · closed/temporarily closed · Trustpilot has posted a consumer alert. |
| `replyPercentage`, `averageDaysToReply`, `negativeReviewsTotal`, `negativeReviewsReplied`, `lastReplyToNegativeReview` | How the business handles negative reviews. |
| `lastReviewDate`, `recentReviews` | Newest review date and the latest N reviews (date, rating, title, whether the business replied). All languages. |
| `facebookUrl`, `logoUrl` | Facebook page linked on the profile; logo. |
| `previouslyClaimed`, `hasSubscription`, `usesAiReplies`, `hasCollectedIncentivisedReviews` | Claimed before (even if not now) · on a Trustpilot subscription · replies with Trustpilot's AI responses · has collected incentivised reviews. |
| `locationsCount` | Number of branch locations on the profile. |
| `promotionTitle`, `sellingPoints` | The business's own tagline and selling points from its profile (paid profiles). |
| `reviewsByLanguage` | Review counts per language, e.g. `{"en": 1578342, "de": 30}`. |
| `similarBusinesses` | Up to 8 competitors Trustpilot shows beside the profile (name, domain, TrustScore, reviews) — ready-made lookalike leads. |
| `profileUrl` | The Trustpilot profile. |
| `profileDetails` | `true` when the profile page was read (all rows by default). |
| `source` | Which category/country (or domain input) produced the row. |

### Inputs

| Input | Default | What it does |
|---|---|---|
| `categories` | `["electronics_store"]` | Trustpilot category ids from the URL `trustpilot.com/categories/<id>` (a full URL works too). Broad branches such as `home_garden` are fine — see the 10,000 cap below. |
| `countries` | `["GB"]` | ISO-2 codes; each category is walked once per country. |
| `location` | — | A city, using Trustpilot's own location filter. |
| `domains` | — | Look up specific businesses by domain, website URL or Trustpilot profile URL. |
| `onlyWithContact` | `true` | Deliver and charge only businesses with an email or phone. |
| `requireEmail` / `requirePhone` | `false` | Stricter contact filters. |
| `minTrustScore` / `maxTrustScore` | `0` / `5` | TrustScore band — e.g. `maxTrustScore: 3.5` for businesses that need reputation help. |
| `minReviews` / `maxReviews` | `0` / `0` (no bound) | Review-count band. |
| `claimedOnly` | `false` | Only claimed profiles. |
| `includeProfileDetails` | `true` | Read each profile for the claimed flag, star distribution, reply rate and recent reviews. Off = listing fields only, faster. |
| `recentReviews` | `3` | Recent reviews per business (0–20). |
| `maxResults` | `50` | Stop after this many delivered businesses (0 = no limit). |
| `maxPagesPerListing` | `0` (all) | Page cap per category × country (20 businesses per page). |
| `splitCappedCategories` | `true` | Walk sub-categories when Trustpilot caps a listing at 10,000. |
| `concurrency` | `10` | Pages read in parallel (1–12). |
| `proxyConfiguration` | none | Not needed — see "How it works". |

Filters run **before** anything is charged, and TrustScore/review filters run before a profile page is even fetched.

### Pricing

**$0.18 per 1,000 businesses** (`business-lead` event, $0.00018 each). No start fee.

- Charged once per business delivered to your dataset.
- **Never charged**: businesses without an email or phone (with the default `onlyWithContact`), duplicates (a business in two sub-categories or two of your domains), domains that have no Trustpilot profile, businesses removed by your filters, and pages Trustpilot would not serve.
- Delivery and billing are one atomic step, so a spending limit you set stops delivery exactly at the limit — you never receive rows you did not pay for, or pay for rows you did not receive.

An empty-input run delivers 50 businesses: **$0.009**.

### How much contact data to expect — measured, not promised

The contact block exists only on profiles the business has **claimed** and chosen to fill in. How many rows carry it depends heavily on **which** businesses you pull, so here are the three frames we measured on 2026-09-23 (all counts over every business, including those with no contact):

| Frame | Businesses | Email | Phone | Email or phone | Street address | Claimed |
|---|---:|---:|---:|---:|---:|---:|
| Top of the listing (first page of `electronics_store`, `plumber`, `car_dealer` in US, GB, DE) | 179 | 79.3% | 73.7% | 82.7% | 72.6% | 93.3% |
| Random profiles from Trustpilot's own sitemap | 150 | 41.3% | 30.0% | 41.3% | 35.3% | 58.7% |
| An entire category, every page (`electronics_store`, listing fields) | US 3,309 · DE 788 | 18.3% · 12.9% | 14.1% · 9.6% | — | 21.4% · 15.2% | — |

So: contact fill runs from **~13% to ~83%** depending on depth into the listing. Trustpilot orders a category by its own "recommended" ranking, which puts claimed, active businesses first; the long tail is mostly unclaimed profiles with no contact at all (0 of 62 unclaimed profiles in the sitemap sample had one). **That is why the default charges only rows with a contact** — you pay for leads, not for empty profiles.

Profile-level fields are always present when the profile is read: website, TrustScore, review count, star distribution, reviews in the last 12 months and last review date were 100% filled in every frame.

The run's `RUN_SUMMARY` record (Storage → Key-value store) reports the fill of every field for **your** run, how many businesses Trustpilot stated vs how many unique ones were collected per listing, and every business that was skipped and why.

### How it works

Every page on trustpilot.com sits behind an AWS WAF "Verifying Connection" check that answers plain HTTP clients with HTTP 403 — from home, datacenter and residential IPs alike. The actor opens **one** real Chromium page, lets it pass the check (about 2 seconds), then reads every listing and profile over plain HTTP carrying the resulting cookie. It re-runs the check only if Trustpilot asks again. No login, no Trustpilot account, no proxy needed; in our tests 188 consecutive pages were served on one check with zero challenges.

Data comes from the JSON Trustpilot embeds in its own pages (the same data the page renders), so field values are exactly what the profile shows.

**The 10,000 cap.** Trustpilot shows at most 500 pages × 20 = 10,000 businesses per category listing (page 501 is empty). When a listing reports that cap the actor walks the category's sub-categories instead (e.g. Trustpilot counts 23,985 businesses in `home_garden` but its GB listing stops at 10,000, so its 10 sub-categories are walked one by one), deduplicating on `businessUnitId`. A leaf category that is itself capped is walked to its 10,000 and the run summary marks it `cappedBySite`.

**Completeness check.** When a listing is walked to its last page, the unique businesses collected are compared with the count Trustpilot states. Measured: 3,309 of 3,327 (99.5%) for `electronics_store` US and 788 of 789 for DE — a handful of businesses shift between pages while the walk runs. A walk that falls below 97% stops the run with an error instead of delivering a short list as if it were complete.

### Data limits

- **Contact data is what the business typed in.** The "Contact info" block is a Trustpilot convention, not a legal register: businesses choose what to publish, and some publish a support mailbox or a shared number (two sister shops can list the same phone). For EU businesses it often matches their legal notice (Impressum), but nothing guarantees that.
- **No contact on unclaimed profiles.** Measured above.
- **Trustpilot's own addresses never ship as a business's**: any email or website on a Trustpilot domain is dropped, and the run fails loudly if one ever reaches the output (the run summary's `platformContactsLeaked` is 0 in every test run).
- **Phones are verbatim.** We do not reformat to E.164, because Trustpilot has no reliable per-number country and a "repaired" number is a guess.
- **Listing order is Trustpilot's.** It ranks by its own relevance; a full walk may miss or repeat under 1% of businesses when rankings shift mid-walk (repeats are never charged twice).
- **Recent reviews are a sample** (dates, stars, titles) to show activity — this actor sells the business row, not review text. For full review text use a reviews scraper.
- **Profile-only fields** (`isClaimed`, `starDistribution`, reply behaviour, recent reviews) are `null` when `includeProfileDetails` is off, and for the rare listing row whose profile could not be read (the row is still delivered with `profileDetails: false`).

### Source

The public pages of www.trustpilot.com (category listings and business profile pages), read without logging in. Some rows belong to sole traders, so a name, email or phone can be personal data — comply with GDPR, CCPA and other data-protection rules when you use it.

### FAQ

**Can I get every business in a big branch like `home_garden`?** Yes — leave `splitCappedCategories` on and `maxResults: 0`. The run walks the sub-categories past Trustpilot's 10,000-per-listing cap.

**How do I find businesses with bad ratings?** `maxTrustScore: 3` (and maybe `minReviews: 20` so the score means something). The listing is ordered best-first, so expect the run to read many listing pages per delivered row; listing pages are cheap and never charged.

**Why do some rows have `countryCode` and `countryName` that differ?** `countryCode` is the country Trustpilot files the business under; `countryName` is the country of the contact address the business published. A German shop with a UK returns address shows both.

**What if a domain has no Trustpilot profile?** It is listed under `notFoundOnTrustpilot` in the run summary and not charged.

# Actor input Schema

## `categories` (type: `array`):

Category ids exactly as they appear in the Trustpilot URL trustpilot.com/categories/<id> — e.g. "electronics_store", "plumber", "car_dealer", "web_design_agency", or a whole branch such as "home_garden" or "electronics_technology". A full category URL is accepted too. When Trustpilot caps a listing at 10,000 businesses the actor walks its sub-categories instead. Leave empty to use only the Domains list.

## `countries` (type: `array`):

2-letter ISO country codes. Trustpilot scopes every category listing to one country, so each category is walked once per country: "GB", "US", "DE", "FR", "ES", "IT", "NL", "DK", "SE", "NO", "AU", "CA", "IE", …

## `location` (type: `string`):

Narrow each category listing to a city, as Trustpilot's own location filter does (e.g. "London", "Manchester", "Berlin"). Leave empty for the whole country.

## `domains` (type: `array`):

Look up specific businesses instead of (or as well as) walking categories: a website domain ("thriftbooks.com", "https://www.zalando.de") or a Trustpilot profile URL ("https://www.trustpilot.com/review/www.thriftbooks.com"). A domain with no Trustpilot profile is reported in the run summary and never charged.

## `onlyWithContact` (type: `boolean`):

On (default): deliver — and charge — only businesses whose Trustpilot profile publishes an email address or a phone number. Businesses without either are skipped and never charged. Turn off to also receive businesses that publish no contact (still with website, TrustScore, reviews and flags).

## `requireEmail` (type: `boolean`):

Deliver only businesses that publish an email address.

## `requirePhone` (type: `boolean`):

Deliver only businesses that publish a phone number.

## `minTrustScore` (type: `number`):

Only businesses with a TrustScore at or above this value (0–5). Leave at 0 for no lower bound.

## `maxTrustScore` (type: `number`):

Only businesses with a TrustScore at or below this value (0–5) — e.g. 3.5 to target businesses with a weak rating for reputation-management outreach. Leave at 5 for no upper bound.

## `minReviews` (type: `integer`):

Only businesses with at least this many Trustpilot reviews. 0 = no lower bound.

## `maxReviews` (type: `integer`):

Only businesses with at most this many reviews — e.g. 50 to find businesses that are barely collecting reviews. 0 = no upper bound.

## `claimedOnly` (type: `boolean`):

Deliver only profiles the business has claimed on Trustpilot (read from the profile page).

## `includeProfileDetails` (type: `boolean`):

On (default): each business's Trustpilot profile page is read for its claimed flag and claim date, verification, star distribution (1–5), reviews in the last 12 months, reply rate to negative reviews, last review date, recent reviews, country code and Facebook page. Off: rows come from the category listing alone (name, website, email, phone, address, TrustScore, review count, categories) and the run is faster. Domain look-ups always read the profile.

## `recentReviews` (type: `integer`):

How many of the business's most recent reviews to include (date, star rating, title, whether the business replied) — a quick read of how active and how well-rated it is right now. 0–20.

## `maxResults` (type: `integer`):

Stop after delivering this many businesses in total. 0 = no limit (a full category walk can be tens of thousands of rows).

## `maxPagesPerListing` (type: `integer`):

Trustpilot lists 20 businesses per page. 0 = walk every page.

## `splitCappedCategories` (type: `boolean`):

Trustpilot shows at most 10,000 businesses (500 pages) per category listing. On (default): when a listing hits that cap, the actor walks the category's sub-categories instead, so large branches are covered past the cap. A business in two sub-categories is delivered once.

## `concurrency` (type: `integer`):

How many Trustpilot pages are read at once (1–12).

## `proxyConfiguration` (type: `object`):

Not needed: Trustpilot answers Apify's network directly once the actor's browser has passed its connection check. Set a proxy only if your runs start reporting blocked pages.

## Actor input object example

```json
{
  "categories": [
    "electronics_store"
  ],
  "countries": [
    "GB"
  ],
  "onlyWithContact": true,
  "requireEmail": false,
  "requirePhone": false,
  "minTrustScore": 0,
  "maxTrustScore": 5,
  "minReviews": 0,
  "maxReviews": 0,
  "claimedOnly": false,
  "includeProfileDetails": true,
  "recentReviews": 3,
  "maxResults": 10,
  "maxPagesPerListing": 0,
  "splitCappedCategories": true,
  "concurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `businesses` (type: `string`):

The dataset of Trustpilot business profiles (one item per business).

## `runSummary` (type: `string`):

Measured totals: Trustpilot-stated vs unique businesses per listing, per-field fill, what was not charged and why, transport stats.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "categories": [
        "electronics_store"
    ],
    "countries": [
        "GB"
    ],
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/trustpilot-business-leads-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "categories": ["electronics_store"],
    "countries": ["GB"],
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/trustpilot-business-leads-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "categories": [
    "electronics_store"
  ],
  "countries": [
    "GB"
  ],
  "maxResults": 10
}' |
apify call scrapersdelight/trustpilot-business-leads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/trustpilot-business-leads-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/oELrLHdNUavO3ohok/builds/y0YpGEa8ftEI4MGea/openapi.json
