# German Website Impressum Scraper (`automation-lab/german-imprint-leads`) Actor

Find public Impressum pages on supplied German business websites and extract legal company, address, contact, VAT, register, and representative records with source evidence.

- **URL**: https://apify.com/automation-lab/german-imprint-leads.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

## German Website Impressum Scraper

Turn a list of public German company websites into evidence-backed legal and contact records.
The Actor finds each site's statutory **Impressum**, then extracts the legal company name,
address, public email and phone, VAT ID, commercial register details, representatives, and
short source excerpts.

It is designed for recurring B2B lead enrichment, CRM cleanup, supplier research, and
compliance triage where a homepage alone does not provide the legal entity behind a brand.
You provide the websites; the Actor performs bounded same-site discovery and returns one
typed result row per unique input URL.

### What does this German website scraper do?

For every submitted homepage or direct legal-notice URL, the Actor:

1. validates that the target is a public HTTP or HTTPS URL;
2. downloads the supplied page as lightweight HTML;
3. follows a same-host link labelled `Impressum`, `Imprint`, or `Anbieterkennzeichnung`;
4. tries a bounded set of conventional Impressum paths when no link is available;
5. detects statutory German legal labels;
6. extracts normalized lead fields and source evidence;
7. records every URL checked and a clear `found`, `not_found`, or `error` outcome.

Direct Impressum URLs are supported too. In that case, the Actor avoids an unnecessary
homepage crawl.

### Who is it for?

- **Sales operations teams** enriching a domain list before account assignment.
- **Revenue operations teams** matching brands to their legal entities in a CRM.
- **Procurement teams** collecting displayed supplier identity and register evidence.
- **Market researchers** building structured samples of German business websites.
- **Compliance analysts** triaging public legal-notice coverage before manual review.
- **Data engineers** feeding recurring website enrichment into a warehouse or spreadsheet.

The Actor does not discover companies from Google or another directory. It processes the
public website URLs that you supply.

### Why use structured Impressum records?

German legal notices often contain fields that are absent from a homepage or contact page:

- the exact legal entity rather than only a trading brand;
- a registered or service address;
- managing directors or board representatives;
- VAT identification and commercial register numbers;
- a register court;
- editorial responsibility details;
- direct evidence from the source page.

Unlike a generic contact extractor, this Actor keeps the located Impressum URL, checked-page
trail, processing status, and bounded evidence excerpts next to the extracted values. That
makes downstream review and refresh workflows easier.

### What data can I extract?

| Field | Meaning |
| --- | --- |
| `inputUrl` | Original normalized website or Impressum URL |
| `inputDomain` | Hostname from the input |
| `resolvedDomain` | Hostname after redirects |
| `status` | `found`, `not_found`, or `error` |
| `imprintUrl` | Located public legal-notice URL |
| `companyName` | Displayed legal company or organization name |
| `legalForm` | Detected form such as GmbH, AG, KG, SE, or e.V. |
| `address` | Displayed legal or registered address text |
| `emails` | Public email addresses on the legal page |
| `phoneNumbers` | Public phone numbers on the legal page |
| `vatId` | Displayed German VAT ID |
| `registrationCourt` | Register or local court text |
| `registrationNumber` | HRB or HRA number |
| `representatives` | Managing directors, board members, or representatives |
| `responsiblePerson` | Editorially responsible person when displayed |
| `sourceEvidence` | Short legal-label excerpts supporting the fields |
| `pagesChecked` | Pages visited during bounded discovery |
| `httpStatus` | Last relevant HTTP status |
| `errorMessage` | Bounded failure diagnostic |
| `scrapedAt` | ISO 8601 extraction timestamp |

Website markup varies. Any unavailable extracted field is returned as `null` or an empty
array rather than being invented.

### How to run the German Website Impressum Scraper

1. Open the Actor in Apify Console.
2. Add one or more company homepages or direct Impressum URLs to **Company website URLs**.
3. Keep **Maximum pages per website** at `6` for normal discovery.
4. Set **Maximum websites** to cap the batch.
5. Click **Start**.
6. Open the **Impressum leads** dataset view or export it as JSON, CSV, Excel, XML, or RSS.

A useful first input is:

```json
{
  "startUrls": [
    { "url": "https://www.bosch.de/" },
    { "url": "https://www.zeit.de/" }
  ],
  "maxItems": 2,
  "maxPagesPerWebsite": 6,
  "maxConcurrency": 2
}
```

### Input parameters

#### `startUrls` (required)

A list of public HTTP or HTTPS URLs. Values may be homepages or direct Impressum pages.
Private-network, localhost, credential-bearing, and unsupported-protocol URLs are rejected.
Duplicate normalized URLs are processed once.

