# Absolventa Germany Graduate Jobs Scraper (`jpopendata/germany-jobs-absolventa`) Actor

German graduate and young-professional jobs from Absolventa (absolventa.de): title, employer, city, salary when shown, permanent/internship/working student/trainee, home office, posted date. Keyword, city and field filters. No personal data. Unofficial; not affiliated with Absolventa.

- **URL**: https://apify.com/jpopendata/germany-jobs-absolventa.md
- **Developed by:** [JP Open Data](https://apify.com/jpopendata) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 per results

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

## Absolventa Germany Graduate Jobs Scraper

**Job postings from Absolventa (absolventa.de), the German job board for graduates and young professionals with about 30,000 open positions: title, employer, city, salary when shown, position type (permanent job, internship, working student, trainee, thesis), home office, work hours, posted date and listing end date, in a clean English schema.**

Search by keyword (German or English) and optionally by city, position type and job field — the same search a visitor runs on absolventa.de.

> **Unofficial tool. Not affiliated with or endorsed by Absolventa or FUNKE Works GmbH.** It reads public pages only (no login), politely (strictly serial requests at least 1.5 s apart, a hard per-run request budget, no block evasion), requests only URLs the site's robots.txt allows, and extracts **job facts only — no personal data** (see "Privacy" below). You are responsible for making sure your use of the data complies with the site's terms and applicable law (including the GDPR).

***

### Quick start — verified input

This input was run successfully on the Apify platform on 2026-10-04 (5 jobs per keyword with job-page details, 12 requests, about 20 seconds, default German residential proxy). Running with an empty input `{}` uses exactly these values.

```json
{
  "keywords": ["Data Analyst", "Ingenieur"],
  "maxItemsPerKeyword": 5
}
```

A larger list-only pull (20 jobs per request, no job pages):

```json
{
  "keywords": ["Werkstudent Marketing", "Junior Controller", "Softwareentwickler"],
  "location": "München",
  "includeDetails": false,
  "maxItemsPerKeyword": 100,
  "maxApiRequests": 20
}
```

Typical German search terms: `Werkstudent`, `Praktikum`, `Trainee`, `Berufseinsteiger`, `Junior Consultant`, `Ingenieur`, `Softwareentwickler`, `Controlling`, `Vertrieb`, `Personal` (HR). English titles such as `Data Analyst` or `Product Manager` work too.

#### Common input mistakes

| Wrong | Right | Why |
|---|---|---|
| `"location": "Bavaria"` | `"location": "München"` | One city or postcode, as typed on the site. |
| `"positionTypes": ["part-time"]` | `"positionTypes": ["werkstudent"]` | Valid: festanstellung, praktikum, werkstudent, trainee, abschlussarbeit (English names work). Part-time shows in `workHours`. |
| `"categories": ["Data Science"]` | `"categories": ["it"]` | Use the site's job fields (88; the error message lists them). |
| `"maxItemsPerKeyword": 200` with details on | also raise `"maxApiRequests"` or set `"includeDetails": false` | With details, every job costs one extra request. |

An invalid value stops the run immediately, before any request, with a message that names the field and lists the valid values. Numbers outside their range are clamped with a warning.

#### Empty results?

A search with no matching jobs finishes with 0 items and `complete: true` — not an error. Try a shorter or German title, a bigger city, or fewer filters.

***

### Output

One dataset item per job posting:

```json
{
  "keyword": "Ingenieur",
  "jobId": "13261078",
  "title": "Ingenieur oder Meister/Techniker Elektrotechnik / Sekundärtechnik / Automatisierung (w/m/d)",
  "companyName": "Flughafen München Konzern",
  "city": "München-Flughafen",
  "locations": ["München-Flughafen"],
  "moreLocationsCount": 0,
  "country": "DE",
  "homeOfficePossible": true,
  "workHours": "full-or-part-time",
  "salaryMinEur": 60000,
  "salaryMaxEur": 81000,
  "salaryText": "60000 bis 81000 €",
  "positionType": "permanent",
  "positionTypeLabel": "Festanstellung",
  "employmentTypes": ["FULL_TIME"],
  "industry": "automatisierungstechnik",
  "postedDate": "2026-09-30",
  "validThrough": "2026-11-22",
  "quickApply": false,
  "isPremium": true,
  "isNew": false,
  "detailsFetched": true,
  "jobUrl": "https://www.absolventa.de/stellenangebote/13261078-p-ingenieur-oder-meister-techniker-elektrotechnik-sekundaertechnik-automatisierung-w-m-d",
  "source": "Absolventa (www.absolventa.de public job list)",
  "sourceUrl": "https://www.absolventa.de/jobs",
  "license": "Publicly available data — unofficial tool; users are responsible for compliance with the source site's terms",
  "retrievedAt": "2026-10-04T09:45:58.659Z"
}
```

- `salaryText` is exactly what the job card shows; the amounts are as published (usually yearly gross EUR; the period is not stated on the card).
- `validThrough` is the end of the listing period from the job page's structured data, not necessarily an application deadline.
- With `includeDetails: false`, `postedDate`, `validThrough`, `positionType`, `employmentTypes` and `industry` are `null`/`[]` and `detailsFetched` is `false`.
- `RUN_SUMMARY` in the key-value store lists per keyword the upstream total, list and job pages read, items stored, `complete`, `stopReason` and `landingPage`.

### Landing pages (important for filters)

For some keyword + city pairs the site itself replaces the search with one of its landing pages (e.g. "Controlling" in "Berlin" becomes "Controlling jobs in Berlin"). The Actor follows that, like a browser. On those pages the site does **not** apply the position-type and salary filters, so the Actor checks them itself: cards without a salary are dropped for `withSalaryOnly`, and with `positionTypes` each job page is checked (needs `includeDetails: true`; otherwise the keyword stops with an explanation instead of returning wrong job types).

### Privacy (GDPR)

Only company facts about the job are returned: no street address or postcode (city only, district suffixes removed), no contact person, e-mail or phone, and no description text. E-mail addresses and phone numbers inside titles are replaced with `[contact removed]`. Employer names are published as the company presents itself; a sole trader's business name can contain a person's name.

### Honest limits

- **Snapshot, site order.** Results follow the site's ranking (paid "Premium" listings often come first); `retrievedAt` tells you when the data was read.
- **Job pages cost requests.** 1 request per list page of 20 jobs, plus 1 per job with `includeDetails`. Jobs whose page has just been removed are stored from the card (`detailsFetched: false`).
- **Residential proxy by default.** absolventa.de answers Apify datacenter IPs with a "Human Verification" page (tested 2026-10-04), so the default `proxyConfiguration` is Apify RESIDENTIAL, country DE (residential traffic is billed by Apify; a Quick start run transfers a few MB at most). One sticky IP is used per run; verification pages are never solved — if one appears, the run stops (or fails if nothing was collected yet).
- **The site can refuse requests.** If it blocks mid-run, the run keeps what it has and ends successfully with `complete: false`; if the first request is blocked, the run fails visibly.

### Pricing

Pay per result: you are charged for each job stored in the dataset. A run stops by itself when it reaches the maximum charge you set for the run.

# Actor input Schema

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

Job titles, skills or employer names, one per line, German or English, e.g. "Controlling", "Werkstudent Marketing", "Data Scientist", "Ingenieur". Each keyword is searched separately and every record carries its keyword. Use "\*" for all jobs. Up to 50 per run. If empty, the Quick start keywords are used.

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

Optional. One German city or postcode, as you would type it on absolventa.de, e.g. "Berlin", "München", "Frankfurt am Main", "50667". Leave empty for all of Germany.

## `positionTypes` (type: `array`):

Optional, any of: festanstellung (permanent job), praktikum (internship), werkstudent (working student), trainee (trainee programme), abschlussarbeit (thesis). English names work too. Sent as the site's own filter; when the site turns the search into one of its landing pages (which ignore this filter), the Actor checks each job page instead (needs includeDetails). Leave empty for all.

## `categories` (type: `array`):

Optional. The site's job fields, e.g. it, softwareentwicklung, controlling, marketing, vertrieb, human-resources, maschinenbau, elektrotechnik, consulting, pflege. English names work too (software, finance, engineering, hr). Leave empty for all fields.

## `withSalaryOnly` (type: `boolean`):

Only jobs that show a salary. Sent as the site's own filter and re-checked on every job card (cards without a salary are dropped).

## `homeOfficeOnly` (type: `boolean`):

Keep only jobs tagged "Homeoffice möglich" / remote. Applied after fetching each list page, so it may need more requests.

## `includeDetails` (type: `boolean`):

true (default): one extra request per job reads the job page's structured data — posted date, position type (Festanstellung, Praktikum ...), employment type, industry, listing end date and all locations. false: list-page facts only (title, employer, city, salary if shown, home office, part-time), 20 jobs per request — much faster for large pulls.

## `maxItemsPerKeyword` (type: `integer`):

Job records kept per keyword (1..2000; values outside are clamped).

## `maxApiRequests` (type: `integer`):

Hard budget of requests to absolventa.de for the whole run (1..1000; clamped), shared fairly between keywords. Each list page (20 jobs) is 1 request; with includeDetails each job page is 1 more. Requests are strictly serial with at least 1.5 s spacing. If the budget runs out the run still SUCCEEDS with the jobs found so far and complete=false in RUN_SUMMARY.

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

Default: Apify RESIDENTIAL proxy, country DE. absolventa.de answers Apify datacenter IPs with a "Human Verification" page (tested 2026-10-04), so a residential German IP is needed on the platform. The run keeps a single sticky session (one IP) — never rotation; verification pages are never solved.

## Actor input object example

```json
{
  "keywords": [
    "Data Analyst",
    "Ingenieur"
  ],
  "location": "",
  "positionTypes": [],
  "categories": [],
  "withSalaryOnly": false,
  "homeOfficeOnly": false,
  "includeDetails": true,
  "maxItemsPerKeyword": 5,
  "maxApiRequests": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}
```

# Actor output Schema

## `records` (type: `string`):

Absolventa job postings with source attribution (source, sourceUrl, license, retrievedAt) on every item.

# 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": [
        "Data Analyst",
        "Ingenieur"
    ],
    "location": "",
    "positionTypes": [],
    "categories": [],
    "withSalaryOnly": false,
    "homeOfficeOnly": false,
    "includeDetails": true,
    "maxItemsPerKeyword": 5,
    "maxApiRequests": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jpopendata/germany-jobs-absolventa").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": [
        "Data Analyst",
        "Ingenieur",
    ],
    "location": "",
    "positionTypes": [],
    "categories": [],
    "withSalaryOnly": False,
    "homeOfficeOnly": False,
    "includeDetails": True,
    "maxItemsPerKeyword": 5,
    "maxApiRequests": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("jpopendata/germany-jobs-absolventa").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": [
    "Data Analyst",
    "Ingenieur"
  ],
  "location": "",
  "positionTypes": [],
  "categories": [],
  "withSalaryOnly": false,
  "homeOfficeOnly": false,
  "includeDetails": true,
  "maxItemsPerKeyword": 5,
  "maxApiRequests": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}' |
apify call jpopendata/germany-jobs-absolventa --silent --output-dataset

```

## MCP server setup

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

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/MhtCDeoiddPJfwAxT/builds/d8H4wFX500fLxgYIm/openapi.json
