# Hiring Companies Germany – Employers with Contact Data (`perceptr0n/hiring-companies-germany`) Actor

Job and place in, one row per company that is hiring for it out: open positions, job titles and locations from the Jobbörse of the Bundesagentur für Arbeit, plus the company's own website and the contact data of its legal notice (Impressum), confirmed by the company's name on that page.

- **URL**: https://apify.com/perceptr0n/hiring-companies-germany.md
- **Developed by:** [Perceptron Data](https://apify.com/perceptr0n) (community)
- **Categories:** Lead generation, Jobs
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 companies

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?

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

## Hiring Companies Germany

Give a job and a place, get one row per company that is hiring for it: open positions, job titles and locations from the Arbeitsagentur Jobbörse, plus the company's own website and the contact data of its legal notice (Impressum) – a website counts only when that page names the company.

<sub>Part of Perceptron Data · Hiring & Trade Fairs</sub>

**Limits:** only companies that advertise on the Jobbörse of the Bundesagentur für Arbeit, read through the JSON interface of the Jobbörse's own app, which is not offered to third parties and can change at any time. The ads name the employer, never its website: the website is searched and confirmed by its legal notice, and 29 % of the companies in our platform test got none (each such row says what was checked). For another 16 % only the website of the company's group was found – the parent or a sister company – and the row says so. Temp agencies and private recruiters are left out by default.

| Company (open positions) | Website | Status | From the legal notice | VAT ID (VIES) |
|---|---|---|---|---|
| Deutsche Bahn AG (13) | deutschebahn.com | `confirmed` | Deutsche Bahn AG, Berlin | valid |
| Miele VG Deutschland KG (3) | miele.de | `confirmed` | Miele Vertriebsgesellschaft Deutschland KG, Gütersloh | valid |
| Enpal Fulfillment B.V. (5) | enpal.de | `group` | Enpal B.V., Berlin – the parent, said as such | valid |

*Electricians around Berlin, platform run of 30 October 2026: 40 companies in 214 seconds. miele.de refused automated requests and was read through Apify's Web Fetch; the ads named neither Deutsche Bahn's nor Enpal's website.*

**What you are not charged for:** temp and recruitment agencies that were left out, companies already in your list (`listId`), companies without contact data when `onlyWithContact` is on, and companies the run did not reach before your cost limit or its timeout (all counted in the run report `OUTPUT`). Rows of companies whose website could not be confirmed are charged – their status says so. Every run has a start fee of $0.01.

### How to use – step by step

1. Click **Try for free** on this page (a free Apify account is enough) – the form opens with "Elektriker" in Berlin.
2. Enter a **Job or keyword** as you would type it into the Jobbörse (German terms find more: `Pflegefachkraft`, `Steuerfachangestellte`) and a **Place** – a town with umlauts (`München`), a postal code or a federal state (`Bayern`); leave the place empty for all of Germany.
3. Set **Maximum companies** (default 10). The companies with the most open positions come first. **Maximum job ads read** (default 200) decides how many ads are read to find them – set it to at least ten times the companies you want.
4. Click **Start**. The default run took 77 seconds on Apify (30 October 2026).
5. Open the **Output** tab: the **Hiring companies** view shows open positions, job titles, places, website, its status, legal name, phone, e-mail and town; every other field is in the full rows. Export as CSV, Excel or JSON, or read the rows through the API.
6. For a weekly list of companies that started hiring, set **Ads published within the last N days** to `7`, give a **List name** and schedule the run weekly: each run then delivers only companies that were not in the list before.

### What you get per company

| Field | Content |
|---|---|
| `company`, `openPositions`, `jobTitles`, `professions`, `locations`, `newestPosting`, `oldestPosting` | from the job ads of this search |
| `website`, `websiteStatus`, `websiteSource`, `websiteEvidence` | the website and why it is the company's (or its group's) |
| `legalName`, `legalForm`, `street`, `postalCode`, `city`, `country`, `phone`, `email`, `fax` | from that website's legal notice |
| `registerType`, `registerNumber`, `registerCourt`, `vatId` | from the legal notice |
| `vatStatus`, `vatValid`, `vatCheckedAt` | the EU VAT ID checked in the EU's VIES register (Swiss UIDs cannot be checked there) |
| `adEmails`, `adPhones`, `postedVia`, `jobUrls` | contacts and links from the ads themselves |
| `websiteCandidates` | every website that was checked, with its result |
| `query`, `source`, `checkedAt` | your search, the sources and the time of the check |

