# TrustMate.io - Company Reviews, Ratings & Authors (`abotapi/trustmate-io-reviews-scraper`) Actor

Scrape complete company review histories from TrustMate.io. Paste company profile URLs, slugs, or domains, with support for both Polish `/opinie/` and English `/reviews/` profiles. Extract one row per review, including rating, full review text, author, date, and company details.

- **URL**: https://apify.com/abotapi/trustmate-io-reviews-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Automation, Developer tools, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 review scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## TrustMate.io Reviews Scraper

Extract full company review histories from **TrustMate.io** (trustmate.io) - the review-collection platform leading in Poland and expanding across the EU. Paste company profile URLs (Polish `/opinie/` or English `/reviews/`), bare slugs or bare domains, and get **one clean row per review** with the rating, full review text, author, date, the **company's reply**, verified flag, helpful/unhelpful votes and machine translations - plus company-level context on every row (rating distribution, response rate, category, average rating, certificates).

The scraper returns the **full review history** for each company - not just the first page of ~28 reviews the site renders.

### Highlights

- ⚡ **Full review history, not just page one.** Offset-paginates the entire service-review feed for each company.
- 🌍 **Paste any link shape.** `trustmate.io/opinie/{slug}`, `trustmate.io/en/reviews/{slug}`, `en.trustmate.io/reviews/{slug}`, or a bare slug/domain - all resolve to the same company.
- 🌐 **English text where it exists.** Each review's `translations` array carries TrustMate's machine translations (see the note below on what "English profile" really means).
- 🗣️ **Company replies included.** See how each company responded to its reviewers - with the reply timestamp and a computed response time in hours.
- ⭐ **Company context on every row.** Rating distribution per star level, response rate, recommend percentage, category, certificates, social links, phone/address where public.
- 🔍 **Filters + sort, in both modes.** `minRating` narrows the feed server-side (785 → 730 → 714 reviews for 1+ / 4+ / 5 on `trustmate-io`) and `sortBy` orders it (newest/oldest/highest/lowest rating/recently updated) exactly like the site. Both apply whether you paste companies or profile links.
- 🔁 **Resume + Incremental mode.** `resumeFromRunId` continues an interrupted run; Incremental mode remembers your scope itself and returns only NEW / UPDATED / REAPPEARED / EXPIRED reviews between scheduled runs.
- 💸 **Pay per result.** Transparent per-review pricing; cap any run with `maxItems`.

### Input

#### Search mode (default)

| Field | Default | Description |
|---|---|---|
| `mode` | `search` | `search` - paste companies; `urls` - paste profile links. Both accept the same entry shapes. |
| `companyUrls` | `["https://trustmate.io/opinie/trustmate-io"]` | Company profile URLs, bare slugs or bare domains. Mixed freely; each resolves to its review feed. |

#### URL mode

| Field | Default | Description |
|---|---|---|
| `startUrls` | `["https://trustmate.io/opinie/trustmate-io"]` | Company profile URLs / slugs / domains. Mix Polish and English links. |

#### Filters - these apply to BOTH search and URL mode

Both fields are read before the mode branch and handed to the same review-feed walk for every
company, so they narrow and order the results identically whether the company came from Search
mode or from a pasted profile link.

| Field | Default | Description |
|---|---|---|
| `minRating` | `1` | Only reviews with at least this star rating (1-5). Measured narrowing, see the table below. |
| `sortBy` | `newest` | `newest` / `oldest` / `ratingDesc` / `ratingAsc` / `recentlyUpdated`. Pinned reviews float above the sort, mirroring the site. |

**`minRating` measured against the live API** (account `trustmate-io`, id 4575, `language=pl`,
2026-08-10 - `grades[]` is sent as a repeated query parameter and the feed's own `totalCount`
changes with it, so this is a server-side narrowing, not a client-side drop):

| `minRating` | `grades[]` sent | `totalCount` returned |
|---|---|---|
| `1` (default) | 1,2,3,4,5 | **785** |
| `4` | 4,5 | **730** |
| `5` | 5 | **714** |
| *(1 only, for contrast)* | 1 | **39** |

> **About "English profiles" - read this before you expect an English data set.**
> TrustMate's English URLs are a UI skin, not a second review feed. Measured on 2026-08-10:
> `https://trustmate.io/en/reviews/{slug}` **302-redirects to** `https://trustmate.io/opinie/{slug}`,
> and the API's `language=en` feed returns the **same reviews with the same Polish `body` text**
> (785 reviews on `language=pl` vs 784 on `language=en`, identical first review id). Passing an
> English link therefore returns the same rows as the Polish one - it does **not** translate the
> corpus. The actual English text lives per review in the **`translations`** array (keep
> `includeTranslations` on to get it). This actor deliberately does not run a second walk for
> "the English profile", because there is no second profile to walk.

