# Germany Jobs Scraper: Arbeitsagentur Jobbörse & Arbeitnow (`datadesk-io/germany-jobs-scraper`) Actor

Scrape German jobs from the Bundesagentur für Arbeit Jobbörse (1M+ jobs) and Arbeitnow by keyword, city and radius: title, employer, salary, full/part-time, contract, remote %, address with coordinates, posting date and URL. Job alerts mode. No login. $1 per 1,000 jobs.

- **URL**: https://apify.com/datadesk-io/germany-jobs-scraper.md
- **Developed by:** [DataDesk](https://apify.com/datadesk-io) (community)
- **Categories:** Jobs, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 jobs

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

## Germany Jobs Scraper: Arbeitsagentur Jobbörse & Arbeitnow

Scrape **jobs in Germany** from the **Bundesagentur für Arbeit Jobbörse** (the federal employment agency's job board, 1M+ live jobs) and **Arbeitnow** by keyword, city and radius. Every job comes with **employer, occupation, full/part-time, contract type, home-office share, published salary, full address with coordinates**, start date, posting date and URL. Apprenticeships (Ausbildung) and internships too. No login, no proxies. **$1 per 1,000 jobs.**

### What you get

| Job fields | Location & pay fields |
|---|---|
| title, companyName, occupation, occupations | street, postalCode, city, region (federal state) |
| offerType (job, apprenticeship, internship) | latitude, longitude, distanceKm |
| workingTime, contractType, fixedTermMonths | salary, salaryPeriod, salaryYearly (EUR) |
| isRemote, remotePercent | startDate, postedAt, updatedAt |
| url, externalUrl, description, tags | suitableForCareerChangers |

### Sources and coverage

| Source | Coverage | Data |
|---|---|---|
| **Bundesagentur für Arbeit Jobbörse** | All of Germany, all industries and skill levels (15,000+ electrician jobs alone) | title, employer, occupation, working time, contract, home office, salary when published, address, coordinates |
| **Arbeitnow** | Germany, mostly English-speaking, tech and startup jobs | title, company, remote flag, job types, tags, description |

### How to use it

1. Click **Try for free** (or **Start**): the prefilled input runs a quick test.
2. Fill in the input fields (see the examples below). Every field is optional.
3. Click **Start** and wait a few seconds to minutes, depending on how many jobs you ask for.
4. Open the **Output** tab and export as **JSON, CSV, Excel, XML or HTML**, or read the results via API.

### Input examples

**Software developers in Berlin (default):**

```json
{"keywords": ["Softwareentwickler"], "locations": ["Berlin"], "maxJobsPerSearch": 20}
```

**Part-time nursing and kitchen jobs in Munich, last 7 days:**

```json
{"keywords": ["Pflegefachkraft", "Koch"], "locations": ["München"], "workingTime": ["part-time"], "postedWithinDays": 7}
```

**Apprenticeships in Hamburg:**

```json
{"keywords": ["Kaufmann"], "locations": ["Hamburg"], "offerType": "apprenticeship"}
```

**Daily alert, remote IT jobs, no temp agencies:**

```json
{"keywords": ["Informatiker"], "remoteOnly": true, "excludeTempAgencies": true, "onlyNewJobs": true, "alertsKey": "de-it-remote"}
```

#### Input fields

| Field | Type | Description |
|---|---|---|
| `keywords` | array | Job titles or keywords in German or English, e.g. Softwareentwickler, Pflegefachkraft, Elektriker, Buchhalter, developer. Empty = all jobs. |
| `locations` | array | German cities or postal codes, e.g. Berlin, München, Hamburg, 50667. Empty = all of Germany. |
| `radiusKm` | integer | Search radius around each city (Arbeitsagentur). |
| `sources` | array | Job boards to search. Arbeitnow has fewer, mostly English-speaking and tech jobs, matched by keyword. |
| `offerType` | string | Kind of offer (Arbeitsagentur). Arbeitnow is searched only for regular jobs. |
| `workingTime` | array | Only these working-time models (Arbeitsagentur). Empty = all. |
| `remoteOnly` | boolean | Keep only jobs that allow home office or remote work. |
| `minYearlySalary` | integer | Keep only Arbeitsagentur jobs with a published salary of at least this much per year (hourly and monthly pay are converted). Most jobs publish no salary, so this filter removes many rows. |
| `excludeTempAgencies` | boolean | Hide jobs from temporary staffing agencies. |
| `employer` | string | Only jobs from this employer name, e.g. Deutsche Bahn (Arbeitsagentur). |
| `maxJobsPerSearch` | integer | Stop after this many jobs for each keyword and city (and for Arbeitnow overall). |
| `postedWithinDays` | integer | Only jobs published in the last N days (e.g. 7). 0 = any date. |
| `onlyNewJobs` | boolean | Return only jobs not seen in previous runs. Schedule daily for alerts. |
| `alertsKey` | string | Name for this alert's memory (e.g. berlin-devs). Use a different key per alert so "only new jobs" works separately. |

### Output example

One row per job. Values below are **example values** from a real test run:

```json
{
  "source": "arbeitsagentur",
  "jobId": "10001-1003891446-S",
  "title": "Softwareentwicklerin (w/m/d)",
  "companyName": "GASAG AG",
  "occupation": "Softwareentwickler/in",
  "occupations": [
    "Softwareentwickler/in",
    "Softwareentwickler/in"
  ],
  "offerType": "job",
  "workingTime": [
    "full-time"
  ],
  "contractType": "fixed-term",
  "fixedTermMonths": 24,
  "isRemote": true,
  "remotePercent": 50,
  "salary": 72600.0,
  "salaryPeriod": "year",
  "salaryCurrency": "EUR",
  "salaryYearly": 72600,
  "street": "EUREF-Campus 23-24",
  "postalCode": "10829",
  "city": "Berlin",
  "region": "Berlin",
  "country": "Deutschland",
  "latitude": 52.480611,
  "…": "more fields below"
}
```

Fields a source does not publish are `null`.

#### Output fields

| Field | Description |
|---|---|
| `source` | Job board the job came from (arbeitsagentur or arbeitnow) |
| `jobId` | Reference number (Arbeitsagentur) or slug (Arbeitnow) |
| `title` | Job title |
| `companyName` | Employer name |
| `occupation` | Main occupation (Beruf) as classified by the Arbeitsagentur |
| `occupations` | All occupations linked to the job |
| `offerType` | job, apprenticeship, internship or self-employment |
| `workingTime` | Working-time models (full-time, part-time, shift/night/weekend) |
| `contractType` | permanent or fixed-term |
| `fixedTermMonths` | Length of a fixed-term contract in months |
| `isRemote` | True if home office / remote work is possible |
| `remotePercent` | Share of home office in percent, if published |
| `salary` | Published fixed pay (EUR) |
| `salaryPeriod` | Pay period of salary (hour, month, year) |
| `salaryCurrency` | Salary currency (EUR) |
| `salaryYearly` | Salary converted to a yearly amount (EUR) |
| `street` | Street and number of the workplace |
| `postalCode` | Postal code (PLZ) |
| `city` | City |
| `region` | Federal state |
| `country` | Country |
| `latitude` | Latitude of the workplace |
| `longitude` | Longitude of the workplace |
| `locations` | All job locations (cities) |
| `startDate` | Earliest start date |
| `postedAt` | First publication date (ISO, UTC) |
| `updatedAt` | Last change on the Arbeitsagentur |
| `suitableForCareerChangers` | True if suitable for career changers (Quereinsteiger) |
| `distanceKm` | Distance from the searched city (km) |
| `externalUrl` | Original posting on the employer's or partner site, if any |
| `description` | Job description text (Arbeitnow) |
| `tags` | Tags (Arbeitnow) |
| `url` | Job posting URL |
| `searchKeyword` | Keyword that found this job |
| `searchLocation` | City of the search this job came from |
| `scrapedAt` | Scrape time (ISO, UTC) |
| `isNew` | True if no earlier run with the same alerts key returned this job |

The Output tab has a **Jobs** view.

### Pricing

Pay-per-event: you pay only for results delivered, no monthly fee.

- **Job** (`job`): **$1.00 per 1,000** ($0.001 each)
- **Actor start:** $0.005 per run

| Run | Jobs | Cost |
|---|---|---|
| Quick test | 20 | $0.025 |
| Small run | 100 | $0.105 |
| Regular run | 1,000 | $1.005 |
| Large run | 10,000 | $10.005 |

Rows that are not delivered are never charged. Apify's free plan includes monthly credit, and you can set a maximum cost per run in the run options.

### Use cases

- **Recruiters & staffing agencies**: find employers hiring in a city or trade right now (sales leads with address and coordinates).
- **Job boards & aggregators**: feed German jobs into your site or app.
- **Labour-market research**: demand by occupation, region, working time and salary.
- **Job seekers & relocation services**: daily alerts with *Only new jobs*.

### Integrations and API

- Export results as JSON, CSV, Excel, XML or HTML from the Output tab.
- **Schedule** runs (daily, hourly) and send results to Google Sheets, Slack, Zapier, Make, n8n, Airbyte or webhooks.
- Call it from code with the [Apify API](https://docs.apify.com/api/v2):

```bash
curl -X POST "https://api.apify.com/v2/acts/datadesk-io~germany-jobs-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["Softwareentwickler"], "locations": ["Berlin"], "maxJobsPerSearch": 20}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("datadesk-io/germany-jobs-scraper").call(run_input={"keywords": ["Softwareentwickler"], "locations": ["Berlin"], "maxJobsPerSearch": 20})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item.get("title"), item.get("companyName"), item.get("city"), item.get("url"))
```

### FAQ

**Do I need a login, API key or proxies?** No. It uses publicly available job search data only.

**Can I search in English?** Yes, but the Arbeitsagentur matches German job titles best (Softwareentwickler, Buchhalter, Pflegefachkraft). Arbeitnow jobs are mostly in English.

**Why do few jobs have a salary?** Employers in Germany often do not publish pay. When they do, you get the amount, the period and a yearly figure.

**Why did I get fewer jobs than the maximum?** The source had fewer matching jobs, or duplicates were removed. You only pay for jobs delivered.

**Is it legal?** It collects only publicly available data. You are responsible for using it in line with applicable laws (e.g. GDPR) and the sources' terms.

### Limitations

The Actor reads up to 10,000 Arbeitsagentur jobs per keyword and city, so split very large searches by city or keyword. Arbeitnow is read politely (one page every 2–3 s, at most 10 pages per run) and filtered by keyword in the title, company and tags. Full job descriptions are available for Arbeitnow jobs only; Arbeitsagentur jobs link to the full posting.

### Support

Found a bug, or need a new field, source or filter? Open an issue in the **Issues** tab; we usually answer within 24 hours. Custom data work: datadesk.io@proton.me.

# Actor input Schema

## `keywords` (type: `array`):

Job titles or keywords in German or English, e.g. Softwareentwickler, Pflegefachkraft, Elektriker, Buchhalter, developer. Empty = all jobs.

## `locations` (type: `array`):

German cities or postal codes, e.g. Berlin, München, Hamburg, 50667. Empty = all of Germany.

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

Search radius around each city (Arbeitsagentur).

## `sources` (type: `array`):

Job boards to search. Arbeitnow has fewer, mostly English-speaking and tech jobs, matched by keyword.

## `offerType` (type: `string`):

Kind of offer (Arbeitsagentur). Arbeitnow is searched only for regular jobs.

## `workingTime` (type: `array`):

Only these working-time models (Arbeitsagentur). Empty = all.

## `remoteOnly` (type: `boolean`):

Keep only jobs that allow home office or remote work.

## `minYearlySalary` (type: `integer`):

Keep only Arbeitsagentur jobs with a published salary of at least this much per year (hourly and monthly pay are converted). Most jobs publish no salary, so this filter removes many rows.

## `excludeTempAgencies` (type: `boolean`):

Hide jobs from temporary staffing agencies.

## `employer` (type: `string`):

Only jobs from this employer name, e.g. Deutsche Bahn (Arbeitsagentur).

## `maxJobsPerSearch` (type: `integer`):

Stop after this many jobs for each keyword and city (and for Arbeitnow overall).

## `postedWithinDays` (type: `integer`):

Only jobs published in the last N days (e.g. 7). 0 = any date.

## `onlyNewJobs` (type: `boolean`):

Return only jobs not seen in previous runs. Schedule daily for alerts.

## `alertsKey` (type: `string`):

Name for this alert's memory (e.g. berlin-devs). Use a different key per alert so "only new jobs" works separately.

## Actor input object example

```json
{
  "keywords": [
    "Softwareentwickler"
  ],
  "locations": [
    "Berlin"
  ],
  "radiusKm": 25,
  "sources": [
    "arbeitsagentur",
    "arbeitnow"
  ],
  "offerType": "job",
  "remoteOnly": false,
  "excludeTempAgencies": false,
  "maxJobsPerSearch": 20,
  "postedWithinDays": 0,
  "onlyNewJobs": false
}
```

# Actor output Schema

## `jobs` (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 = {
    "keywords": [
        "Softwareentwickler"
    ],
    "locations": [
        "Berlin"
    ],
    "maxJobsPerSearch": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("datadesk-io/germany-jobs-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 = {
    "keywords": ["Softwareentwickler"],
    "locations": ["Berlin"],
    "maxJobsPerSearch": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("datadesk-io/germany-jobs-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 '{
  "keywords": [
    "Softwareentwickler"
  ],
  "locations": [
    "Berlin"
  ],
  "maxJobsPerSearch": 20
}' |
apify call datadesk-io/germany-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datadesk-io/germany-jobs-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/avmXMu6fpfkaOME5H/builds/LfLsKKOcMaVEwi2gF/openapi.json
