# DACH Reputation Scraper — Trusted Shops & ProvenExpert (`memo23/dach-reputation-scraper`) Actor

Scrape German-market company reputation across Trusted Shops and ProvenExpert from one website domain — ratings, review counts, per-criteria marks and full review text, with the same company matched across platforms and every match auditable. JSON, CSV or Excel.

- **URL**: https://apify.com/memo23/dach-reputation-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 reviews

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?

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

## DACH Reputation Scraper — Trusted Shops, ProvenExpert & eKomi

Give it a company's own website domain and get back that company's reputation across the three German-market review platforms it appears on — average ratings, review counts, per-criteria marks and full review text — with the same business matched across platforms so you can compare like for like.

![How the DACH Reputation Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-dach.png)

### Why use this scraper?

- **One domain in, every platform out.** Paste `otto-office.com`. The actor resolves that company on each platform with a public lookup, no profile IDs to hunt down.
- **The same company, matched across platforms.** Each business row carries a rating weighted across every platform it was found on, plus `ratingByPlatform` so a divergence between them stays visible rather than being averaged away.
- **Auditable matching.** Every match records `matchConfidence` and `matchSignals`, so you can see it was joined on a shared domain rather than on a guess. Matches are never asserted silently.
- **Numbers that are honest about their scope.** Trusted Shops publishes a rolling 12-month window; the lifetime total is carried separately as `lifetimeReviewCount` and never conflated. OTTO Office reads 4,529 in the window against 105,570 lifetime.
- **Per-criteria marks.** Trusted Shops scores DELIVERY, GOODS and SERVICE separately — useful when an overall 4.7 hides a delivery problem.
- **No proxy required.** Every supported platform serves direct requests.
- **eKomi resolved from the domain too.** eKomi publishes no directory or sitemap, so the actor derives the account from the domain and then verifies the certificate names that domain before trusting it.

### Overview

| | |
|---|---|
| **Platforms** | Trusted Shops, ProvenExpert, eKomi |
| **Entry points** | Company website domain, or a direct profile URL / ID |
| **Row types** | `business` (matched company), `profile` (per platform), `review` |
| **Proxy** | Not required |

### How it works

1. **Resolve.** A domain is looked up on every platform offering a public lookup. Trusted Shops returns each market variant separately — `otto-office.com` yields German, Belgian-Dutch and Belgian-French shops, which are genuinely different shops with different ratings.
2. **Fetch.** Each profile is pulled with its ratings, counts and reviews. A platform that fails is reported and skipped; losing one never costs you the others.
3. **Match.** Profiles are clustered into companies on shared identity signals, domain first.
4. **Emit.** One `business` row per company, one `profile` row per platform, and the reviews.

### Supported inputs

| Input | Example |
|---|---|
| Company domain | `otto-office.com` |
| ProvenExpert profile | `https://www.provenexpert.com/{slug}/` |
| eKomi certificate | `https://www.ekomi.de/bewertungen-{account}.html` |
| Trusted Shops profile | `https://www.trustedshops.de/bewertung/info_{TSID}.html` (or `.com/buyerrating/`, `.fr/evaluation/`) |
| Bare Trusted Shops ID | `X507F9B7DFF6E66ACED13EDB990A7B6BA` |

### Use cases

- **Reputation monitoring** — track one company's score across platforms on a schedule and alert on movement.
- **Competitive benchmarking** — compare a set of competitors on a single weighted number, with the per-platform detail underneath.
- **Due diligence** — verified-purchase flags, merchant reply behaviour and the gap between order date and review date show how a business actually operates.
- **Complaint mining** — pull the low-star reviews across every platform at once for sentiment and root-cause work.

### Input configuration

```json
{
    "companyDomains": ["otto-office.com"],
    "profileUrls": ["https://www.provenexpert.com/andre-grosse-digitalmarketing-street/"],
    "includeReviews": true,
    "maxReviewsPerCompany": 100,
    "maxItems": 1000
}
```

Ratings-only monitoring across many companies, which is far cheaper:

```json
{ "companyDomains": ["otto-office.com", "thomann.de"], "includeReviews": false }
```

| Field | Type | Description |
|---|---|---|
| `companyDomains` | array | Company websites to resolve on every platform with a public lookup. |
| `profileUrls` | array | Direct profile URLs or IDs, for platforms with no public lookup. |
| `includeReviews` | boolean | Pull review text as well as company and profile rows. Default `true`. |
| `maxReviewsPerCompany` | integer | Cap per company per platform. Default 100. |
| `maxItems` | integer | Total rows across every type. Default 1000. |
| `proxy` | object | Optional; only useful for very large runs. |

### Output overview

