# Trusted Shops Scraper - German Online Shop Emails & Phones (`scrapersdelight/trusted-shops-directory-scraper`) Actor

Every Trusted Shops certified online shop on trustedshops.de as a B2B lead: legal company name, Impressum address, email, phone, Handelsregister court + number, managing director, Gütesiegel status and ratings. Filter by category, country, member-since. $0.009 per shop.

- **URL**: https://apify.com/scrapersdelight/trusted-shops-directory-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$9.00 / 1,000 per shop lead delivereds

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

## Trusted Shops Scraper — German Online Shop Emails, Phones & Handelsregister

Get every **Trusted Shops member shop on trustedshops.de** as a B2B lead: legal company name,
Impressum street address, **email**, **phone**, website, **Handelsregister court and number**, the
person who represents the company, the Gütesiegel (trustmark) status and the full rating block.
One row per shop, keyed on the Trusted Shops ID.

Trusted Shops certifies online shops selling to German consumers, and certification requires a complete,
verified Impressum. The shop's profile page publishes that identity. This actor reads it from the
profile's own structured data (no field labels are guessed or translated) and returns it as clean
columns.

**Who buys this:** payment providers, shipping and returns software, ERP / tax / accounting
integrators, e-commerce agencies, marketplaces and anyone else selling to established DACH online shops.
Every shop in this list has paid for a trustmark, so it is an active, invested e-commerce business.

### What you get: measured, not promised

Measured on live runs on 2026-09-23, on two samples taken in different ways (a single sample can be
skewed):

| Field | Sitemap sample (600 certified shops) | Category sample (400 certified shops, *Bekleidung* + *Baumarkt*) |
|---|---|---|
| **email** | **99.8%** | **98.8%** |
| **phone** | **89.2%** | **91.0%** |
| email **and** phone | 89.0% | 90.3% |
| street + postal code + city | 99.8% | 100% |
| legal company name | 100% | 100% |
| Handelsregister number | 75.2% | 77.5% |
| Handelsregister court | 75.2% | 78.0% |
| represented by (managing director / owner) | 97.0% | 96.0% |
| website | 100% | 100% |
| rating (12 months) | 47.2% | 100% |
| delivery / goods / service marks | 48.0% | 98.8% |

- The email is the shop's **company mailbox** in most rows: it sits on the shop's own domain in 65% of
  the sitemap sample and 83% of the category sample. Freemail (gmail, gmx, web.de …) appears in 3.2%
  and 1.3%. Two flags, `emailOnShopDomain` and `emailIsFreemail`, let you filter on this.
- Handelsregister numbers are missing for sole traders (who are not in the commercial register) and
  for sellers based abroad. Those sellers print their own country's register instead, for example
  `KVK 76615464` (NL), `FN 62825s` (AT) or `REGON 363670423` (PL).
- The rating is null for shops whose profile shows "Keine Bewertungen" (no reviews). Long-standing
  members listed at the top of the sitemap often have none, which is why the two samples differ so
  much on rating fill.
- Where a field is missing, the site did not publish it for that shop. It is not a parser gap: every
  field the site publishes reaches the row, and the offline test checks this on every sample profile.

### How it works

1. **Whole directory.** Leave the inputs empty and the actor walks the member sitemap
   (`/ts_sitemaps/profile.xml`, **14,663 member profiles** on 2026-09-22). It checks that sitemap has
   at least 10,000 profiles and that its `<loc>` count matches before using it.
2. **By category.** Pick one or more of the 34 directory categories. The actor walks the
   directory's own listing, which trustedshops.de itself filters to shops with a **valid**
   Gütesiegel, so only matching shops are fetched. Every category is checked against the total the site
   states (for example *Optiker*: the site says 50 certified shops, and a live run delivered all 50). If a listing page stays
   down through every retry, the rest of that category is taken from the sitemap instead, so no category
   comes back short.
3. **By shop.** Paste Trusted Shops IDs or profile URLs to look up exactly those shops.