#### `maxItems`

Maximum unique input URLs processed in the run. Default: `100`. Range: `1` to `1000`.
The limit is applied before requests are scheduled.

#### `maxPagesPerWebsite`

Maximum number of supplied/homepage and candidate legal pages checked per website.
Default: `6`. Range: `1` to `15`.

#### `maxConcurrency`

Maximum websites processed at once. Default: `5`. Range: `1` to `15`. Reduce this for
small or rate-sensitive sites.

#### `requestTimeoutSecs`

Per-page HTTP timeout. Default: `20` seconds. Range: `5` to `60` seconds. Transient network
and selected temporary HTTP failures receive bounded retries.

### Output example

A current real-site run returns rows shaped like this (representative values shortened):

```json
{
  "inputUrl": "https://www.zeit.de/",
  "inputDomain": "zeit.de",
  "resolvedDomain": "zeit.de",
  "status": "found",
  "imprintUrl": "https://www.zeit.de/impressum/index",
  "companyName": "Zeitverlag Gerd Bucerius GmbH & Co. KG",
  "legalForm": "GmbH & Co. KG",
  "address": "Helmut-Schmidt-Haus, Buceriusstraße, 20095 Hamburg",
  "emails": ["redaktion@zeit.de"],
  "phoneNumbers": ["+49 40 ..."],
  "vatId": "DE189342458",
  "registrationCourt": "Amtsgericht Hamburg",
  "registrationNumber": "HRA 91",
  "representatives": ["Nils von der Kall"],
  "responsiblePerson": null,
  "sourceEvidence": ["Vertreten durch die Geschäftsführung ..."],
  "pagesChecked": [
    "https://www.zeit.de/",
    "https://www.zeit.de/impressum/index"
  ],
  "httpStatus": 200,
  "errorMessage": null,
  "scrapedAt": "2026-08-13T05:30:00.000Z"
}
```

The dataset retains diagnostic outcome rows so batch integrations can reconcile every
submitted URL. Only a successfully located legal record triggers the `lead` billing event.

### How much does it cost to extract German website Impressum leads?

The Actor uses pay-per-event pricing:

- **`start` event:** `$0.005` once per run.
- **`lead` event:** applies once for each successfully located and extracted Impressum record.
- Diagnostic outcome rows do not trigger the `lead` event.

Current per-lead prices decrease by Apify plan:

| Plan | Price per found lead |
| --- | ---: |
| FREE | $0.005336 |
| BRONZE | $0.00464 |
| SILVER | $0.0036192 |
| GOLD | $0.002784 |
| PLATINUM | $0.001856 |
| DIAMOND | $0.0012992 |

At BRONZE pricing, a run with 10 found Impressum leads costs about `$0.0514`; 100 found leads
cost about `$0.469`; and 1,000 found leads cost about `$4.645`. Batches with fewer extracted
records trigger fewer `lead` events. Apify compute usage is billed under the user's
platform plan.

### Bulk lead-enrichment workflow

For a recurring CRM process:

1. export domains missing legal-entity fields from the CRM;
2. map them into `startUrls`;
3. schedule the Actor daily, weekly, or monthly;
4. join rows back on `inputDomain`;
5. accept `found` fields into a staging table;
6. route `not_found` and `error` statuses to a retry or review queue;
7. compare `sourceEvidence` and `scrapedAt` on later runs.

The Actor returns current public page content. It does not maintain history or claim that a
field changed; store snapshots in your own dataset or warehouse when change detection is
needed.

### Export to spreadsheets and data pipelines

The default dataset works with Apify's standard exports. Common patterns include:

- CSV or Excel export for sales operations;
- Google Sheets via an Apify integration;
- Make or Zapier workflows triggered after a run;
- webhook delivery to an enrichment service;
- JSON API ingestion into a data warehouse;
- scheduled Tasks for recurring domain batches.

Use `status` as the workflow branch and keep `imprintUrl` plus `sourceEvidence` for review.

### Run with the Apify API