#### `websiteStatus` – how sure is the website?

- `confirmed` – the site's legal notice names the company itself (its legal name, or its name tied to a job location).
- `group` – the legal notice names another company of the same group, e.g. the parent ("Apleona GmbH" for "Apleona Property Services GmbH"). The contact data are that company's – often the right switchboard, but not the employer's own address.
- `not_confirmed` – websites were checked, none names the company; `websiteCandidates` lists them with the reason.
- `not_found` – no candidate website: the ads carry no address, Wikidata has no entry and no domain built from the name exists.

### How the website is found – and why it is checked

The Jobbörse names the employer as text only. A domain in an ad can belong to a job portal, a recruiter or the parent group; a domain built from the name can belong to a namesake in another town. So every candidate is read like an imprint check: the actor finds the site's legal notice and compares the company named there with the employer.

1. **Domains in the ads** – e-mail addresses and links (job boards, applicant tracking systems and free mail left out).
2. **Wikidata** – the official website of an entry with the company's name, then of the brand's entry (German, Austrian or Swiss companies only).
3. **Domains built from the name** – only those that exist; first names, frequent surnames and words like "Montage" or "Klinikum" alone are never tried. Such a domain needs more than the name: the full legal name, a tie to a job location (postal code or town), or – for a group site – a group company whose name is part of the employer's.
4. **Sites this actor cannot read itself** – they refuse automated requests, do not answer or draw their pages with JavaScript – are read once more through Apify's [Web Fetch](https://apify.com/apify/web-fetch), after every other candidate was tried and only for sites the ads, Wikidata or the name point to (see costs below).

### Measured, not assumed

Platform test on Apify, 30 October 2026 (build 0.2), the default settings otherwise:

| Search | Companies | Own website confirmed | Group website | Without | Run time |
|---|---|---|---|---|---|
| Example run (empty input: Elektriker, Berlin) | 10 | 5 | 3 | 2 | 77 s |
| Elektriker, Berlin | 40 | 25 | 5 | 10 | 214 s |
| Pflegefachkraft, München | 30 | 15 | 5 | 10 | 148 s |
| Steuerfachangestellte, Hamburg | 30 | 16 | 4 | 10 | 171 s |
| Mechatroniker, all of Germany | 20 | 10 | 4 | 6 | 128 s |
| **Together** | **130** | **71 (55 %)** | **21 (16 %)** | **38 (29 %)** | |

All runs succeeded; the rows came in the order of open positions. Apify's Web Fetch was called 65 times for these 130 rows (about $0.08 on our account) and brought back the website of 6 rows from sites that refused us or did not answer.

Every `confirmed` and `group` row of these runs was checked by hand (company ↔ legal notice ↔ domain); the wrong results found that way – a namesake's site taken as a group website, an insurer's name and address read from a tax adviser's legal notice – were fixed in this build. What still goes wrong, and is reported as such: sites that refuse every automated request even through Web Fetch, employers that are persons (a tax adviser, a practice), and groups whose legal notice names a company the ad does not mention.

### Input example

```json
{
    "keyword": "Pflegefachkraft",
    "location": "München",
    "radiusKm": 25,
    "maxCompanies": 30,
    "maxJobs": 300,
    "onlyWithContact": true
}
```

A weekly list of new companies hiring electricians in Bavaria:

```json
{
    "keyword": "Elektriker",
    "location": "Bayern",
    "publishedSince": 7,
    "maxCompanies": 100,
    "maxJobs": 1000,
    "listId": "elektriker-bayern"
}
```

### Output example

```json
{
    "company": "ELTEC Service GmbH",
    "openPositions": 1,
    "jobTitles": ["Elektriker / Elektroniker für Energie- und Gebäudetechnik (m/w/d)"],
    "locations": ["10587 Berlin"],
    "newestPosting": "2026-10-22",
    "website": "https://www.eltec-berlin.de/",
    "websiteStatus": "confirmed",
    "websiteSource": "job_ad_email",
    "websiteEvidence": "the site's legal notice names the company (same legal name)",
    "legalName": "ELTEC Service GmbH",
    "street": "Einsteinufer 63 - 65",
    "postalCode": "10587",
    "city": "Berlin",
    "phone": "030 - 34 78 55",
    "email": "info@eltec-berlin.de",
    "registerNumber": "HRB 32288",
    "registerCourt": "Berlin-Charlottenburg",
    "vatId": "DE136750056",
    "vatStatus": "valid",
    "adEmails": ["hr@eltec-berlin.de"],
    "jobUrls": ["https://www.arbeitsagentur.de/jobsuche/jobdetail/10001-1003897805-S"],
    "websiteCandidates": [{"domain": "eltec-berlin.de", "source": "job_ad_email", "result": "confirmed"}],
    "query": {"keyword": "Elektriker", "location": "Berlin", "radiusKm": 25, "excludeAgencies": true}
}
```

*Shortened; from the platform run of 30 October 2026.*

### What does a run cost?

$0.01 per run start, then per stored company – cheaper on bigger Apify plans:

| Your Apify plan | Per company |
|---|---|
| Free | $0.01 |
| Starter | $0.0075 |
| Scale | $0.006 |
| Business & Enterprise | $0.005 |

| Companies (Free plan) | Cost |
|---|---|
| 10 | $0.11 |
| 100 | $1.01 |
| 1,000 | $10.01 |

- **Every stored row is charged**, including companies whose website could not be confirmed – `websiteStatus` says which. Switch on `onlyWithContact` to get (and pay for) only companies with contact data.

- Temp agencies left out, companies already in your list and companies not reached are not charged; the run report `OUTPUT` counts them.

- **Web Fetch is billed by Apify, not by this actor.** It runs on your Apify account: $0.0015 per delivered page on the free plan plus $0.00005 per call start (Apify Store, 13 October 2026), at most 6 pages per site and 2 sites per company. In our platform test of 30 October 2026 it came to about $0.0006 per company on average. `webFetch: false` switches it off; such sites then keep their reason in `websiteCandidates`.

- If you set a maximum cost per run, the actor stops starting new companies when the limit is reached and says so in its status message.

### Data & fair use

The job ads come from the JSON interface of the Jobbörse (Jobsuche API) of the Bundesagentur für Arbeit; company data come from the companies' own public legal notices, Wikidata and the EU's VIES service. This actor is **not affiliated with or endorsed by the Bundesagentur für Arbeit**. It reads at a polite request rate and never rotates IP addresses.

Names of managing directors, personal e-mail addresses (`firstname.lastname@`) and mobile numbers from the ads are left out unless `includePersonNames` is on. They are personal data under GDPR – you need a lawful basis to process them. For sole traders, the company name itself can be a person's name.

### FAQ

**Why does a company have no website?**
The ads name the employer, never its website. When no candidate's legal notice names the company, the row says `not_confirmed` and lists in `websiteCandidates` what was checked and why it did not fit – a guessed domain of a namesake is not passed off as the company's.

**What does `group` mean for my outreach?**
The legal notice belongs to another company of the same group – usually the parent. Its phone number and address reach the group, not necessarily the hiring branch. `websiteEvidence` names that company.