Each profile page is about 1.4 MB. The actor checks every page arrived complete before reading it. A
page cut off mid-download is fetched again, never read as "this shop publishes nothing".

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `categories` | array | — | Directory categories (34, e.g. `lebensmittel`, `bekleidung`, `baumarkt`, `optiker`). Empty = whole directory. |
| `shops` | array | — | Trusted Shops IDs (`X` + 32 hex) or profile URLs. A shop you name is returned whatever its Gütesiegel status. |
| `certificateStatus` | `valid` | `any` | `valid` | `valid` = only shops with a currently valid Gütesiegel (about 4 in 5 members). `any` = every member, including invalid certificates and reviews-only memberships. |
| `sellerCountries` | array | — | Keep only sellers whose Impressum address is in these countries (`DE`/`DEU`, `AT`, `CH`, `NL` …). |
| `memberSinceFrom` | date | — | Only shops that joined Trusted Shops on or after this date (`YYYY-MM-DD`), useful for finding new members. |
| `minReviewCount12Months` | integer | 0 | Skip shops with fewer reviews in the last 12 months (a rough measure of order volume). |
| `requirePhone` | boolean | false | Only shops that publish a phone number. |
| `requireRegisterNumber` | boolean | false | Only shops that publish a commercial-register number. |
| `includeCriteriaRatings` | boolean | true | Adds the DELIVERY / GOODS / SERVICE marks and the rating label, at one extra ~1.5 KB request per shop. |
| `excludeTsIds` | array | — | Suppression list: shops already in your CRM or delivered earlier. Never charged. |
| `maxItems` | integer | 30 | Stop after this many delivered shops. Raise it (e.g. `20000`) for the whole directory. |
| `maxConcurrency` | integer | 10 | Profiles fetched in parallel. |
| `proxyConfiguration` | object | direct | trustedshops.de runs no anti-bot, so the default is a direct connection. A request that fails is retried once through Apify RESIDENTIAL automatically. |

#### Example: every certified food and drink shop with a phone number

```json
{
  "categories": ["lebensmittel", "genussmittel"],
  "requirePhone": true,
  "maxItems": 5000
}
```

#### Example: shops that joined since the start of 2026 and are based in Austria or Switzerland

```json
{
  "certificateStatus": "any",
  "sellerCountries": ["AT", "CH"],
  "memberSinceFrom": "2026-01-01",
  "maxItems": 1000
}
```

### Output

A real row, delivered by the live actor on 2026-09-23 (description shortened here):

```json
{
  "tsId": "X236713B7D2601C105AB7AD0FF597A6B7",
  "shopName": "Kaffeezentrale DE",
  "companyName": "Kaffeezentrale DE GmbH",
  "imprintName": "Kaffeezentrale DE GmbH",
  "email": "info@kaffeezentrale.de",
  "phone": "+4923451659000",
  "website": "www.kaffeezentrale.de",
  "domain": "kaffeezentrale.de",
  "street": "Lothringer Allee 8",
  "postalCode": "44805",
  "city": "Bochum",
  "countryCode": "DEU",
  "registerCourt": "Amtsgericht Bochum",
  "registerNumber": "HRB 7383",
  "registerType": "HRB",
  "representedBy": "Bernd Kerkhoff",
  "contactFormUrl": null,
  "whatsappUrl": null,
  "emailOnShopDomain": true,
  "emailIsFreemail": false,
  "certificateStatus": "VALID",
  "hasValidTrustmark": true,
  "certificationType": "CLASSIC",
  "certifiedSince": "2012-01-30",
  "memberSince": "2012-03-15",
  "rating": 4.93,
  "reviewCount12Months": 3032,
  "reviewCountAllTime": 28636,
  "ratingDistribution12Months": { "1": 6, "2": 7, "3": 14, "4": 132, "5": 2873 },
  "ratingLabel": "EXCELLENT",
  "deliveryRating": 4.93,
  "goodsRating": 4.93,
  "serviceRating": 4.93,
  "categories": ["Haushaltswaren & Haushaltsgeräte", "Lebensmittel", "Genussmittel"],
  "keywords": ["Bier", "Kaffee"],
  "description": "Kaffeezentrale - seit 1999 Ihr Partner für Kaffee, Espresso, Cappuccino & Co. …",
  "logoUrl": "https://channel-settings.etrusted.com/logo-1c48f397-44e5-4d93-a8c2-0d319e29f201--medium",
  "socialLinks": [],
  "hasOtherMarketProfiles": false,
  "targetMarket": "DEU",
  "language": "de",
  "profileType": "member",
  "profileUrl": "https://www.trustedshops.de/bewertung/info_X236713B7D2601C105AB7AD0FF597A6B7.html",
  "scrapedAt": "2026-09-23T04:25:00.299Z"
}
```

#### Every field