Replace `YOUR_TOKEN` with an Apify API token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~german-imprint-leads/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.bosch.de/"}],
    "maxItems": 1
  }'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/german-imprint-leads').call({
  startUrls: [{ url: 'https://www.bosch.de/' }],
  maxItems: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/german-imprint-leads').call(run_input={
    'startUrls': [{'url': 'https://www.bosch.de/'}],
    'maxItems': 1,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI assistants

#### Claude Code

Add the Actor as an Apify MCP tool in Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/german-imprint-leads"
```

#### Claude Desktop, Cursor, and VS Code

Use this equivalent MCP JSON configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/german-imprint-leads"
    }
  }
}
```

Example prompts:

- “Extract the public Impressum records for these five German supplier websites.”
- “Return company name, VAT ID, register number, representatives, and source URL as JSON.”
- “Separate found records from websites that need manual review.”

### Accuracy, limits, and failure behavior

- Extraction uses public server-rendered HTML; it does not run a browser.
- JavaScript-only or challenge-protected legal pages may return `not_found` or `error`.
- Labels and page structures differ, so fields may be null even when other fields are found.
- The Actor checks same-host pages only and does not crawl an entire site.
- It does not validate email deliverability, VAT registration, or register status.
- It does not infer hidden contacts or enrich people from third-party sources.
- A `found` result means a page with German legal signals was located, not that every field
  was available or legally sufficient.
- Redirects are followed and recorded through `resolvedDomain` and `imprintUrl`.
- Temporary request failures receive bounded retries; permanent HTTP failures do not loop.

For best results, provide canonical company homepages or direct Impressum URLs and keep the
crawl limit at its default.

### Responsible and legal use

Only process pages you are permitted to access. Respect website terms, robots guidance,
applicable rate limits, database rights, privacy rules, and the purpose for which public
contact data was displayed. German Impressum pages can contain personal names and contact
details. A public page does not automatically authorize unsolicited marketing, profiling,
or unrestricted redistribution.

Use an appropriate lawful basis, minimize retained fields, secure exports, honor deletion or
objection rights where applicable, and obtain legal advice for your jurisdiction and use
case. This Actor is a technical extraction tool, not legal or compliance advice.

### FAQ and troubleshooting

#### Why did I get `not_found`?

The Actor could fetch pages but did not find enough legal-page signals within the configured
page limit. Try supplying the site's direct Impressum URL or increasing
`maxPagesPerWebsite` up to `15`.

#### Why did I get `error`?

Inspect `errorMessage`, `httpStatus`, and `pagesChecked`. The site may be unavailable,
challenge-protected, non-HTML, or too slow. Increase the request timeout when the public page
responds slowly.

#### Why is a field null?

The page may not display it in recognizable text. Check `imprintUrl` and `sourceEvidence`
before deciding whether manual extraction or another authoritative source is appropriate.

#### Does the Actor search Google for businesses?

No. It deliberately processes user-supplied URLs. This keeps the workflow predictable and
avoids charging for unrelated search results.

#### How does event billing work?

The one-time `start` event applies to the run. The `lead` event applies only when an
Impressum record is successfully located and extracted; diagnostic rows do not trigger it.

### Related automation-lab Actors

- [Website Contact Details Extractor](https://apify.com/automation-lab/website-contact-details-extractor)
  for broader email, phone, and social-link extraction outside legal notices.
- [Website Company Address Extractor](https://apify.com/automation-lab/website-company-address-extractor)
  for identifying office, mailing, and company address candidates across public pages.

Use this Actor when Germany-specific statutory identity and evidence are the core job; use
the related Actors when broader website contact or address coverage is more important.

### Support

When reporting a problem, include a reproducible public URL, the input settings, run ID,
`status`, `pagesChecked`, and the bounded `errorMessage`. Do not post API tokens, private
customer lists, or confidential exports.

# Actor input Schema

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

Public HTTP(S) homepages or direct Impressum URLs to process. One output row is produced per unique URL.

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

Maximum number of unique input websites to process in this run.

## `maxPagesPerWebsite` (type: `integer`):

Maximum homepage and candidate legal pages checked for each website.

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

Number of websites processed at once. Lower this for fragile sites.

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

Per-page timeout before a request is reported as failed.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.bosch.de/"
    },
    {
      "url": "https://www.zeit.de/"
    }
  ],
  "maxItems": 10,
  "maxPagesPerWebsite": 6,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing legal company, contact, register, and source-evidence fields.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.bosch.de/"
        },
        {
            "url": "https://www.zeit.de/"
        }
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/german-imprint-leads").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 = {
    "startUrls": [
        { "url": "https://www.bosch.de/" },
        { "url": "https://www.zeit.de/" },
    ],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/german-imprint-leads").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 '{
  "startUrls": [
    {
      "url": "https://www.bosch.de/"
    },
    {
      "url": "https://www.zeit.de/"
    }
  ],
  "maxItems": 10
}' |
apify call automation-lab/german-imprint-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/german-imprint-leads"
        }
    }
}

```

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/p28scVDcGVkwWvugh/builds/HDZgoVEfGdFKN29wP/openapi.json
