# Arbeitsagentur Jobs Scraper (Germany: Bundesagentur für Arbeit) (`swissalpinedata/arbeitsagentur-jobs-scraper`) Actor

Scrapes job listings from Germany's Bundesagentur für Arbeit (Arbeitsagentur) job board via its public JSON API.

- **URL**: https://apify.com/swissalpinedata/arbeitsagentur-jobs-scraper.md
- **Developed by:** [WebAlpine Studio](https://apify.com/swissalpinedata) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 job listings

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

## Arbeitsagentur Jobs Scraper (Germany: Bundesagentur für Arbeit Jobsuche)

Collects job listings from the public job board of the Bundesagentur für Arbeit (German Federal Employment Agency), the largest job board in Germany, through the same JSON API that the official Jobsuche website and app use. No HTML parsing is involved, so the data is structured, complete, and stable.

### Why this actor

- Official source: the public JSON API behind the Jobsuche website and app of the Bundesagentur für Arbeit, the largest job board in Germany.
- No login, no account and no browser. The Actor calls the same endpoint the official app uses, with polite delays and retries.
- Structured fields straight from the API: title, employer, location with coordinates, working time, contract type, salary where given, dates and the reference number.

### What it does

You give the actor a keyword (job title, skill, or profession) and optionally a place, a radius, and filters such as working time, contract type, or publication age. It queries the Arbeitsagentur Jobsuche API page by page, removes duplicates, and stores every listing as one flat JSON record with title, employer, location with coordinates, publication and start dates, salary information where the employer provided it, and working time flags. With `fetchDetails` enabled it also fetches the full job description text for each listing.

### Why use it

- The Arbeitsagentur board lists well over a million open positions, including apprenticeships and internships, many of which never appear on commercial job boards.
- Structured fields instead of scraped HTML: coordinates, postal codes, salary ranges, contract duration, home office and shift flags, all straight from the source.
- Filters are applied server side, so you only pay for the listings you actually want.
- Typical run time is a few seconds per 100 listings without descriptions, or roughly one second per listing with `fetchDetails`.

### Input

| Field | Type | Description |
| --- | --- | --- |
| `was` | string, required | Keyword, job title, skill, or profession to search for. |
| `wo` | string | City, region, or postal code to search around. Leave empty to search all of Germany. |
| `umkreis` | integer | Search radius in kilometers around `wo`. Default 25. Ignored when `wo` is empty. |
| `angebotsart` | enum | Offer type: Arbeit (employment), Selbstständigkeit (self-employment), Ausbildung (apprenticeship), or Praktikum (internship). Default Arbeit. |
| `arbeitszeit` | array of enum | Working time filter: Vollzeit, Teilzeit, Schicht/Nacht/Wochenende, Homeoffice, Minijob. Leave empty for all. |
| `befristung` | enum | Contract duration filter: befristet (fixed term) or unbefristet (permanent). Leave empty for all. |
| `veroeffentlichtseit` | integer | Only return jobs published within this many days. |
| `zeitarbeit` | boolean | Whether to include jobs from temp work agencies. Leave unset to include both. |
| `fetchDetails` | boolean | Fetch the full job description text and the temp agency flag for each listing. One extra request per job, so slower. Default false. |
| `maxItems` | integer | Maximum number of listings to collect. Default 100, maximum 10,000. |

Example input:

```json
{
  "was": "Pflegefachkraft",
  "wo": "München",
  "umkreis": 25,
  "arbeitszeit": ["tz"],
  "befristung": "2",
  "veroeffentlichtseit": 7,
  "maxItems": 50
}
```

### Output example

One record per job listing. This is a real record from a run with `fetchDetails` enabled, with the description shortened.

```json
{
  "source": "arbeitsagentur",
  "refnr": "12016-10005207786-S",
  "url": "https://www.arbeitsagentur.de/jobsuche/jobdetail/12016-10005207786-S",
  "external_url": null,
  "title": "Softwareentwickler m/w/d *",
  "profession": "Softwareentwickler/in",
  "all_professions": "Softwareentwickler/in, Datenbankentwickler/in",
  "employer": "PerZukunft Arbeitsvermittlung GmbH & Co. KG",
  "location_city": "Berlin",
  "location_zip": "12163",
  "location_region": "BERLIN",
  "location_country": "DEUTSCHLAND",
  "latitude": 52.462501889,
  "longitude": 13.31995116,
  "location_count": 1,
  "published_at": "2026-08-31",
  "entry_date": "2026-09-03",
  "modified_at": "2026-08-31T13:01:15.045",
  "offer_type": "ARBEIT",
  "contract_duration": "KEINE_ANGABE",
  "fixed_term_months": null,
  "salary_from": 30.26,
  "salary_to": 30.26,
  "salary_type": "STUNDENLOHN",
  "salary_unit": "FESTGEHALT",
  "fulltime": true,
  "part_time": null,
  "shift_work": null,
  "homeoffice_possible": null,
  "minijob": false,
  "career_changer_ok": false,
  "temp_agency": false,
  "description": "Ab [sofort] suchen wir einen Softwareentwickler m/w/d in Vollzeit für eine mittelständige Papierfabrik in Berlin - Neukölln. Ihr Einstiegsgehalt liegt bei [30,26] €/h. ...",
  "scraped_at": "2026-09-22T20:31:33.966978+00:00"
}
```

Field notes:

- `refnr` is the Arbeitsagentur reference number and is unique per listing. `url` opens the listing on arbeitsagentur.de, `external_url` is the employer's own application page when one exists.
- `location_*`, `latitude`, and `longitude` describe the first work location. `location_count` tells you how many locations the listing has.
- `published_at` and `entry_date` are ISO dates, `modified_at` and `scraped_at` are ISO timestamps.
- `salary_from` and `salary_to` are only present when the employer entered a salary. `salary_type` says what the number means (for example STUNDENLOHN for hourly, MONATSGEHALT for monthly, JAHRESGEHALT for yearly, KEINE\_ANGABEN when nothing was given).
- `contract_duration` is UNBEFRISTET, BEFRISTET, or KEINE\_ANGABE. `fixed_term_months` is filled for fixed term contracts when known.
- Boolean flags (`fulltime`, `part_time`, `shift_work`, `homeoffice_possible`, `minijob`, `career_changer_ok`) are `null` when the listing does not state them.
- `description` and `temp_agency` are only filled when `fetchDetails` is enabled. Descriptions are plain text as provided by the employer.
- The actor never invents values. Any field the API does not return for a listing is `null`.

### Pricing

This Actor uses pay per result. You pay **USD 0.002 per job listing**, which is **USD 2.00 per 1,000 results**. There is no charge per run or per request, and a run that returns no results produces no result charges.

| Results | Price |
| --- | --- |
| 100 | USD 0.20 |
| 1,000 | USD 2.00 |
| 10,000 | USD 20.00 |

A daily run with 200 new listings costs USD 0.40, about USD 12 per month. Set `maxItems` to cap the cost of a run.

### Limitations

- The API returns at most 10,000 listings per search. For broad queries such as "Pflege" (over 100,000 matches) narrow the search by place, radius, offer type, or publication age and run the actor several times.
- Only the first work location is flattened into the record. Listings with several locations show `location_count` greater than 1.
- Salary information is optional for employers, so it is missing on most listings.
- The API does not expose a postal address for the employer, only for the work location.
- Fetching descriptions requires one additional request per listing with a short polite delay, so large runs with `fetchDetails` take longer.

### Legal

The actor only reads publicly available data from the Bundesagentur für Arbeit job board through the same public API that powers arbeitsagentur.de. No login, paywall, or bot protection is bypassed and no proxies are used. Job listings can contain personal data such as contact names and phone numbers of recruiters. What you do with the collected data, and whether your processing of it complies with the GDPR and the terms of use of the Bundesagentur für Arbeit, is your responsibility.

### FAQ

**Which job board is this?**
The Jobsuche of the Bundesagentur für Arbeit at arbeitsagentur.de/jobsuche, the official German public employment agency job board.

**Does this actor use a proxy?**
No. The API is public and does not block requests at the polite rate the actor uses.

**Why are some fields null?**
The API does not return a value for every field on every listing. The actor leaves the field null instead of guessing.

**How do I get the full job description?**
Enable `fetchDetails`. The actor then calls the job details endpoint once per listing. Expect roughly one listing per second.

**Why did I get fewer results than `maxItems`?**
Either the search matched fewer listings, or the search matched more than 10,000 and the API stopped serving pages. The log tells you which. Narrow the query to get more.

**Can I search apprenticeships or internships?**
Yes, set `angebotsart` to Ausbildung or Praktikum.

### Changelog

**0.1.x** (2026-09-25): README with concrete pricing and a short summary of the data source. No change to the output.

**0.1**: Initial release. Search by keyword, place, radius, offer type, working time, contract duration, publication age, and temp agency flag, with optional full description fetch.

# Actor input Schema

## `was` (type: `string`):

Job title, skill, or keyword to search for (the API's "was" parameter).

## `wo` (type: `string`):

City, region, or postal code to search around (the API's "wo" parameter). Leave empty to search all of Germany.

## `umkreis` (type: `integer`):

Search radius in kilometers around the place given in "wo". Ignored when "wo" is empty.

## `angebotsart` (type: `string`):

Type of job offer to search for.

## `arbeitszeit` (type: `array`):

Filter by working time model. Leave empty for all.

## `befristung` (type: `string`):

Filter by whether the contract is fixed term or permanent. Leave empty for all.

## `veroeffentlichtseit` (type: `integer`):

Only return jobs published within this many days. Leave empty for all.

## `zeitarbeit` (type: `boolean`):

Whether to include jobs offered by temp work agencies. Leave unset to include both.

## `fetchDetails` (type: `boolean`):

If enabled, fetches the full job description text and the temp agency flag for each result via the job details endpoint (one extra request per job, with a polite delay). Slower but richer output.

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

Maximum number of job listings to collect. The API exposes at most 10,000 results per search, so narrow the query (place, radius, filters) to reach more jobs.

## Actor input object example

```json
{
  "was": "Softwareentwickler",
  "wo": "Berlin",
  "umkreis": 25,
  "angebotsart": "1",
  "fetchDetails": false,
  "maxItems": 100
}
```

# Actor output Schema

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

All records returned by this run, as JSON.

# 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 = {
    "was": "Softwareentwickler",
    "wo": "Berlin",
    "umkreis": 25,
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("swissalpinedata/arbeitsagentur-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 = {
    "was": "Softwareentwickler",
    "wo": "Berlin",
    "umkreis": 25,
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("swissalpinedata/arbeitsagentur-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 '{
  "was": "Softwareentwickler",
  "wo": "Berlin",
  "umkreis": 25,
  "maxItems": 100
}' |
apify call swissalpinedata/arbeitsagentur-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,swissalpinedata/arbeitsagentur-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/qaRiCIkWb9f9cp3wW/builds/U1xxWINw35YRhghbI/openapi.json