| Field | Meaning |
|---|---|
| `tsId` | Trusted Shops ID, the directory's own key. One row per TSID; duplicates are never delivered or charged. |
| `shopName` | Shop name as shown on the profile. |
| `companyName` | Legal company behind the shop. |
| `imprintName` | Name on the profile's Impressum address block. |
| `email` | Contact email as published. Trusted Shops' own addresses are never emitted (checked by test). |
| `phone` | Phone exactly as published, usually `+49…`. Never reformatted or completed. |
| `website`, `domain` | Shop URL as published; its host in lower case without `www.` (IDN domains such as `kanapee-möbel.de` kept). |
| `street`, `postalCode`, `city`, `countryCode` | Impressum address; country as ISO alpha-3. |
| `registerCourt`, `registerNumber` | Handelsregister court and number exactly as printed. Only whitespace is tidied; a number is never completed or "repaired". |
| `registerType` | `HRB`, `HRA`, `GnR`, `PR`, `VR` or `GsR`, read off the printed number. |
| `representedBy` | "Vertreten durch": managing directors or owner. |
| `contactFormUrl`, `whatsappUrl` | Extra contact channels, when published. |
| `emailOnShopDomain`, `emailIsFreemail` | Whether the email is on the shop's own domain, or on a freemail provider. |
| `certificateStatus` | What the profile's Gütesiegel box shows: `VALID` ("Gültig"), `INVALID` ("ungültig"), `NOT_SHOWN` (no box: reviews-only or pending). |
| `hasValidTrustmark` | `true` exactly when `certificateStatus` is `VALID`. |
| `certificationType` | `CLASSIC` (audited trustmark) or `NO_AUDIT` (reviews-only membership). |
| `certifiedSince` | The date the profile prints as "Zertifiziert seit" (only for VALID). |
| `memberSince` | Start of the Trusted Shops membership. |
| `rating`, `reviewCount12Months`, `reviewCountAllTime`, `ratingDistribution12Months` | The profile's rating block. `rating` is null, never 0, when there are no rated reviews. |
| `ratingLabel`, `deliveryRating`, `goodsRating`, `serviceRating` | Marks from Trusted Shops' public quality endpoint. Only emitted when the profile itself shows a rating. |
| `categories`, `keywords` | Directory categories and sub-category keywords. |
| `description`, `logoUrl`, `socialLinks` | The shop's own profile content. |
| `hasOtherMarketProfiles` | The same company runs further Trusted Shops profiles (other countries). |
| `targetMarket`, `language`, `profileType`, `profileUrl`, `scrapedAt` | Profile metadata. |

The run also writes a `RUN_SUMMARY` record to the key-value store. It counts profiles examined, rows
delivered and rows removed by each filter, and keeps apart the three kinds of nothing: **not found**
(the profile does not exist), **no contact** (the profile publishes no email, phone or street address)
and **unreachable** (still failing after retries). None of these is charged.

### Pricing

**$0.009 per shop delivered.** Plain pay-per-event with no start fee. You are charged only for rows
that land in your dataset with at least one way to reach the shop.

You are never charged for: a profile that does not exist, a profile with no contact data, a profile we
could not reach, a shop your filters or suppression list removed, or a duplicate. A test run with the
default `maxItems` of 30 costs at most $0.27.

About filters: `certificateStatus`, `sellerCountries`, `memberSinceFrom`, `minReviewCount12Months`,
`requirePhone` and `requireRegisterNumber` are applied after each profile is read. A narrow filter
therefore reads more profiles than it returns, and runs longer, but you still pay only for delivered
rows. Category mode does not have this cost: the site filters to valid certificates before anything is
fetched.

### Speed

At the default 1,024 MB: 600 shops in 94 s from the sitemap and 400 in 94 s by category. The whole
directory (14,663 profiles) takes roughly 25 to 40 minutes, depending on how fast trustedshops.de answers.

### Data limits

- **Germany first.** This version covers trustedshops.de, the German market (`targetMarket` = DEU).
  About 1 in 7 of its shops are legally based in another country (NL, PL, AT, CZ, DK, IT, BE
  measured), and `countryCode` / `sellerCountries` tell them apart. The .at / .ch / .nl / .fr / .pl
  markets are not yet covered.
- **Members only.** The sitemap and listings return paying members. Unclaimed "non-member" profiles
  (about 5,600 more on trustedshops.de) carry no verified identity and are left out on purpose.
- **Two rating sources can disagree.** For a few shops the public quality endpoint reports reviews
  while the profile shows "Keine Bewertungen" (16 of 600 in the sitemap sample). The row follows the
  profile page and leaves those marks null.
- **Register numbers as printed.** Some shops write the court into the number field
  (`Amtsgericht Hamburg HRB 142867`) and leave the court field empty. The actor ships what was printed
  and does not split or complete it.

### Source

Data comes from the public trustedshops.de profile pages, the directory's own listing, the member
sitemap and the public `api.trustedshops.com` quality endpoint. No login and no personal account are
used.

This actor is not affiliated with, endorsed by or connected to Trusted Shops. "Trusted Shops" and
"Gütesiegel" are used only to describe the data source.

### FAQ

**How many shops are there?** 14,663 member profiles on trustedshops.de on 2026-09-22, of which
about 4 in 5 hold a valid Gütesiegel. Per category, the certified count is shown on the site (for
example *Lebensmittel* 1,290, *Bekleidung* 1,292, *Optiker* 50).