**How do I get only companies with contact data?**
Switch on `onlyWithContact`. Companies without a confirmed or group website then produce no row and cost nothing.

**How do I get only new companies every week?**
Give a `listId` and schedule the run. Each run remembers the companies it delivered under that name and leaves them out next time.

**Are temp agencies included?**
Not by default: ads of temporary work agencies (Zeitarbeit) and private recruiters are left out, so the rows are companies that hire for themselves. Switch `excludeAgencies` off to include them.

**What happens with an input the actor cannot use?**
The run ends successfully with no rows, and its status message says what to change – a place the Jobbörse does not know, neither a keyword nor a place, a number field with text in it. Only the run start is charged. If the Jobbörse itself refuses or fails, the run fails, so a schedule notices.

**Can I use it from an AI agent?**
Yes. The input has two text fields (`keyword`, `location`) and plain numbers; every row carries the search and the evidence for its website.

### Changelog

- **30 October 2026** – 0.2: group websites found through the brand's Wikidata entry and through group companies whose name is part of the employer's; Web Fetch only after every other candidate and only for the company's own domains; rows in the order of open positions; renamed companies confirmed through their Wikidata entry.
- **27 October 2026** – 0.1: first private version.

### Auf Deutsch: Firmen, die gerade einstellen – mit Kontaktdaten

Beruf und Ort rein, je einstellender Firma eine Zeile raus: offene Stellen, Stellentitel und Orte aus der Jobbörse der Bundesagentur für Arbeit, dazu die eigene Website der Firma und die Kontaktdaten aus ihrem Impressum – eine Website zählt nur, wenn ihr Impressum die Firma nennt.

Die Stellenanzeigen nennen den Arbeitgeber, nie seine Website. Der Actor sucht sie in den Anzeigen (E-Mail-Adressen, Links), in Wikidata und unter aus dem Namen gebildeten Domains und prüft jede Kandidatin über ihr Impressum. Nennt das Impressum eine andere Firma derselben Gruppe, heißt die Zeile `group`, nie `confirmed`. Zeitarbeit und private Vermittler fallen standardmäßig heraus; mit einem Listennamen (`listId`) liefert jeder Lauf nur Firmen, die vorher noch nicht dabei waren.

Ehrliche Grenzen: Im Plattformtest vom 30. Oktober 2026 bekamen 29 % der Firmen keine bestätigte Website; die Zeile nennt dann, was geprüft wurde. Seiten, die automatische Abrufe ablehnen, liest der Actor einmal über Apifys Web Fetch, das Apify auf Ihrem Konto abrechnet.

### More from Perceptron Data