| `rowType` | One per | Carries |
|---|---|---|
| `business` | Matched company | Weighted rating, total ratings, platforms, match confidence and signals, per-platform ratings, profile URLs |
| `profile` | Platform per company | That platform's rating, counts, distribution, criteria marks, address, and its stated limits |
| `review` | Review | Rating, title, text, author, date, verified flag, merchant reply |

### Output samples

Business row:

```json
{
    "rowType": "business",
    "key": "otto-office.com",
    "name": "OTTO Office Deutschland",
    "websiteDomain": "otto-office.com",
    "platforms": ["trustedshops", "provenexpert"],
    "matchConfidence": "high",
    "matchSignals": ["domain:otto-office.com", "phone:8007779997"],
    "weightedRating": 4.7,
    "totalRatings": 4529,
    "ratingByPlatform": { "trustedshops": 4.7, "provenexpert": 4.6 },
    "profileUrls": { "trustedshops": "https://www.trustedshops.de/bewertung/info_X507F9B7DFF6E66ACED13EDB990A7B6BA.html" }
}
```

Profile row:

```json
{
    "rowType": "profile",
    "platform": "trustedshops",
    "name": "OTTO Office Deutschland",
    "averageRating": 4.7,
    "reviewCount": 4529,
    "lifetimeReviewCount": 105570,
    "ratingDistribution": { "1": 115, "2": 44, "3": 103, "4": 548, "5": 3729 },
    "criteriaRatings": { "DELIVERY": 4.7, "GOODS": 4.7, "SERVICE": 4.7 },
    "limits": ["Trusted Shops publishes only the rolling 12-month window: 4529 of 105570 lifetime reviews are reachable"]
}
```

Review row:

```json
{
    "rowType": "review",
    "platform": "provenexpert",
    "companyName": "André Große – DIGITALMARKETING STREET",
    "rating": 5,
    "text": "Wer einen langjährig erfahrenen Profi im Digitalmarketing an der Seite sucht, ist bei André Große genau richtig.",
    "authorName": "Sonja Förste",
    "reviewDate": "2025-02-04T00:00:00.000Z",
    "isVerified": null
}
```

### Key output fields

- **`matchConfidence`** — `high` (matched on a shared domain), `medium` (phone, or name plus a location), `low` (one weak signal — worth checking), `single` (found on one platform only, so nothing was matched).
- **`weightedRating`** vs **`ratingByPlatform`** — the weighted mean across platforms, and the underlying per-platform scores it came from.
- **`reviewCount`** vs **`lifetimeReviewCount`** — what is reachable versus what the company has accumulated. Do not present the first as a company's total.
- **`criteriaRatings`** — per-criterion marks where the platform publishes them (Trusted Shops: DELIVERY, GOODS, SERVICE).
- **`limits`** — what a given platform could not supply for this company, and why. A null field plus an empty `limits` means the company genuinely has no value; a null field with a limit means the platform does not publish it.

### FAQ

**Why do I get several companies for one domain?**
Trusted Shops runs many merchants as a separate shop per market. `otto-office.com` is three shops — German, Belgian-Dutch, Belgian-French — with genuinely different ratings (4.7, 4.28, 4.36). They are not merged because they are not the same shop.

**Why is `authorName` empty on many Trusted Shops reviews?**
Only reviewers who made their consumer profile public expose a name — roughly a quarter in sampling. The site shows "Community Member" for the rest; this actor returns `null` so you can filter on the field directly.

**How many reviews can I get?**
Trusted Shops serves its full rolling 12-month window. ProvenExpert publishes at most 20 per company and eKomi at most 10 on the certificate; both say so in that profile's `limits`, alongside the true total.

**Why does an eKomi lookup sometimes find nothing when the company shows an eKomi seal?**
Some seals link to a certificate that no longer exists. The actor confirms a certificate actually names the domain before accepting it, because eKomi serves an empty page rather than a 404 for a dead account — matching on the guess alone would attach one company's reviews to another.

**Are older reviews available?**
No. Both platforms only publish a recent window. Run on a schedule to build an archive over time.

**Do I need a proxy?**
No.

### Support & feature requests

Open an issue on the actor's **Issues** tab in the Apify Console.

### Additional services

Need this on a schedule, pushed to a webhook, S3 or Google Sheets, or joined with review data from another platform? Apify handles scheduling and delivery, and every run's dataset stays addressable over the API. For a custom variant — extra platforms, a different row shape — open an issue describing the output you want.

### Explore more scrapers