**Can I get only new members?** Yes. Set `memberSinceFrom`, and `certificateStatus: "any"` if you also
want members who are not yet certified.

**Can I refresh a list I already have?** Pass the TSIDs in `shops`. Use `excludeTsIds` to skip shops
you already hold.

**Do I need a proxy?** No. The default is a direct connection. If trustedshops.de ever starts
refusing it, the actor falls back to Apify RESIDENTIAL on its own.

**Why is the email empty for a few shops?** Those shops publish only a phone number, a contact form or
a WhatsApp link, and those channels are delivered instead. A shop with no email, no phone and no street
address is not delivered and not charged.

# Actor input Schema

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

Trusted Shops directory categories to pull. Each category is walked through the directory's own listing, pre-filtered by trustedshops.de to shops holding a VALID Gütesiegel, so only matching shops are ever fetched. Leave empty (and leave 'Specific shops' empty) to walk the whole member directory (14,663 member profiles on 2026-09-22) from its sitemap.

## `shops` (type: `array`):

Look up named shops instead of walking the directory. Accepts a Trusted Shops ID (X followed by 32 hex characters) or any profile URL containing one, e.g. https://www.trustedshops.de/bewertung/info\_X0F44BDBD6DF1414C5C32DE292FFF8A59.html. A shop you name is returned whatever its Gütesiegel status. When filled, 'Shop categories' is ignored.

## `certificateStatus` (type: `string`):

'valid' = only shops whose profile shows a valid Trusted Shops Gütesiegel (trustmark), about 81% of members. 'any' also returns members whose certificate is invalid or who hold a reviews-only membership; with categories selected this switches to a sitemap scan filtered by category, which examines more profiles and is slower.

## `sellerCountries` (type: `array`):

Only return shops whose Impressum address is in these countries. ISO codes, 3- or 2-letter: DEU or DE, AUT or AT, CHE or CH, NLD, POL … Every shop on trustedshops.de targets German buyers, but about 1 in 7 is legally seated abroad (NL, PL, AT, CZ, DK, IT, BE measured). Leave empty for all.

## `memberSinceFrom` (type: `string`):

Only shops whose Trusted Shops membership started on or after this date (YYYY-MM-DD). Use it to pull NEW members — shops that just invested in a trustmark are shops actively buying e-commerce services.

## `minReviewCount12Months` (type: `integer`):

Skip shops with fewer reviews in the last 12 months — a proxy for order volume. 0 = no minimum.

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

Skip shops whose profile publishes no phone (about 1 in 6). Skipped shops are never charged.

## `requireRegisterNumber` (type: `boolean`):

Skip shops whose profile publishes no commercial-register number — usually sole traders and foreign-seated sellers. Skipped shops are never charged.

## `includeCriteriaRatings` (type: `boolean`):

Adds the per-criteria marks (DELIVERY, GOODS, SERVICE) and the rating label (EXCELLENT, GOOD …) from Trusted Shops' public quality endpoint — one extra ~1.5 KB request per delivered shop.

## `excludeTsIds` (type: `array`):

Suppression list — shops already in your CRM or delivered by an earlier run. Matched on the TSID, never charged.

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

Stop after this many delivered shops. Only delivered shops are charged. The default keeps a test run cheap; raise it (e.g. 20000) to take the whole directory.

## `maxConcurrency` (type: `integer`):

Profiles fetched in parallel.

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

trustedshops.de runs no anti-bot, so the default is a DIRECT connection (measured ~50x cheaper than residential). A request that fails direct is retried once through Apify RESIDENTIAL automatically. Set a proxy here only if you need every request routed through one.

## Actor input object example

```json
{
  "categories": [
    "optiker"
  ],
  "certificateStatus": "valid",
  "minReviewCount12Months": 0,
  "requirePhone": false,
  "requireRegisterNumber": false,
  "includeCriteriaRatings": true,
  "maxItems": 5,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `shops` (type: `string`):

One item per Trusted Shops member shop: legal identity, contact, Handelsregister, Gütesiegel status and ratings.

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

Coverage accounting: profiles examined, rows delivered, filter counts, and the three kinds of nothing (not found, no contact, unreachable) kept apart — none of them charged.

# 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": [
        "optiker"
    ],
    "maxItems": 5,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/trusted-shops-directory-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": ["optiker"],
    "maxItems": 5,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/trusted-shops-directory-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": [
    "optiker"
  ],
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapersdelight/trusted-shops-directory-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/trusted-shops-directory-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/gbNK6NlJThh15SAiw/builds/k4l0wgr9LrfZ4swt5/openapi.json
