# Impressum Scraper: German Company Contacts & Directors (`datagleaner/impressum-contacts`) Actor

Extract Impressum contact data from German, Austrian and Swiss company websites: legal name, managing directors (Geschäftsführer), email, phone, address, VAT ID and register number (HRB/FN/CHE). $3 per 1,000 imprints with a contact; sites without one are free.

- **URL**: https://apify.com/datagleaner/impressum-contacts.md
- **Developed by:** [Data Gleaner](https://apify.com/datagleaner) (community)
- **Categories:** Lead generation, Integrations, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 imprint with contacts

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

## Impressum Scraper: German, Austrian & Swiss Company Contacts from the Legal Notice

**Impressum Scraper** reads the legally required legal notice (Impressum, Imprint, Legal notice, Mentions légales) of company websites and returns it as clean data. Give it domains and get each company's **legal name and legal form, managing directors (Geschäftsführer), email, phone and fax, postal address, VAT ID (USt-IdNr., UID, MWST), register court and number (HRB, HRA, FN, CHE)** and the person responsible for content (V.i.S.d.P.). **You pay $0.003 (from 3 November 2026: $0.005) only for a website whose imprint gave a company name plus an email or phone; sites with no imprint are free.**

It answers searches such as: *impressum scraper*, *impressum email extractor*, *imprint contact details*, *German company contacts*, *DACH company leads*, *Geschäftsführer email*, *Handelsregister number from website* and *legal notice extractor*.

Built for lead-generation pipelines and AI agents as well as people: one row per website, the same fields every time, and the price tied to the answer you wanted. Plain HTTP, no browser, no login.

### Why the imprint

German law (§ 5 DDG, formerly § 5 TMG), Austrian law (§ 5 ECG, § 25 MedienG) and Swiss law (Art. 3 UWG) require nearly every business website to publish who runs it. That makes the Impressum the most complete free source of verified B2B contact data in the DACH region: the legal entity, the people who legally represent it, an address that takes registered mail, and the commercial register entry you can check against the Handelsregister.

### What you get

| Field | Example |
|---|---|
| `companyName`, `legalForm` | `Tourlane GmbH`, `GmbH` (also UG (haftungsbeschränkt), AG, KG, GmbH & Co. KG, e.K., OHG, SE, e.V., OG, SARL, SAS, SA...) |
| `managingDirectors` | `["Julian Weselek", "Anna Semmelroth"]` from Geschäftsführer, Geschäftsführung, Vorstand, "Vertreten durch", Managing Director, Gérant |
| `owners` | Inhaber(in) of a sole trader (e.K.), persönlich haftende Gesellschafter |
| `responsibleForContent` | Person responsible under § 18 Abs. 2 MStV (V.i.S.d.P.), or Directeur de la publication |
| `address` | `{"street": "Prinzessinnenstraße 20", "postalCode": "10969", "city": "Berlin", "country": "DE"}` |
| `emails`, `primaryEmail` | The company's own addresses, deobfuscated; the best general one (info@, kontakt@) as `primaryEmail` |
| `phones`, `fax` | E.164 format, e.g. `+493083795330` |
| `vatId` | `DE302188049`, `ATU62224319`, `CHE-109.030.864`, `FR...` and other EU formats |
| `registerCourt`, `registerNumber` | `Amtsgericht Berlin-Charlottenburg`, `HRB 170081 B`; `Handelsgericht Wien`, `FN 271791 v`; `Handelsregister des Kantons Zürich`, `CHE-106.838.812` |

### How it works

1. Loads the home page and finds the imprint link by its text or address: Impressum, Imprint, Legal notice, Mentions légales, Colofon, Note legali, Aviso legal, Información legal. A link may point to the parent company's domain.
2. With no link, tries the usual paths: `/impressum`, `/imprint`, `/legal-notice`, `/de/impressum`, `/impressum.html`, `/mentions-legales`. A path that returns 404 costs nothing.
3. Reads the visible text block by block and maps the labelled fields: German and English first, French as well. Emails written as `info(at)firma.de`, `info [at] firma [dot] de`, `info @ firma.de`, HTML entities or Cloudflare email protection are decoded.
4. Keeps only emails on the company's own domain (or a webmail box), so an agency or hosting provider named in the imprint does not end up in your CRM.
5. Retries with exponential backoff on 429 and 5xx, honours `Retry-After`, paces requests per site and respects `robots.txt`.

### Use cases

- **DACH B2B lead generation:** turn a list of German, Austrian or Swiss domains (from Google Maps, Gelbe Seiten, a trade-fair exhibitor list or your CRM) into decision-maker names with a company email and phone.
- **Find the Geschäftsführer and their company email** for outreach, partnerships or M\&A sourcing.
- **KYC, supplier and partner checks:** legal entity, register number and VAT ID straight from the source, ready to verify in the Handelsregister or VIES.
- **CRM enrichment and deduplication:** `domain`, `vatId` and `registerNumber` are stable join keys.
- **AI agents** that need "who runs this company and how do I reach them" for a list of websites, paying only for hits.

### Input

| Field | Meaning |
|---|---|
| `websites` | Company websites, one per line: `firma.de`, `https://www.firma.de/` or a direct imprint URL. |
| `datasetId` | Optional. Dataset of another Actor to take websites from, merged with `websites`. See below. |
| `datasetField` / `maxDatasetItems` | Website field name if unusual; cap on websites read (default 1000). |
| `onlyWithEmail` | Output only sites whose imprint gave an email (default `false`). Sites without one are free either way. |
| `maxPagesPerSite` | Pages read per site (default 3): home page, imprint link, fallback paths. 404 paths do not count. |
| `languageHint` | `auto` (default, from the domain), `de`, `en` or `fr`: which imprint link and paths to try first. |
| `maxConcurrency` | Sites processed in parallel (default 10). |
| `delaySecs` | Pause between two requests to the same site (default 0.5). |
| `respectRobotsTxt` | Skip pages that robots.txt disallows (default `true`). |
| `proxyConfiguration` | Optional, no proxy by default. Turn on Apify Proxy if many sites answer 429. |

Leave everything empty to run three built-in DACH examples (about 10 seconds, 3 billable rows).

```json
{
  "websites": ["tourlane.de", "https://www.bergzeit.de", "https://www.willhaben.at", "https://www.post.ch"],
  "onlyWithEmail": false,
  "maxPagesPerSite": 3,
  "languageHint": "auto"
}
```

### Run it after Google Maps Scraper or any scraper

Open the source Actor's **Integrations** tab, add this Actor (`datagleaner/impressum-contacts`) and set its input to:

```json
{"datasetId": "{{resource.defaultDatasetId}}"}
```

Every time the source run succeeds, this Actor reads the websites from its results (`website`, `url`, `domain`, `site`, `homepage`, `link`, `companyWebsite` or `web`, the first one present; `datasetField` names another field), skips items with no website, social-media or map links, and duplicates, and reads the imprint of each (at most `maxDatasetItems`, default 1000). Each row also carries `sourceTitle`, the `title` or `name` of the source item (for example the Google Maps place name). Billing is the same: one event per imprint with a contact, nothing for sites without one. Works with Google Maps Scraper (`compass/crawler-google-places`) and any Actor whose output has a website field.

The same works from code, for one finished run:

```python
run = client.actor("datagleaner/impressum-contacts").call(run_input={"datasetId": "SOURCE_DATASET_ID"})
```

The status message tells how many items were read from the dataset and how many had no website, or says so if the dataset could not be read.

It also works as an integration without setting any input: in the source Actor's Integrations tab choose Add integration and pick this Actor, and the dataset is passed automatically.

### Output

One row per input website. A real row:

```json
{
  "domain": "tourlane.de",
  "imprintUrl": "https://www.tourlane.de/impressum/",
  "companyName": "Tourlane GmbH",
  "legalForm": "GmbH",
  "managingDirectors": ["Julian Weselek", "Anna Semmelroth"],
  "owners": [],
  "responsibleForContent": null,
  "address": {"street": "Prinzessinnenstraße 20", "postalCode": "10969", "city": "Berlin", "country": "DE"},
  "emails": ["hello@tourlane.de", "press@tourlane.com"],
  "primaryEmail": "hello@tourlane.de",
  "phones": ["+493083795330"],
  "fax": null,
  "vatId": "DE302188049",
  "registerCourt": "Amtsgericht Berlin-Charlottenburg",
  "registerNumber": "HRB 170081 B",
  "hasContact": true,
  "status": "ok",
  "error": null,
  "input": "tourlane.de",
  "scrapedAt": "2026-10-09T14:49:21+00:00"
}
```

`status` is `ok` (imprint with contact, billed), `noContact` (imprint found, but no company name with an email or phone), `noImprint` (no legal notice found), `unreachable`, `blockedByRobots`, `invalidUrl` or `error`. Only `ok` rows are billed. A field that the imprint does not state is `null` or an empty list; nothing is guessed.

The Output tab has two views: **Imprint contacts** (company, directors, email, phone, VAT ID, register) and **All fields**. Export to CSV, Excel, JSON or Google Sheets, or read the dataset through the API.

### Use it from n8n, Make, Zapier or an AI agent

Actor ID: `datagleaner/impressum-contacts`

Minimal input:

```
{"websites": ["https://www.tourlane.de", "https://www.bergzeit.de"]}
```

Each tool below runs this Actor with your own Apify API token.

- **n8n:** add the **Apify** node (`@apify/n8n-nodes-apify`). On n8n Cloud you install it from the community node registry. Choose **Run an Actor and get dataset**, set Actor to `datagleaner/impressum-contacts` and paste the input above.

- **Make:** use the Apify app's **Run an Actor** module, then **Get Dataset Items** to read the results. **Watch Actor Runs** can trigger a scenario when a run finishes.

- **Zapier:** use the Apify action **Run Actor**, then the search **Fetch dataset items**. The trigger **Finished Actor run** starts a Zap when a run ends.

- **AI agents (MCP):** connect to `https://mcp.apify.com/?tools=datagleaner/impressum-contacts`. In Claude Code:

  ```
  claude mcp add --transport http apify "https://mcp.apify.com/?tools=datagleaner/impressum-contacts"
  ```

  Then run `/mcp` to sign in to Apify in your browser. Other clients can sign in with OAuth or send the header `Authorization: Bearer YOUR_APIFY_TOKEN`. Clients that run local MCP servers can use Apify's package (`@apify/actors-mcp-server`, run with `npx -y` and `APIFY_TOKEN` set) instead. Then ask the agent in plain words, for example:

  > Find the managing directors, email and VAT ID of tourlane.de and bergzeit.de.

- **LangChain (Python):**

```python
## pip install langchain-apify, then set APIFY_TOKEN in your environment
import json
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("datagleaner/impressum-contacts")
result = tool.invoke({"run_input": json.loads('{"websites": ["https://www.tourlane.de", "https://www.bergzeit.de"]}')})
```

Through the API, one call returns the rows:

```bash
curl -X POST "https://api.apify.com/v2/acts/datagleaner~impressum-contacts/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"websites": ["tourlane.de", "willhaben.at"], "onlyWithEmail": true}'
```

Tip for agents: set `onlyWithEmail` to `true` when you only need reachable contacts, and read `primaryEmail` for the single best address.

### How much does it cost?

Pay per event: **US$3.00 per 1,000 imprints with a contact** (event `imprint-with-contact`, US$0.003 each) until 3 November 2026. **From 3 November 2026 the price is US$5.00 per 1,000** (US$0.005 each); the raise has been announced to users 14 days ahead, as the platform requires. You are charged once per website whose legal notice gave a company name plus an email or phone. Sites where no imprint is found, imprints without a contact, and unreachable sites are free.

Worked example: 1,000 German company domains, of which about 85% have a readable imprint with a contact, cost 850 x $0.003 = **$2.55** until 3 November 2026 and 850 x $0.005 = **$4.25** from then. Platform usage is small because the Actor makes plain HTTP requests, about 3 to 5 per site.

### Limits

- No JavaScript rendering. An imprint drawn only by scripts (some single-page shops), or a site that refuses non-browser clients with 403 or 429, gives `noImprint` or `unreachable`, free of charge. Some Shopify and Cloudflare-fronted shops answer 429 to automated clients; the Actor backs off and retries, and Apify Proxy can help.
- Names are read from labelled fields. An imprint that names its directors only inside a running sentence may leave `managingDirectors` empty while the rest of the row is filled.
- Emails or phones shown only as images are not read.
- Up to 10 pages per site; default 3. A site gets no new request after 90 seconds; a very slow server is returned with what was found by then, so one slow site cannot hold the whole run open.

### FAQ

**How do I get the Geschäftsführer and email of a German company from its website?** Put the domain in `websites`. The Actor finds the Impressum and returns `managingDirectors`, `primaryEmail` and `phones`, plus the register entry to verify them.

**Does it work for Austria and Switzerland?** Yes. Austrian imprints give `FN` Firmenbuch numbers, the Handelsgericht and `ATU` VAT IDs; Swiss imprints give the `CHE` UID and the cantonal Handelsregister. French Mentions légales (RCS, SIREN, TVA) and English Imprint pages are read as well.

**Is this the same as a Handelsregister lookup?** No. It reads what the company itself publishes on its website, which is usually more current for email and phone. Use `registerCourt` and `registerNumber` to look the entity up in the official register.

**What if a site has no imprint?** The row comes back with status `noImprint` and costs nothing.

**Can I scrape thousands of domains?** Yes. Sites run in parallel (`maxConcurrency`), each with at most one request at a time and a polite delay.

**Does it guess emails?** No. It returns only addresses printed on the imprint page, and only those on the company's own domain or a webmail box.

**Can I export to CSV or my CRM?** Yes: CSV, Excel, JSON, Google Sheets, Zapier, Make, or the API.

### Responsible use

This Actor reads publicly available legal notices that companies are required by law to publish. It does not log in, solve CAPTCHAs or get around blocks. Names of directors and responsible persons are personal data under the GDPR: you are responsible for having a lawful basis when you store or contact them, and for following anti-spam rules (in Germany § 7 UWG restricts unsolicited B2B email and calls).

# Actor input Schema

## `websites` (type: `array`):

Company websites, one per line. `firma.de`, `https://www.firma.de/` and a direct imprint URL such as `https://www.firma.de/impressum` all work. Leave empty to run 3 built-in DACH examples.

## `datasetId` (type: `string`):

Optional. Read company websites from this dataset, for example Google Maps Scraper results, and add them to the websites above. Each item's `website` (or `url`, `domain`, `site`, `homepage`, `link`, `companyWebsite`, `web`) is used; items without one are skipped. In an integration use `{{resource.defaultDatasetId}}`.

## `datasetField` (type: `string`):

Optional. Name of the field that holds the website when it is not one of the usual ones. Tried first.

## `maxDatasetItems` (type: `integer`):

Stops reading the dataset after this many distinct websites. Only used with a dataset ID.

## `onlyWithEmail` (type: `boolean`):

Output only websites whose legal notice gave at least one email address. Sites without one are free either way.

## `maxPagesPerSite` (type: `integer`):

Pages read per website: the home page, then the imprint link and, if there is none, the common imprint paths (/impressum, /imprint, /legal-notice, /mentions-legales). A path that returns 404 does not count.

## `languageHint` (type: `string`):

Which language's imprint link and paths to try first. Auto picks German for .de, .at and .ch, French for .fr, .be and .lu, and English otherwise. All languages are parsed either way.

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

How many websites are processed at the same time. Each website gets at most one request at a time.

## `delaySecs` (type: `number`):

Polite pause between two requests to the same website.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for each page before retrying.

## `respectRobotsTxt` (type: `boolean`):

Skip pages that the site's robots.txt disallows.

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

Optional. Defaults to no proxy. Turn on Apify Proxy if many sites answer 429 (rate limited), as Shopify shops sometimes do on shared cloud IPs.

## Actor input object example

```json
{
  "websites": [
    "https://www.tourlane.de",
    "https://www.bergzeit.de",
    "https://www.willhaben.at",
    "https://www.post.ch"
  ],
  "maxDatasetItems": 1000,
  "onlyWithEmail": false,
  "maxPagesPerSite": 3,
  "languageHint": "auto",
  "maxConcurrency": 10,
  "delaySecs": 0.5,
  "requestTimeoutSecs": 20,
  "respectRobotsTxt": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "websites": [
        "https://www.tourlane.de",
        "https://www.bergzeit.de",
        "https://www.willhaben.at",
        "https://www.post.ch"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/impressum-contacts").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 = {
    "websites": [
        "https://www.tourlane.de",
        "https://www.bergzeit.de",
        "https://www.willhaben.at",
        "https://www.post.ch",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/impressum-contacts").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 '{
  "websites": [
    "https://www.tourlane.de",
    "https://www.bergzeit.de",
    "https://www.willhaben.at",
    "https://www.post.ch"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datagleaner/impressum-contacts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagleaner/impressum-contacts"
        }
    }
}
```

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/P4uhaLA7w194Df5yP/builds/gKl8rlKnYJyUvjWhk/openapi.json
