# Stepstone Jobs Scraper (`apexdatalabs/stepstone-jobs-scraper`) Actor

Stepstone scraper API for Germany's largest job board. Extract job listings to clean JSON (jobs\_v1 schema): title, company, location, salary, remote type, dates. 100% measured run success, monitored daily, fixed fast. No recruiter or contact-person data, by design.

- **URL**: https://apify.com/apexdatalabs/stepstone-jobs-scraper.md
- **Developed by:** [APEX Data Labs](https://apify.com/apexdatalabs) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 job 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?

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

## Stepstone Jobs Scraper

![uptime](https://img.shields.io/badge/uptime-pending_first_canary-lightgrey)

Turn StepStone.de searches into clean, structured job data. Give it keywords
and a location — or paste full search URLs — and get back a consistent,
analysis-ready dataset: title, company, location, salary when the posting
shows one, employment type, remote status, posting date, and the full
description. Built for recruiting analytics, labor-market research, and
job-aggregation pipelines that need dependable output day after day.

Runs on a monitored chassis: an automated canary exercises this actor daily,
and failures are diagnosed and patched under human review. Uptime and
mean-time-to-repair are published in the badge above.

### Try it in 20 seconds

Press **Start** with the prefilled input (data engineer / Berlin, 20 jobs) —
a first run finishes in well under a minute and costs about $0.13. Then raise
`maxItems` or paste your own StepStone search URLs.

### What one result looks like

```json
{
  "board": "stepstone_de",
  "board_job_id": "11713465",
  "url": "https://www.stepstone.de/stellenangebote--Data-Engineer-Machine-Learning-Engineer-...-11713465-inline.html",
  "title": "Data Engineer* / Machine Learning Engineer*",
  "company_name": "inovex GmbH",
  "company_url": "https://www.stepstone.de/cmp/de/inovex-gmbh-24494/jobs",
  "location_raw": "Karlsruhe, Köln, München, Hamburg, Stuttgart, Berlin, Erlangen",
  "country_code": "DE",
  "remote_type": "hybrid",
  "employment_type": "full_time",
  "salary_raw": null,
  "posted_at": "2026-08-10T02:01:19.477Z",
  "description_text": "Seit 25 Jahren unterstützen wir bei inovex mit rund 500 IT-Expert:innen …",
  "tags": ["IT, IT-Datenbanken"],
  "scraped_at": "2026-08-15T23:02:56+00:00"
}
```

Real row from a monitoring run — nothing hand-edited except the trimmed description.

### Why this one

- **Measured, not promised.** Before pricing, we ran 660 results across two
  time windows on three proxy tiers and shipped the configuration that
  succeeded on every run. A canary re-runs both input paths every day.
- **Same schema across boards.** Output is `jobs_v1`, the field contract
  shared by all our job-board actors — combine boards without remapping.
- **Removed listings handled.** Expired postings are detected three ways
  (structured-data absence, canonical drift, "nicht mehr verfügbar" text)
  and skipped, never emitted as ghost jobs.
- **Job data only.** No recruiter or contact-person fields, by design.

### Output schema

This actor emits `jobs_v1` — the same field contract as every job-board actor
we publish, so multi-board pipelines never remap fields.

| Field | Type | Description |
|---|---|---|
| board | string | Always `stepstone_de` |
| board\_job\_id | string | StepStone's job ID — dedup key together with `board` |
| url | string | Canonical posting URL |
| title | string | Job title |
| company\_name | string | Hiring company |
| company\_url | string/null | Company profile link |
| location\_raw | string | Location as displayed |
| city, region | string/null | Parsed location parts |
| country\_code | string | ISO country (DE) |
| remote\_type | string/null | onsite / hybrid / remote |
| employment\_type | string/null | full\_time / part\_time / contract / internship / apprenticeship |
| salary\_min/max/currency/period | number/string/null | Parsed salary |
| salary\_raw | string/null | Salary text as displayed |
| posted\_at | string/null | Posting date (ISO-8601) |
| description\_text | string | Plain-text description |
| description\_html | string/null | HTML description (opt-in) |
| tags | array | StepStone categories |
| apply\_url | string/null | Direct apply link |
| scraped\_at | string | Scrape timestamp |

No recruiter or contact-person data is collected — by design.

### Pricing

**$0.004 per job result + $0.05 per run start.** No hidden compute or proxy
line items — results are fetched through reliable German residential proxies
included in the price. A 100-job run costs $0.45 total.

Why this price: in measured head-to-head economics, comparable actors charge
similar per-result rates but fail roughly a quarter of their runs — runs you
still wait on. This actor's proxy configuration was chosen by measurement
(two test windows, 660 results): 100% run success. You pay slightly more per
listed unit and less per job actually delivered.

### Migrating from another StepStone actor?

`searchUrls`, `maxItems`, and `proxyConfiguration` work here the way you
already use them — existing run inputs carry over unchanged. `keywords` +
`location` + `radiusKm` are available when you'd rather not build URLs.

### Changelog

- 2026-08-09 — v0.1 chassis scaffold (pre-release)

# Actor input Schema

## `keywords` (type: `string`):

What to search for, e.g. 'data engineer'. Leave empty when using searchUrls.

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

City or region on stepstone.de, e.g. 'Berlin'.

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

Radius around the location.

## `searchUrls` (type: `array`):

Full stepstone.de search-result URLs to scrape. Takes precedence over keywords/location. Compatible with existing workflows that pass search URLs directly.

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

Stop after this many jobs. Default 20 gives a fast first run (~1 min); raise it for full crawls.

## `includeDescriptionHtml` (type: `boolean`):

Also emit the job description as HTML (larger datasets).

## `disableRescue` (type: `boolean`):

Measurement runs only: fetch exclusively through proxyConfiguration, no residential rescue. Keeps tier-ladder economics uncontaminated.

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

Apify proxy settings. German residential IPs are the reliable default for stepstone.de.

## Actor input object example

```json
{
  "keywords": "data engineer",
  "location": "Berlin",
  "radiusKm": 30,
  "searchUrls": [],
  "maxItems": 20,
  "includeDescriptionHtml": false,
  "disableRescue": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}
```

# Actor output Schema

## `jobs` (type: `string`):

Structured jobs\_v1 rows in the run's default dataset.

# 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 engineer",
    "location": "Berlin",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("apexdatalabs/stepstone-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": "data engineer",
    "location": "Berlin",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("apexdatalabs/stepstone-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": "data engineer",
  "location": "Berlin",
  "maxItems": 20
}' |
apify call apexdatalabs/stepstone-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apexdatalabs/stepstone-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/aZ7FsVG52JBcHb75l/builds/3GEdk6wFYUeuZebz0/openapi.json