| Actor | What it does |
|---|---|
| [Arbeitsagentur Jobs](https://apify.com/perceptr0n/arbeitsagentur-jobs-scraper) | Keyword and place in, one row per job out: employer, salary range, home office, location |
| [Imprint & VAT Check](https://apify.com/perceptr0n/imprint-impressum-website-contact-scraper) | Domains in, company rows out: legal name, address, register number and EU VAT ID checked against VIES (Swiss UIDs excluded) |
| [Free Imprint & Contact Check](https://apify.com/perceptr0n/free-website-contact-imprint-scraper) | The same company row, free, for up to 10 websites per run |
| [kununu Employer Data](https://apify.com/perceptr0n/kununu-employer-data-scraper) | Employer score vs. industry, salary ranges, benefits and reviews for DACH companies |
| [Advertiser Check (Google & Bing)](https://apify.com/perceptr0n/google-ads-transparency-scraper) | Company list in, one row per company out: Google ads, Bing ads, ad counts, accounts |
| [Messe München Exhibitors](https://apify.com/perceptr0n/messe-muenchen-exhibitor-list-scraper) | Exhibitor lists of bauma, IFAT, BAU and more |
| [Koelnmesse Exhibitors](https://apify.com/perceptr0n/anuga-ism-koelnmesse-exhibitor-scraper) | Exhibitor lists of Anuga, ISM, imm cologne and more |
| [TED Tenders](https://apify.com/perceptr0n/eu-tenders-ted-scraper) | EU public tenders and contract awards from TED |

### Support

Bug reports are welcome in the **Issues** tab.

# Actor input Schema

## `keyword` (type: `string`):

What the companies are hiring for, as you would type it into the Jobbörse, e.g. `Elektriker`, `Pflegefachkraft`, `SAP Berater`. Leave it empty to find all companies hiring in the place. With neither a keyword nor a place, the run is the example search Elektriker in Berlin.

## `location` (type: `string`):

Town, postal code or federal state, e.g. `Berlin`, `80331` or `Bayern`. Leave empty for all of Germany.

## `radiusKm` (type: `integer`):

Distance around the place. Default 25.

## `publishedSince` (type: `integer`):

Only companies with an ad published in this many days (0–100), e.g. `7` for a weekly list. Leave empty for all ads.

## `excludeAgencies` (type: `boolean`):

Default on: ads of temporary work agencies (Zeitarbeit) and private recruiters are left out, so only companies that hire for themselves remain.

## `maxCompanies` (type: `integer`):

Default 10. Stop after this many company rows. The companies with the most open positions come first.

## `maxJobs` (type: `integer`):

Default 200. How many job ads are read to find the companies (at most 10,000 per run). More ads find more companies; set it to at least ten times `maxCompanies`.

## `onlyWithContact` (type: `boolean`):

Default off. When on, only companies with contact data get a row: those whose own website was confirmed, and those for which the website of their group was found (status `group`). The others produce no row and cost nothing.

## `validateVat` (type: `boolean`):

Default on: a VAT ID found in the legal notice is checked in the EU's VIES register.

## `includePersonNames` (type: `boolean`):

Default off. When on, managing directors from the legal notice, and personal e-mail addresses and mobile numbers from the ads, are included. These are personal data under GDPR — you need a lawful basis to process them.

## `webFetch` (type: `boolean`):

Default on. A company site this actor cannot read itself — it refuses automated requests, does not answer, or draws its legal notice with JavaScript — is read once more through Apify's Web Fetch actor: only after every other candidate site was tried, only sites the ads, Wikidata or the company's name point to, and at most 2 sites per company. Apify bills it on your account ($0.0015 per delivered page, at most 6 pages per site).

## `listId` (type: `string`):

Optional. With a list name, each run remembers the companies it delivered under that name, and the next run with the same name delivers only companies that were not in the list before — set it for weekly schedules.

## Actor input object example

```json
{
  "keyword": "Elektriker",
  "location": "Berlin",
  "radiusKm": 25,
  "excludeAgencies": true,
  "maxCompanies": 10,
  "maxJobs": 200,
  "onlyWithContact": false,
  "validateVat": true,
  "includePersonNames": false,
  "webFetch": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per hiring company: open positions, job titles, locations, confirmed website and legal-notice contact data.

## `resultsCsv` (type: `string`):

The same rows as CSV, for spreadsheets and CRMs.

## `report` (type: `string`):

Not charged. How many ads and employers were found, how many websites were confirmed, which agencies were left out and why the run stopped.

# 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 = {
    "keyword": "Elektriker",
    "location": "Berlin"
};

// Run the Actor and wait for it to finish
const run = await client.actor("perceptr0n/hiring-companies-germany").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 = {
    "keyword": "Elektriker",
    "location": "Berlin",
}

# Run the Actor and wait for it to finish
run = client.actor("perceptr0n/hiring-companies-germany").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 '{
  "keyword": "Elektriker",
  "location": "Berlin"
}' |
apify call perceptr0n/hiring-companies-germany --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,perceptr0n/hiring-companies-germany"
        }
    }
}
```

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/lavs8TOaLKw1V0bFK/builds/DbLJG9Xij6TVsPY8x/openapi.json