#### Output and limits

| Field | Default | Description |
|---|---|---|
| `maxItems` | `20` | **The cap.** Total review rows across all companies. Leave empty for unlimited. |
| `maxPagesPerCompany` | `0` | Optional per-company page cap (~100 reviews/page). Leave empty for unlimited - the run stops at Max Items. |
| `includeTranslations` | `true` | Include the `translations` array (machine translations of each review body). |

#### Resume & recurring updates

| Field | Default | Description |
|---|---|---|
| `resumeFromRunId` | - | Continue one specific interrupted run - reviews already collected in that run/dataset are skipped. |
| `incrementalMode` | `false` | Recurring monitoring: remember this scope's reviews and return only what changed (NEW / UPDATED / REAPPEARED / EXPIRED). State is keyed on your scope automatically, or on a manual `stateKey`. |
| `stateKey` | - | Name the incremental baseline (run two campaigns over the same companies). |
| `emitUnchanged` / `emitExpired` | `false` | Incremental mode extras - return (and bill) unchanged rows / expired rows. |

#### Detail enrichment (optional surcharge)

| Field | Default | Description |
|---|---|---|
| `fetchDetails` | `false` | Fetch each company's public profile page and attach schema.org profile blocks, social links, logo and meta descriptions to every review row. Billed per review row via the `detail-enrichment` event. |

#### Export to your apps (MCP connectors, optional)

| Field | Default | Description |
|---|---|---|
| `mcpConnectors` | - | Optional MCP connectors to copy the results into (Notion, Linear, Airtable, Apify). Never changes the dataset. |
| `notionParentPageUrl` | - | Notion page under which one page per review is created. Notion connector only. |
| `maxNotifyListings` | `50` | Cap on rows written to each connector per run. Does not affect the dataset or your bill. |

#### Example input

```json
{
  "mode": "search",
  "companyUrls": [
    "https://trustmate.io/opinie/trustmate-io",
    "ogrodniczy.com"
  ],
  "minRating": 1,
  "sortBy": "newest",
  "maxItems": 500
}
```

### Output

One row per review. Example (trimmed):

Field shapes only - the values below are placeholders, not a real reviewer or company.

```json
{
  "platform": "trustmate",
  "reviewId": 10000001,
  "reviewPublicId": "00000000-0000-0000-0000-000000000000",
  "rating": 5,
  "reviewBody": "Sample review text exactly as the reviewer wrote it.",
  "authorName": "Reviewer Name",
  "authorType": "person",
  "reviewWeight": 2,
  "reviewDate": "2026-06-12T11:18:40+00:00",
  "language": "pl",
  "verified": true,
  "companyReply": "Sample public reply from the company.",
  "companyReplyDate": "2026-06-12T12:00:40+00:00",
  "companyResponseTimeHours": 0.7,
  "helpfulCount": 0,
  "unhelpfulCount": 1,
  "translations": [{ "language": "en", "body": "Machine translation of the review body." }],
  "companyName": "Example Company",
  "companySlug": "example-company",
  "companyRatingAvg": 4.89,
  "companyRatingDistribution": { "1": 30, "2": 5, "3": 8, "4": 43, "5": 1377 },
  "companyServiceReviewCount": 785,
  "companyCombinedReviewCount": 1463,
  "companyResponseRate": 100,
  "companyCategory": "Opinie o firmach i produktach",
  "sourceUrl": "https://trustmate.io/opinie/example-company",
  "scrapedAt": "2026-08-08T04:30:00Z"
}
```

#### Key output fields