- **[Trusted Shops Reviews Scraper](https://apify.com/memo23/trusted-shops-reviews-scraper)** — deep review history from Trusted Shops alone, with the full rolling window.
- **[Trustpilot Scraper](https://apify.com/memo23/trustpilot-scraper-ppe)** — the English-language equivalent.
- **[Google Maps Reviews Scraper](https://apify.com/memo23/google-maps-reviews-scraper)** — local business reviews.
- **[G2 Scraper](https://apify.com/memo23/g2-scraper)** — software product reviews.

### 🤖 For AI Agents & LLM Apps

Compact reference for agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/dach-reputation-scraper`).

**Purpose:** Resolve a company's website domain to its reputation across Trusted Shops, ProvenExpert and eKomi — ratings, review counts, per-criteria marks and review text — with cross-platform matching.

**Minimal input:**

```json
{ "companyDomains": ["otto-office.com"], "includeReviews": false }
```

**Output:** three row types keyed by `rowType`. `business` carries key, name, websiteDomain, platforms, matchConfidence, matchSignals, weightedRating, totalRatings, ratingByPlatform, profileUrls, limits. `profile` carries platform, platformId, name, averageRating, ratingCount, reviewCount, lifetimeReviewCount, ratingDistribution, criteriaRatings, address fields, limits. `review` carries platform, companyName, rating, title, text, authorName, reviewDate, replyText, replyDate, isVerified.

**Behaviors an agent should know:**

- One domain can produce several `business` rows. Trusted Shops runs a separate shop per market and they carry different ratings; do not collapse them.
- Never report `reviewCount` as a company's total. `lifetimeReviewCount` is frequently an order of magnitude larger (4,529 against 105,570 on OTTO Office).
- Check `matchConfidence` before treating a `business` row as one company. `single` means it was found on one platform, not that a match was weak.
- `limits` explains every gap. A null field with a matching limit is a platform restriction, not missing data.
- ProvenExpert caps at 20 reviews per company and eKomi at 10. ProvenExpert publishes no per-review id — dedupe those on author plus date plus text. eKomi publishes no reviewer name.
- `authorName` is null wherever the reviewer has no public profile.
- Set `includeReviews: false` to monitor ratings across many companies cheaply.
- Pay-per-event billing — see the Pricing tab.

### ⚠️ Disclaimer

This actor collects only publicly available data that anyone can see by visiting these review pages. It does not access private data, bypass authentication, or collect personal information beyond what reviewers chose to publish. Requests are limited to paths the target sites permit crawling. You are responsible for how you use the data — make sure your use complies with applicable law (GDPR, CCPA) and each site's terms. Requests to eKomi are limited to certificate pages, which its robots.txt permits. Not affiliated with or endorsed by Trusted Shops AG, Expert Systems AG (ProvenExpert), or eKomi.

### SEO Keywords

provenexpert scraper, trusted shops scraper, ekomi scraper, ekomi bewertungen, german reviews scraper, DACH reputation monitoring, provenexpert bewertungen, trusted shops bewertungen, multi-platform review scraper, company reputation API, german business ratings, cross-platform review aggregation, reputation management data, verified purchase reviews, shop rating export, european review platforms, competitor rating benchmark

# Actor input Schema

## `companyDomains` (type: `array`):

The company's own website, e.g. "otto-office.com". Each domain is resolved on every platform that offers a public lookup (currently Trusted Shops, which returns each market variant separately). This is the easiest way in — you never need to find a profile ID.

## `profileUrls` (type: `array`):

Direct profile URLs for platforms with no public lookup: a ProvenExpert profile (https://www.provenexpert.com/{slug}/), a Trusted Shops profile (trustedshops.de/bewertung/info\_{TSID}.html or the .com/.fr variants), or a bare TSID.

## `includeReviews` (type: `boolean`):

Pull individual reviews as well as the company and profile rows. Turn this off to monitor ratings cheaply across many companies.

## `maxReviewsPerCompany` (type: `integer`):

Trusted Shops serves its full rolling 12-month window; ProvenExpert publishes at most 20 per company.

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

Total dataset rows across every type (company, profile, review).

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

Optional. All supported platforms serve direct requests, so a proxy is only useful for very large runs.

## Actor input object example

```json
{
  "companyDomains": [
    "otto-office.com"
  ],
  "profileUrls": [
    "https://www.provenexpert.com/andre-grosse-digitalmarketing-street/"
  ],
  "includeReviews": true,
  "maxReviewsPerCompany": 100,
  "maxItems": 1000
}
```

# Actor output Schema

## `results` (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 = {
    "companyDomains": [
        "otto-office.com"
    ],
    "profileUrls": [
        "https://www.provenexpert.com/andre-grosse-digitalmarketing-street/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/dach-reputation-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 = {
    "companyDomains": ["otto-office.com"],
    "profileUrls": ["https://www.provenexpert.com/andre-grosse-digitalmarketing-street/"],
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/dach-reputation-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 '{
  "companyDomains": [
    "otto-office.com"
  ],
  "profileUrls": [
    "https://www.provenexpert.com/andre-grosse-digitalmarketing-street/"
  ]
}' |
apify call memo23/dach-reputation-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/dach-reputation-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/UyfXJYrhUD5E8zxms/builds/xYcs8JfGC97nAAOL8/openapi.json