| Field | Description |
|---|---|
| `rating` | Star rating, 1-5 (`grade`). |
| `reviewBody` | Full review text. |
| `authorName` / `authorType` | Reviewer name (person or company domain) and a company/person classifier. |
| `reviewDate` / `reviewUpdatedAt` | Published / last-edited timestamps (ISO 8601). |
| `language` | Original review language. |
| `verified` / `notVerified` | TrustMate verification flags. |
| `companyReply` / `companyReplyDate` / `companyResponseTimeHours` | The company's public reply, its timestamp and the response gap in hours. |
| `helpfulCount` / `unhelpfulCount` | Helpful-vote tallies. |
| `translations` | Machine translations of the review body. |
| `pinned` / `imported` / `importSource` / `shared` | Review metadata flags. |
| `orderIdentifier` / `orderNumber` / `isOrderLinked` | Whether the review is tied to a specific order (TrustMate's post-purchase invite flow). |
| `companyName` / `companySlug` / `companyWebsite` / `companyCategory` | Company context on every row. |
| `companyRatingAvg` / `companyRatingDistribution` | Company average grade and per-star distribution. |
| `companyServiceReviewCount` / `companyCombinedReviewCount` | Service-review total (what is paginated) vs the headline combined total (incl. product reviews). |
| `companyResponseRate` / `companyResponseCount` / `companyRecommendPercentage` | Company reply and recommend aggregates. |
| `companyCertificates` / `companyDescription` / `companyPhone` / `companyAddress` / `companySocialLinks` / `companyLogoUrl` | Public profile extras from the account API. |
| `companyJsonLd` / `companySameAs` / `companyLogo` / `companyAggregateRating` / `companyMetaDescription` | Schema.org profile data - only when `fetchDetails` is on. |

In Incremental mode, rows also carry `changeType` (`NEW`/`UPDATED`/`UNCHANGED`/`REAPPEARED`/`EXPIRED`), `changedFields`, `firstSeenAt` and `lastSeenAt`.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped reviews into the tools you already use, via Model Context Protocol
connectors (Notion, Linear, Airtable, Apify). Authorize a connector under **Apify , Settings ,
API & Integrations**, then select it in the **Export to your apps** input section. Notion
gets one page per review (set `notionParentPageUrl`); other connectors get a best-effort record
write or a digest message.

This is a pure side-channel: the dataset is written first and is never modified, `maxNotifyListings`
caps only what is copied out, and a connector that is unauthorized, rate-limited or offline logs a
warning and leaves your scrape untouched.

### When the run stops, and when it fails

- **A company that cannot be read is never silently swallowed.** If a profile URL / slug does not
  resolve, or TrustMate refuses the account lookup, that company is reported and skipped - and if
  that leaves the run with nothing scraped at all, the run **fails** with an explanatory status
  message instead of finishing "successfully" with an empty dataset.
- **A partial run never expires anything.** `EXPIRED` rows are only produced when the run reached
  the natural end of every company's feed. A page cap, a `maxItems` cap, a resumed run, a skipped
  company, or an empty page served while the feed still reports more reviews all mark the run
  incomplete, and the previous baseline is kept exactly as it was.
- **State is only saved on the normal success path**, so a failed run can never clobber the
  baseline your next scheduled run compares against.

### Proxy guidance

**No special network setup required.** TrustMate serves its review data openly, so the default **Apify proxy works on every Apify plan, including the free tier** - leave the Connection section as-is for the cheapest runs.

- **Datacenter (default):** recommended. Fast and effectively free.
- **Residential (optional):** only needed for higher IP rotation on very large pulls. Billed at a higher rate than the default proxy and metered per run.
- **Free tier / no Apify proxy:** the run automatically falls back to a built-in datacenter backup gateway (never a paid residential pool), and to a direct connection if that is unavailable too. Set the `BACKUP_PROXY_URL` environment variable on the actor to point the fallback at your own gateway instead. Reliability is lower than the default datacenter path - for dependable results, use the default Apify proxy.

### Billing

Charged events:

- **`apify-default-dataset-item`** - charged for each review row returned.
- **`detail-enrichment`** - charged per review row **only** when `fetchDetails` is on.
- **`apify-actor-start`** - charged once per run (depends on memory, one event per GB).

Use `maxItems` to cap any run. In Incremental mode, `emitUnchanged` / `emitExpired` return extra rows that are billed like any other row.

### Disclaimer

This actor collects only publicly available information from TrustMate.io - the same data any visitor can see without logging in. It does not go around authentication, access private data, or collect anything behind a login. Use the data in compliance with TrustMate's Terms of Service, applicable laws (including GDPR), and the rights of data subjects. You are responsible for how you use the scraped data.

# Actor input Schema

## `mode` (type: `string`):

Choose 'search' to paste a list of company profile URLs / slugs / domains, or 'url' to paste profile links directly. Both resolve to the same review feed.

## `companyUrls` (type: `array`):

Only used when mode = search - ignored in URL mode. One or more TrustMate company profile URLs, bare slugs or bare domains. Example: https://trustmate.io/opinie/trustmate-io , https://en.trustmate.io/reviews/trustmate-io , 'ogrodniczy.com' .

## `startUrls` (type: `array`):

Only used when mode = urls - ignored in Search mode. One or more TrustMate company profile URLs, bare slugs or bare domains. Mix Polish (/opinie/) and English (/en/reviews/) links freely.

## `minRating` (type: `string`):

Applies in BOTH search and URL mode. Only return reviews with at least this star rating (1-5). 1 returns all reviews. Narrowing to 4 or 5 filters out lower-starred reviews from the result set (measured on trustmate-io: 1+ = 785 reviews, 4+ = 730, 5 = 714).

## `sortBy` (type: `string`):

Applies in BOTH search and URL mode. Orders the review feed before walking it. Newest first is the TrustMate default; 'Rating' options sort by star rating (pinned reviews float above the sort, mirroring the site).

## `maxItems` (type: `integer`):

Hard cap on the total number of review rows collected across all companies. This is THE cap - the run stops here even when review pages remain. Leave empty for no item cap (unlimited).

## `maxPagesPerCompany` (type: `integer`):

Optional cap on the number of review pages (~100 reviews each) fetched per company. Leave empty (0) for no page limit - the run stops at Max Items. Do not set both this and a low Max Items expecting two caps: the run stops at whichever comes first, and Max Items is the primary one.

## `includeTranslations` (type: `boolean`):

Whether to include the translations array (machine translations of each review body into other languages) on every row. Disable to slim the output.

## `fetchDetails` (type: `boolean`):

When on, each company's public profile page is fetched and parsed (JSON-LD, social sameAs links, logo, meta descriptions) and the extra fields are attached to every review row of that company. Billed per review row returned via the detail-enrichment event. Leave off for the base review output.

## `resumeFromRunId` (type: `string`):

A previous run or dataset ID to continue from. Reviews already collected in that run/dataset are skipped. Leave empty to start fresh. Not compatible with Incremental mode once an incremental baseline exists for this scope (see State key).

## `incrementalMode` (type: `boolean`):

Remember this scope's reviews across runs and return only what changed since the last run, tagged changeType (NEW / UPDATED / REAPPEARED / EXPIRED). Default off - a normal run returns everything. Enables daily/weekly monitoring without pasting a run id every time.

## `stateKey` (type: `string`):

Optional name for the incremental baseline. By default the baseline is keyed automatically on a hash of your mode + companies + filters. Set a key to run two separate monitoring campaigns over the same companies, or to rename an existing baseline.

## `emitUnchanged` (type: `boolean`):

Incremental mode only. When on, reviews that did not change since the last run are also returned (tagged UNCHANGED). These rows are returned AND billed like any other row - leave off to get only what changed.

## `emitExpired` (type: `boolean`):

Incremental mode only. When on, reviews present in the baseline but no longer found after a complete scan are returned as EXPIRED rows. These rows are returned AND billed like any other row. Only runs that reach the natural end of every company's feed can detect expirations; capped or resumed runs skip this.

## `proxy` (type: `object`):

Proxy used for all requests. The default Apify proxy works on the free tier; residential is only needed for higher rotation.

## `mcpConnectors` (type: `array`):

Optionally send the scraped reviews into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-review export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which one page per review is created. Required to enable the Notion export; ignored by every other connector.

## `maxNotifyListings` (type: `integer`):

Cap on how many review rows are written to each connector per run. Does not affect the dataset, and does not change what you are billed for.

## Actor input object example

```json
{
  "mode": "search",
  "companyUrls": [
    "https://trustmate.io/opinie/trustmate-io"
  ],
  "startUrls": [
    "https://trustmate.io/opinie/trustmate-io"
  ],
  "minRating": "1",
  "sortBy": "newest",
  "maxItems": 20,
  "maxPagesPerCompany": 0,
  "includeTranslations": true,
  "fetchDetails": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "mode": "search",
    "companyUrls": [
        "https://trustmate.io/opinie/trustmate-io"
    ],
    "startUrls": [
        "https://trustmate.io/opinie/trustmate-io"
    ],
    "minRating": "1",
    "sortBy": "newest",
    "maxItems": 20,
    "maxPagesPerCompany": 0,
    "includeTranslations": true,
    "fetchDetails": false,
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/trustmate-io-reviews-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 = {
    "mode": "search",
    "companyUrls": ["https://trustmate.io/opinie/trustmate-io"],
    "startUrls": ["https://trustmate.io/opinie/trustmate-io"],
    "minRating": "1",
    "sortBy": "newest",
    "maxItems": 20,
    "maxPagesPerCompany": 0,
    "includeTranslations": True,
    "fetchDetails": False,
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/trustmate-io-reviews-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 '{
  "mode": "search",
  "companyUrls": [
    "https://trustmate.io/opinie/trustmate-io"
  ],
  "startUrls": [
    "https://trustmate.io/opinie/trustmate-io"
  ],
  "minRating": "1",
  "sortBy": "newest",
  "maxItems": 20,
  "maxPagesPerCompany": 0,
  "includeTranslations": true,
  "fetchDetails": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/trustmate-io-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/trustmate-io-reviews-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/woJvuW4w23QfjI18A/builds/ZRIHFIqyc0Y35jZN2/openapi.json
