# StepStone Jobs Scraper (`nice_dev/stepstone-jobs-scraper`) Actor

Scrape StepStone job offers in Germany, Austria, Belgium and the Netherlands by keyword, location or search URL: title, company, salary, remote work, plus optional contract type, full description and recruiter contacts. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/nice_dev/stepstone-jobs-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** Jobs, Lead generation, MCP servers
- **Features:** Limited permissions
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.23 / 1,000 job ads

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

### 💼 What is StepStone Jobs Scraper?

**StepStone Jobs Scraper** extracts **job ads from [StepStone](https://www.stepstone.de)** in **Germany, Austria, Belgium and the Netherlands** (stepstone.de, stepstone.at, stepstone.be, stepstone.nl): **title, company, location, salary range, home office, benefits, publication and end dates** — and, as options, **the full job ad split into sections, the company profile with its employee rating, and the recruiter's e-mail and phone number** written in the ad. It works as a **StepStone API alternative**: run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.

Type a **keyword** (`Data Analyst`) and a **location** (`Berlin`), or paste any StepStone search, company or job ad URL, click **Start**, and download the job ads in JSON, CSV or Excel. Search several keywords, locations and countries in one run, use StepStone's own filters (date, home office, contract type, experience, German state…), or tick **Only new job ads** to follow a market day after day. No login, nothing to set up.

### 📋 What data can you extract from StepStone?

One item per job ad, 92 fields:

| Category | What you get |
| --- | --- |
| 🏷️ **Job ad** | title, StepStone link and id, its position in the results, whether it matches the search or is a related ad — `Software Entwickler - Mainframe (w/m/d)` |
| 🏢 **Company** | name, StepStone company page, logo, anonymous employer or not; with the full job ad: size, industries, address, "About us" text, benefits, open job ads, employee rating and number of reviews, photos, videos, website, year founded, sector codes, recruitment agency or not, header pictures, brand colour, parent company — `TARGOBANK, 5001-10000 employees, 4.3 from 364 reviews` |
| 💰 **Salary** | minimum, maximum, currency, period, the same range brought to a year and its middle, and whether it is StepStone's estimate (stepstone.de) — `51,000-70,000 EUR / year` |
| 📍 **Location** | place and postcode as shown, the list of places, country site; with the full job ad: street, city, full address, latitude and longitude — `Duisburg` |
| 🏠 **Work** | home office (partly or fully remote); with the full job ad: contract type, working hours, employment type, field of work, language of the ad — `Feste Anstellung` |
| 📝 **Description** | the short text of the results list, benefits, labels; with the full job ad: the whole text (plain text, Markdown or HTML) and its sections — introduction, tasks, profile, benefits, contact |
| 🕒 **Dates** | publication date, end of publication, days since published, days left, still online or not *(optional)* — what the date filters read |
| 🔗 **Apply and placement** | quick application on StepStone, "no cover letter needed", sponsored, top or highlighted ad, ad from a partner site |
| 📞 **Recruiter contacts** (option) | contact person, e-mail addresses and phone numbers the employer wrote in the job ad |
| 🔎 **Search** | the keyword, location and results page that found the ad, extraction time; how many job ads the search found, related searches and top skills of the search |

Every field, with an example, is listed in the **Output** section below.

The fields marked **details** in the Output tab come from the job ad page: they are filled when **Full job ad and company profile** is ticked (an option, off by default). Without it you get every field of the results list, which is enough for most job market studies.

### ✅ Why use StepStone Jobs Scraper?

- 🌍 **4 StepStone countries in one run**: stepstone.de, .at, .be (in French, Dutch or English) and .nl — every keyword × location is searched on each, with a cap per search.
- 🎯 **StepStone's own filters**: posted within, home office, working hours, contract type, experience, application method, language of the ad, German state — sent with the search, so fewer pages are read.
- 💰 **Salary from the results list** on stepstone.de, also given as a yearly amount (a monthly or hourly pay is converted), with a flag for StepStone's estimates.
- 🧩 **Pay only for what you use**: the full job ad (whole text in sections, company profile and rating) and the recruiter contacts are two separate options, both off by default; reading the contacts opens the job ad page of every ad (charged as the full job ad), and the contacts themselves are charged only on the ads where an e-mail or a phone number is found.
- 🔔 **Monitoring built in**: tick **Only new job ads**, schedule the Actor, and each run returns (and charges) only what it has never delivered before. A job ad found by several searches is saved — and charged — once.
- 🔌 API, scheduling, monitoring, integrations (Make, Zapier, n8n, Google Sheets…), proxy rotation and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to scrape StepStone

1. Create a free Apify account.
2. Open **StepStone Jobs Scraper**, type a **Search keyword** (e.g. `Data Analyst`) and a **Location** (e.g. `Berlin`), and pick the **Countries**.
3. Or paste your own StepStone URLs into **Start URLs**: any search results page (every filter set on the site is kept, pagination is automatic), a company's job page or single job ads.
4. Set **Max job ads** (100 by default, 0 = no limit) — and **Max job ads per search** when you run several searches — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to scrape StepStone?

This Actor uses **pay per event** pricing: a price per 1,000 job ads saved plus a small fee per run start — the amounts are on the **Pricing** tab of this page. The two options are charged on top, only on the job ads they are used for:

- **Full job ad and company profile** (`job-details`): each job ad saved with what its page gives. A job ad URL pasted in **Start URLs** is read from its page, so it is charged this option too, as is a job ad read for **Recruiter contacts** alone.
- **Recruiter contacts** (`job-contacts`): only the job ads where an e-mail address or a phone number is found; a contact name alone costs nothing more.

Filters StepStone does not offer are applied by the Actor on every job ad it reads: a job ad you keep costs its normal price, a job ad a filter drops costs a smaller filter fee (`filter-check`; `detail-filter-check` when the filter needed the job ad page) — filtering never costs more than taking everything. The **Site filters** of the form are applied by StepStone itself: the job ads they leave out cost nothing. Platform usage (compute, proxy) is included in the price.

| Price per 1,000 events | Free | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Job ad (`apify-default-dataset-item`) | $0.31 | $0.28 | $0.26 | $0.23 |
| Full job ad and company profile (`job-details`) | $0.45 | $0.39 | $0.33 | $0.27 |
| Recruiter contact found (`job-contacts`) | $0.89 | $0.88 | $0.87 | $0.86 |
| Job ad dropped by a filter (`filter-check`) | $0.049 | $0.039 | $0.029 | $0.019 |
| Job ad page read for a filter (`detail-filter-check`) | $0.20 | $0.19 | $0.18 | $0.17 |

Run start (`apify-actor-start`): $0.01 per run, on every plan.

Two examples without a paid plan:

- 1,000 job ads from the results, no option: 1,000 × $0.00031 + $0.01 = $0.32 (on Gold: $0.24).
- 1,000 job ads with **Full job ad and company profile** and **Recruiter contacts**, a contact found on about 4 ads in 10: $0.31 + $0.45 + 400 × $0.00089 + $0.01 ≈ $1.13.

### ⚙️ Input

```json
{
    "query": "Data Analyst",
    "location": "Berlin",
    "maxItems": 200
}
```

Several keywords and cities, permanent jobs paying at least 60,000 a year, published in the last 7 days, only the ones not delivered before:

```json
{
    "searchQueries": ["SAP Berater", "Data Engineer"],
    "locations": ["München", "Hamburg"],
    "contractTypes": ["permanent"],
    "minSalary": 60000,
    "postedAfter": "7 days",
    "maxItemsPerQuery": 50,
    "onlyNew": true,
    "stateKey": "sap-data-de"
}
```

IT and marketing job ads in Vienna, at employers in IT and internet, published in the last 14 days:

```json
{
    "countries": ["at"],
    "austriaState": "wien",
    "disciplines": ["it", "marketing"],
    "sectors": ["itAndInternet"],
    "postedWithin": "14",
    "maxItems": 200
}
```

Austria and Belgium (English pages of stepstone.be), with the full job ad and the recruiter contacts:

```json
{
    "query": "Developer",
    "countries": ["at", "be"],
    "belgiumLanguage": "en",
    "extractDetails": true,
    "extractContacts": true,
    "maxItems": 100
}
```

Monitor these employers: every new job ad of two companies, found by their StepStone company number, on each run:

```json
{
    "companyIds": ["2672", "58943"],
    "onlyNew": true,
    "stateKey": "my-employers",
    "maxItems": 0
}
```

Or with your own URLs (a search, a company, a job ad):

```json
{
    "startUrls": [
        { "url": "https://www.stepstone.de/jobs/data-analyst/in-berlin?radius=30&wfh=1" },
        { "url": "https://www.stepstone.de/cmp/de/targobank-2672/jobs" },
        {
            "url": "https://www.stepstone.de/stellenangebote--Software-Entwickler-Mainframe-w-m-d-Duisburg-TARGOBANK--13793839-inline.html"
        }
    ],
    "maxItems": 500
}
```

| Field | Notes |
| --- | --- |
| `companyIds` | All the job ads of these employers, by StepStone company number (the companyId column of the results, e.g. `2672`; digits only, up to 200). Each employer is read on every country of `countries`. A keyword in `query` / `searchQueries` narrows each employer's job ads (leave it empty to get all of them); the site filters apply, `location` does not. With `onlyNew` it monitors the new job ads of these employers. |
| `jobIds` | Read known job ads again by StepStone job ad number (the id column of the results, e.g. `14740497`; digits only, up to 1,000). A number belongs to one country: the first one of `countries` is used. Each job ad is read from its own page, like a job ad URL in `startUrls`. |
| `query`, `searchQueries` | Job title, skill or company, as typed in the StepStone search box (`Software Entwickler`, `Pflegefachkraft`, `SAP`); `searchQueries` adds more keywords (one search each). Empty = every job ad of the country (capped by Max job ads, default 100). Ignored when `startUrls` is set. |
| `location`, `locations` | City or postcode, as typed on StepStone (`Berlin`, `München`, `Wien`, `Amsterdam`); `locations` adds more places. Every keyword is searched in every location, on every country (max 500 searches per run). Empty = the whole country. |
| `radius` | Distance around the location in kilometres (`30` by default, up to `200`), passed to StepStone as on its site; used only with a location. It mostly changes the nearby job ads that `includeRelatedJobs` adds: in Berlin, the job ads that match the search were the same at 0 and 30 km. |
| `countries` | The StepStone sites to search: `de`, `at`, `be`, `nl` (several = each search on each site). Ignored for `startUrls` (the country is read from the URL). |
| `belgiumLanguage` | Language of stepstone.be: `fr`, `nl` or `en` — the search pages and the site's texts (contract type, working hours) follow it. Used only with Belgium. |
| `startUrls` | StepStone URLs of the 4 countries: search results pages (every filter set on the site is kept, pagination automatic: `https://www.stepstone.de/jobs/data-analyst/in-berlin?radius=30&wfh=1`), company job pages (`https://www.stepstone.de/cmp/de/targobank-2672/jobs`: all its job ads) or single job ads. Up to 1,000 URLs. The search fields and the **Site filters** are then ignored; filters, caps and monitoring still apply. |
| `maxItems`, `maxItemsPerQuery` | Stop after this many job ads for the whole run, and for each search (keyword × location × country, or start URL) (`0` = unlimited). |
| `includeRelatedJobs` | Off (default) = only the job ads that match the keyword and location. On = also the related ones StepStone adds: nearby places and similar job titles, often several times more ads ("Software-Entwickler" in Berlin: 454 matching ads, 2,857 with the related ones), each tagged in the section column. |
| `includeSearchStats` | Off (default). On = for each search, the Actor also saves the record SEARCH_STATS in the run's key-value store: the number of job ads StepStone finds and how they split by city, region, sector, discipline, contract type, experience, work from home, working time, application method, language, skill, category and salary step. Figures StepStone shows for the search, no extra charge. See "Search statistics" in the tips below. |
| `postedWithin` | The last `1`, `3`, `7`, `14` or `30` days. 1, 3, 7 and 14 are StepStone's date filters; 30 is applied by the Actor on the publication date, like `postedAfter` (if you also set a later `postedAfter`, it wins). For any other date, use `postedAfter`. |
| `sortBy` | `relevance` (default) or `date` (newest first). With `date`, StepStone sends neither the salary nor the end of publication in its results list: they then come from the job ad page (`extractDetails` or `extractContacts`). |
| `workFromHome` | `partial` (partly from home) or `full` (fully remote). StepStone's result list only says whether home office is possible: the job ads found with `full` come out as `full`, all the others as `partial`. |
| `workType` | `fullTime` or `partTime`. |
| `contractTypes` | Keep job ads of ANY of these types: `permanent`, `fixedTerm`, `internship`, `workingStudent`, `apprenticeship`, `trainee`, `freelance`, `temporaryAgency`, `salesAgent`, `franchise`, `thesis`, `legalClerkship`, `doctorate` (the last two on stepstone.de only). A site that has none of the chosen types is not searched (the log says so). |
| `experience` | Keep job ads of ANY of these levels: `noExperience`, `experienced`, `managerial`. |
| `applicationMethod` | `quick` (quick application on StepStone) or `external` (on the company website). |
| `jobLanguage` | Only job ads written in this language: `de`, `en`, `fr`, `nl` (e.g. English job ads in Germany). |
| `bundesland` | Germany only: job ads in one federal state (`bayern`, `nordrhein-westfalen`, `berlin`…), with or without a location. With several countries it applies to the stepstone.de searches only (`countries` must include de). |
| `austriaState` | Austria only: job ads in one state (`wien`, `steiermark`, `tirol`…), with or without a location. With several countries it applies to the stepstone.at searches only (`countries` must include at). |
| `belgiumProvince` | Belgium only: job ads in one province (`brussels`, `east-flanders`, `liege`…), with or without a location. With several countries it applies to the stepstone.be searches only (`countries` must include be). |
| `netherlandsProvince` | The Netherlands only: job ads in one province (`noord-holland`, `utrecht`…), with or without a location. With several countries it applies to the stepstone.nl searches only (`countries` must include nl). |
| `disciplines` | Keep job ads of ANY of these fields of work: `it`, `marketing`, `sales`, `engineering`, `health`, `finance`, `logistics`, `education`, `advertising`… (40 values, listed in the input form). `advertising` exists on stepstone.de only; a discipline a site does not have is left out for that site (the log says so), and a site with none of the chosen ones is not searched. |
| `sectors` | Keep job ads of employers in ANY of these sectors: `itAndInternet`, `staffingAndRecruitment`, `banking`, `healthAndSocialServices`… (38 values, listed in the input form). stepstone.be and stepstone.nl have a shorter list: only the sectors they share with stepstone.de are sent there (the log names the others). |
| `skillIds`, `cityIds`, `categoryIds` | Codes of StepStone's own filters, for what the lists above do not cover: the numbers in the address of a search you filtered on the site by skill, city or job category (`673826`; digits only, up to 50 each, any of them). Codes belong to one country. |
| `extractDetails` | **Extra-charge option, off by default.** Opens each job ad: whole text and its sections, contract type, working hours, street address and GPS, end of publication, badges, and the company profile (size, industries, address, "About us", benefits, rating and number of reviews, website). |
| `descriptionFormat` | Form of the description and of each of its sections: `text`, `markdown` or `html`. |
| `descriptionMaxLength` | Cut the description, and each of its sections, after this many characters (`2000`; `0` = the whole text). |
| `extractContacts` | **Extra-charge option, off by default.** The contact person, e-mail addresses and phone numbers the employer wrote in the job ad (an e-mail on about 6 job ads in 30, a phone number on about 5 in 30). Opens the job ad page of every job ad you get, so each one is charged the **Full job ad** option too; the contacts option is added only on the job ads where an e-mail or a phone number is found. |
| `postedAfter`, `postedBefore` | Publication date range: `2026-09-01` (the whole day is included, German time), or a period before now (`7 days`, `2 weeks`, `1 month`, `24 hours`). A job ad without a publication date is dropped as soon as a bound is set. |
| `includeKeywords`, `excludeKeywords` | Keep only the job ads whose TITLE contains at least one of these words (`Senior`, `Werkstudent`), or drop those whose title contains one (case and accents ignored). For `excludeKeywords` the words are WHOLE words: `art` drops "Art deco", not "Smart watch"; several words in one entry (`hand made`) must appear together. Chinese, Japanese, Korean, Thai, Lao, Khmer and Burmese words are found anywhere in the title (no spaces there). |
| `excludeCompanies` | Drop the job ads of these companies: part of the company name (`Zeitarbeit`), case and accents ignored. A job ad without a company name is kept (see `excludeAnonymous`). |
| `includeCompanies` | Keep only the job ads of these companies: part of the company name (`SAP`, `Bosch`), case and accents ignored. A job ad without a company name is dropped. |
| `minSalary` | Keep only the job ads whose salary range reaches at least this yearly amount (`60,000`; monthly × 12, hourly × 2,080), StepStone's estimates included. A job ad without a salary figure is dropped; `0` = off. |
| `maxSalary` | Drop the job ads whose salary range starts above this yearly amount (same yearly conversion as the minimum). A job ad without a salary figure is kept (turn on "only with a salary" to drop it); `0` = off. |
| `onlyWithSalary`, `excludeSponsored`, `excludeAnonymous` | Drop the job ads that show no salary figure; the ones StepStone marks as sponsored; the ones published without the employer's name. |
| `excludePartnerJobs` | Drop the job ads StepStone marks as partner, cross-posted or backfilled (copies of ads published on other job boards). |
| `excludeRecruitmentAgencies` | Drop the job ads of employers that StepStone files as a recruitment agency. Read on the job ad page, so it needs the full job ad or the recruiter contacts option; an employer with no profile is kept. |
| `descriptionIncludeKeywords`, `descriptionExcludeKeywords` | Keep only the job ads whose whole text contains at least one of these words (`Führerschein`), or drop those whose text contains one. Whole words, case and accents ignored. Read on the job ad page, so it needs the full job ad or the recruiter contacts option; the whole text is searched even when the description length option cuts the text you get. |
| `onlyWithContacts` | Keep only the job ads where an e-mail address or a phone number was found (a recruiter name alone is not enough). Needs the recruiter contacts option: the run is refused without it. |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the job ads never delivered under this memory key (`berlin-data-jobs`); `resetState` forgets the memory. |
| Advanced | `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

A real item of stepstone.de with both options, shortened (long texts cut, some fields left out; the phone number is masked here):

```json
{
    "id": "13793839",
    "harmonisedId": "a162a148-d460-483e-959c-f64dbbaed0a7",
    "url": "https://www.stepstone.de/stellenangebote--Software-Entwickler-Mainframe-w-m-d-Duisburg-TARGOBANK--13793839-inline.html",
    "title": "Software Entwickler - Mainframe (w/m/d)",
    "companyName": "TARGOBANK",
    "companyId": "2672",
    "companyUrl": "https://www.stepstone.de/cmp/de/targobank-2672/jobs",
    "isAnonymous": false,
    "location": "Duisburg",
    "country": "DE",
    "site": "stepstone.de",
    "publishedAt": "2026-10-20T22:04:23.647Z",
    "validThrough": "2026-11-19T23:04:23.647Z",
    "salaryMin": 51000,
    "salaryMax": 70000,
    "salaryCurrency": "EUR",
    "salaryPeriod": "year",
    "salaryIsEstimate": true,
    "salaryText": "51,000-70,000 EUR / year",
    "salaryYearlyMin": 51000,
    "salaryYearlyMax": 70000,
    "workFromHome": "partial",
    "snippet": "TARGOBANK ist ein Finanzdienstleister, der innovative digitale Lösungen für Bankdienstleistungen entwickelt.…",
    "benefits": [
        "Sie bekommen einen unbefristeten Arbeitsvertrag, ein ansprechendes Gehalt und 30 Tage Urlaub (mit zusätzlichen Urlaubsmodellen erweiterbar).",
        "Sie können in Voll- oder Teilzeit arbeiten, Homeoffice ist bis zu 50% möglich."
    ],
    "skills": [],
    "labels": ["Anschreiben nicht erforderlich"],
    "isSponsored": false,
    "section": "main",
    "rank": 2,
    "description": "BANK.ECHT.ANDERS. Das ist unser Anspruch als Arbeitgeberin. Wir wollen zur besten Bank für alle unsere…",
    "descriptionSections": [
        {
            "name": "description",
            "title": "Ihre Aufgaben",
            "text": "• Analysieren, erweitern und entwickeln neuer Software-Systeme und Applikationen in einem…"
        },
        {
            "name": "profile",
            "title": "Ihr Profil",
            "text": "• Abgeschlossenes Studium der praktischen / angewandten Informatik oder eine Ausbildung…"
        }
    ],
    "contractType": "Feste Anstellung",
    "workType": "Homeoffice möglich, Teilzeit, Vollzeit",
    "employmentType": ["FULL_TIME"],
    "industry": "IT, IT-Softwareentwicklung",
    "jobLanguage": "de",
    "directApply": false,
    "noCoverLetter": true,
    "isOnline": true,
    "city": "Duisburg",
    "address": "Duisburg, Deutschland",
    "latitude": 51.42982,
    "longitude": 6.748468,
    "companyEmployees": "5001-10000",
    "companyIndustries": ["Banken und Finanzdienstleister"],
    "companyAddress": "Kasernenstr. 10, Düsseldorf",
    "companyJobsCount": 70,
    "companyRating": 4.28838,
    "companyReviewCount": 364,
    "companyWebsite": null,
    "contactName": null,
    "emails": [],
    "phones": ["+49 211 XXXXXXXX"],
    "searchQuery": "Software Entwickler",
    "searchLocation": null,
    "searchUrl": "https://www.stepstone.de/jobs/software-entwickler?page=1",
    "page": 1,
    "scrapedAt": "2026-10-21T12:00:00.000Z",
    "locations": ["Duisburg"],
    "searchTotalResults": 25507,
    "searchMatchingResults": 4135,
    "relatedSearches": ["Hardwareentwickler", "Systems Engineer"],
    "searchTopSkills": ["Deutsch", "Kommunikation"],
    "positionOnPage": 2,
    "labelTypes": ["NO_COVER_LETTER"],
    "postedDaysAgo": 0,
    "expiresInDays": 29,
    "salaryYearlyMid": 60500,
    "titleClean": "Software Entwickler - Mainframe",
    "companyFounded": null,
    "companySectorIds": [],
    "isRecruitmentAgency": null,
    "heroImageUrl": null,
    "companyHeroImageUrl": null,
    "brandColor": null,
    "isFreeListing": false,
    "isParentCompany": false
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. A field StepStone does not give for a job ad is `null` (or an empty list), never missing.

#### All 92 fields

| Fields | What you get |
| --- | --- |
| `id`, `harmonisedId`, `url`, `title`, `titleClean` | **Job ad**: `13793839` (the number at the end of the link), StepStone's group-wide id, the link without tracking parameters, the title, and the title without the gender mention such as `(m/w/d)` or `(h/f)` |
| `companyName`, `companyId`, `companyUrl`, `companyLogoUrl`, `isAnonymous` | **Company**: `TARGOBANK` (`null` for an anonymous ad), its StepStone id, its page of job ads, logo, `true` when the employer hides its name |
| `location`, `locations`, `postalCode`, `country`, `site` | **Location**: `Duisburg` as shown, the same cut at its commas (`München, Hamburg` gives two places), the postcode, `DE`, `AT`, `BE` or `NL`, `stepstone.de` |
| `publishedAt`, `validThrough`, `postedDaysAgo`, `expiresInDays` | **Dates**: publication (what the date filters read) and end of publication, ISO 8601 UTC; whole days since publication and whole days left until the end of publication (negative once over), counted at the extraction time |
| `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod`, `salaryIsEstimate`, `salaryText` | **Salary**: `51000`, `70000`, `EUR`, `year` (or `month`, `week`, `day`, `hour`), `true` when it is StepStone's estimate, `51,000-70,000 EUR / year` or the employer's own words |
| `salaryYearlyMin`, `salaryYearlyMax`, `salaryYearlyMid` | the range brought to a year (monthly × 12, weekly × 52, daily × 220, hourly × 2,080) — what `minSalary` reads — and its middle (the one bound known when only one is) |
| `workFromHome`, `snippet`, `benefits`, `skills`, `labels`, `labelTypes` | `partial`, `full` (the job ads of a `full` search) or `null`; the short text of the results list (about 500 characters); the benefits listed; the skills when StepStone lists them; the labels of the result card and their codes (`QUICK_APPLY`, `NO_COVER_LETTER`, the same on the four sites) |
| `isSponsored`, `isTopJob`, `isHighlighted`, `isPartnershipJob`, `isCrossPosted`, `isBackfilled`, `partnerSite` | **Apply and placement**: paid placements (sponsored, top, highlighted), a job ad from a partner site or also published on another StepStone group site, a job ad StepStone added from a partner feed, the name of the partner site |
| `section`, `rank`, `page`, `positionOnPage` | `main` = matches the search, `regional` / `semantic` = a related job ad (nearby place, similar title); its position in the results, the results page it was on and its position on that page |
| `description`, `descriptionSections` | **Description** (details): the whole text in the chosen format, and its sections `introduction`, `description` (tasks), `profile`, `benefits`, `additionalInformation` (contact), each with its title |
| `contractType`, `workType`, `employmentType`, `industry`, `jobLanguage` | **Work** (details): `Feste Anstellung`, `Homeoffice möglich, Teilzeit, Vollzeit` as written on the site (often blank on stepstone.be, where many employers leave them out), `FULL_TIME`…, the field of work, the language of the ad |
| `directApply`, `noCoverLetter`, `badges`, `isOnline` | quick application on StepStone, "no cover letter needed", the badges of the job ad page, still online or not |
| `street`, `city`, `region`, `address`, `latitude`, `longitude` | **Location** (details): the address of the job and its GPS coordinates (`region` is often empty on StepStone) |
| `companyEmployees`, `companyIndustries`, `companyAddress`, `companyAbout`, `companyBenefits`, `companyJobsCount` | **Company** (details): `5001-10000`, industries, address, the "About us" text, benefits, open job ads on StepStone |
| `companyRating`, `companyReviewCount`, `companyImages`, `companyVideos`, `companyWebsite` | employee rating out of 5 and number of reviews, photos, videos, website (given by StepStone on part of the Austrian and Belgian job ads, almost never in Germany) |
| `companyFounded`, `companySectorIds`, `isRecruitmentAgency`, `isParentCompany` | **Company** (details): the year the company was created (when StepStone's profile gives it), the codes of its sectors (the same in the four countries), `true` when one of them is staffing and recruitment services (`null` when no sector is given), `true` for a parent company |
| `heroImageUrl`, `companyHeroImageUrl`, `brandColor`, `isFreeListing` | **Look** (details): the header picture of the job ad and of the company profile, the employer's brand colour (`#001c52`), `true` for a free listing |
| `searchTotalResults`, `searchMatchingResults`, `relatedSearches`, `searchTopSkills` | **Search summary** (same on every row of a search; `null` or empty for a job ad URL): job ads the search found in all, of which match the keyword itself, searches StepStone suggests next to it, the skills it lists most |
| `contactName`, `emails`, `phones` | **Recruiter contacts** (option): the person, e-mails and phones written in the job ad; `null` / empty lists otherwise |
| `searchQuery`, `searchLocation`, `searchUrl`, `scrapedAt` | **Search**: the keyword and location of the form that found the job ad (`null` when left empty, and for start URLs), the results page, the extraction time |

### 💡 Tips

#### How to get more results

Set `maxItems` to `0` and use a broad keyword, or none at all with a country: StepStone has no page limit, every page of a search is read. Tick `includeRelatedJobs` to add the job ads of nearby places and similar titles StepStone shows under the main results. For one employer, paste its StepStone company page into `startUrls`.

#### How to reduce costs

The price is per job ad, so the levers are `maxItems`, `maxItemsPerQuery`, the **Site filters** (applied by StepStone: the job ads left out are not read and cost nothing), the other filters (a filtered-out job ad costs only the filter fee) and `onlyNew` for recurring runs (you never pay twice for the same job ad). Leave the two options off when the results list is enough: title, company, place, salary, home office, benefits and dates are all in it.

#### Several searches in one run

Fill `searchQueries`, `locations` and / or `countries`: the Actor runs one search per country × keyword × location (3 keywords × 4 cities × 2 countries = 24 searches, up to 500 per run). The single `query` and `location` fields still work and are added to the lists. A job ad found by several searches is saved — and charged — once. Set `maxItemsPerQuery` to give every search its own cap: without it the first searches can use up the whole `maxItems` budget. You can also paste several search URLs into `startUrls`: each one is a search of its own, with the same cap.

#### Monitoring: only the new job ads

Tick **Only new job ads** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the job ads already delivered: they are not saved, not charged, and their page is not even opened. The memory lives in a named key-value store of your account (`stepstone-jobs-scraper-seen`, up to 150,000 job ads per key) and is only updated with job ads that really reached the dataset: a job ad is never marked as delivered before it is in your dataset. Give each schedule its own `stateKey` (two schedules sharing a key would hide each other's job ads), and tick `resetState` once to start over. With `sortBy` set to `date` (newest first), a search stops as soon as it meets a long run of job ads you already have, so a daily run reads only the first pages. With `includeRelatedJobs` ticked, StepStone lists the related job ads in blocks after the matching ones, each block starting again from its newest: the search then stops nowhere and reads every page, so a run costs more time (never more money) and no new job ad is missed. In StepStone's own order (the default) a new job ad can sit behind known ones, so every page of the search is read: for a broad search, choose `date`, or set `maxItems` / `maxItemsPerQuery` to save time. With a cap (`maxItems` or `maxItemsPerQuery`), a job ad that no earlier run delivered but that was put online before the last run saved (less one day) is not new: the cap of that run left it out, so it is skipped, not delivered and not charged — a second run right after the first gives only the job ads put online since. Without a cap, or after a run stopped early (its timeout, an abort, its maximum cost), the next run returns every job ad not delivered yet.

#### Filter by publication date

`postedWithin` keeps the job ads StepStone published in the last 24 hours, 3, 7, 14 or 30 days: 1, 3, 7 and 14 are applied by StepStone, 30 by the Actor on `publishedAt`, exactly like `postedAfter` with `30 days` (the later of the two bounds applies). `postedAfter` and `postedBefore` take a date (`2026-09-01`, the whole day is included, German time) or a period before now (`7 days`, `2 weeks`, `1 month`; via the API also `24 hours` or a full ISO date-time). They read `publishedAt`, which every result card gives: no job ad page is needed. With `sortBy` set to `date`, StepStone dates the results up to about 20 hours earlier than the job ad page itself, or days later when the employer re-publishes the job ad (15 days measured). When the job ad pages are read (`extractDetails` or `extractContacts`), `publishedAt` is the date of the page, whatever the order chosen, and `postedAfter` keeps the job ads of the period by that date (the Actor opens the pages of the job ads dated up to a day before the bound to check them; those the page shows older are dropped and charged the filter fee). Without the pages, `publishedAt` is the date of the results list: with `sortBy: date` it can be up to about 20 hours earlier than the real publication, so a `postedAfter` counted in hours can leave out a job ad published just after the bound, or days later for a re-published job ad, which then passes a bound it should not; leave a day of margin or read the pages. A job ad without a publication date is dropped as soon as a date bound is set. Filtered-out job ads are not saved and do not count in `maxItems` (each job ad dropped costs the filter fee, see Pricing); the run summary tells how many were filtered. With `sortBy` set to `date`, searches stop at the first page that is entirely too old (not with `includeRelatedJobs`: the related job ads come in blocks after the matching ones, every page is read and the job ads too old are left out).

#### Salary filters

StepStone gives a salary range only on stepstone.de, in the results list, for most job ads (23 of 25 on a test page), most often as its own estimate (`salaryIsEstimate`). `minSalary` and `onlyWithSalary` read that range. On stepstone.de in the default order `minSalary` is also passed to StepStone as its own salary filter (steps of 10,000, rounded down), so fewer job ads are read; the exact amount is checked on every job ad. With `sortBy` set to `date`, the results list carries no salary: both filters then judge the salary of the job ad page and need it read, with `extractDetails` or `extractContacts` (when neither is on they are ignored, and the log says so). On stepstone.at, .be and .nl no salary was found on any job ad: there these two filters drop everything.

#### Search statistics

Tick `includeSearchStats` to get, besides the job ads, the figures StepStone itself shows for each search: how many job ads it finds and how they split by city, region, sector, discipline, contract type, experience, work from home, working time, application method, language, skill, category and salary step. They are saved as the record SEARCH_STATS of the run's key-value store (open the Output tab, or the Storage tab of the run), one entry per search, free of charge. The counts are StepStone's own, for the whole search, not only for the job ads you collected. Every value carries the `id` that the site uses, so you can copy it into `skillIds`, `cityIds` or `categoryIds` for a narrower next run. A facet StepStone does not give for a search (the salary steps on stepstone.at, .be and .nl) is simply missing from its entry.

```json
{
    "generatedAt": "2026-11-12T14:40:12.511Z",
    "searches": [
        {
            "searchUrl": "https://www.stepstone.de/jobs/vertrieb/in-hamburg?radius=30",
            "searchQuery": "vertrieb",
            "searchLocation": "Hamburg",
            "country": "DE",
            "site": "stepstone.de",
            "totalResults": 1910,
            "matchingResults": 1290,
            "nearbyResults": 617,
            "similarResults": 3,
            "relatedSearches": ["Einkauf", "Vertriebsmitarbeiter"],
            "facets": {
                "workType": [
                    { "id": "80001", "label": "Vollzeit", "count": 1489 },
                    { "id": "80002", "label": "Teilzeit", "count": 362 }
                ],
                "disciplines": [
                    {
                        "id": "79649004",
                        "label": "Vertrieb und Verkauf",
                        "count": 1907,
                        "children": [{ "id": "251254", "label": "Verkaufsberatung", "count": 1010 }]
                    }
                ],
                "skills": [{ "id": "225052", "label": "Vertrieb", "count": 1173 }]
            }
        }
    ]
}
```

The labels are in the language of the site. `totalResults` is every job ad of the search; `matchingResults` the ones that match the keyword and place, `nearbyResults` and `similarResults` the related ones that `includeRelatedJobs` adds. A search pasted from a job ad URL, or `jobIds`, has no entry. A run that is stopped or moved keeps the searches it had counted.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per StepStone job ad. Actor id: `nice_dev/stepstone-jobs-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/stepstone-jobs-scraper`.

Smallest input, for a cheap first call:

```json
{
    "query": "Data Analyst",
    "location": "Berlin",
    "maxItems": 10
}
```

Key output fields: `title`, `companyName`, `location`, `salaryText`, `workFromHome`, `publishedAt`, `url` and `description` (with `extractDetails`).

Cost: the price per 1,000 job ads plus the run-start fee, and the options only when ticked, see the pricing section above. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape StepStone?

The Actor only reads the job ads StepStone shows publicly to any anonymous visitor. It logs in to nothing. Results can contain personal data (a recruiter's name, e-mail or phone number written in a job ad, with the **Recruiter contacts** option), which is protected by GDPR: do not store or use it without a legitimate reason. You are responsible for using the data in compliance with StepStone's Terms of Use and applicable law. This Actor is not affiliated with StepStone.

#### Does it need a login or a proxy?

No login. The proxy is included in the price: leave the default setting (the residential proxy is not available). A request StepStone turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds).

#### Is the data safe to open in Excel or to show on a web page?

Titles and descriptions are the employers' own words, copied as they are. A text can begin with `-`, `+`, `=` or `@` (a phone number, a title such as `-20% today`): Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. With `descriptionFormat` set to `html`, `description` and the section texts are the employer's own HTML, which the Actor does not sanitize: on a web page, escape every field like any text written by a stranger.

#### Known limitations

- Salary: only stepstone.de gives one, mostly StepStone's estimate (`salaryIsEstimate`); with `sortBy` set to `date`, the salary and the end of publication (`validThrough`) come only from the job ad page (`extractDetails` or `extractContacts`).
- stepstone.nl has few job ads: some searches in a Dutch city return none, whatever the radius.
- `radius` is passed to StepStone and only works with a location; StepStone uses it mostly for the related job ads of `includeRelatedJobs`, so the main results may not change with it.
- `companyWebsite` is given by StepStone on part of the Austrian and Belgian job ads, almost never in Germany; `skills` is empty on almost every job ad.
- Recruiter contacts are what the employer wrote in the job ad: most ads have none (an e-mail on about 6 in 30, a phone number on about 5 in 30).
- Site filters that are not in the form can still be used by pasting a filtered StepStone search URL into `startUrls`.
- `onlyNew` remembers job ad ids, not their content: a job ad whose text changed is not returned again.
- `onlyNew` with a cap: a job ad put online more than a day before the last run saved (a day, because the date of a result can be up to 20 hours earlier than the real one), that no run delivered, is taken for one the cap left out and is not returned later — the older job ads of a search ADDED to a `stateKey` already used, a job ad whose page failed after every retry (listed in `FAILED_REQUESTS`), one a filter you relaxed now lets through. Use a new `stateKey`, or `resetState`, to get them all.
- Two runs sharing the same `stateKey` at the same time may both return the same new job ad.

**A run that reaches its timeout** stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with `onlyNew`, remembered, and the run ends *Succeeded* with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).

**A run the platform stops without warning** (out of memory)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the job ads already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the job ads it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the job ads of its last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the job ads saved, filtered out and no longer on StepStone (taken offline while the run was reading them), and the requests that failed after every retry. Those requests and the removed job ads are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause.

If StepStone changes its pages, you are told instead of paying for blank rows. A results page that counts job ads but gives none the Actor can read is an error (listed in `FAILED_REQUESTS`), never a quiet "No job ads found". If the first 20 job ads read all lack their title, publication date, location, text snippet, position in the results (rank and page), employer name or id, or — with the job ad page — description, text sections, contract type and working time (not on stepstone.be, where many employers leave them blank), language, online status, employment type, industry, city or the company's address or number of ads, the run saves nothing more, stops and fails, and its last message names the missing field and the country: at most those first job ads are charged. A results page whose job ads all lack their link or their section is an error too. Each country of a run is checked on its own: the 20 job ads are those of that country. A job ad that `postedAfter` / `postedBefore` drops because it has no date at all counts among those 20. A run of fewer job ads (a scheduled `onlyNew` run that finds a few new ones, a small **Max job ads**) is checked at its end, from 5 job ads: its job ads are already saved, and the run fails with the missing field instead of ending green.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which requests failed and why.

# Actor input Schema

## `startUrls` (type: `array`):

StepStone URLs from any of the 4 countries: search-result pages (every filter set on the site is kept, pagination is automatic, e.g. `https://www.stepstone.de/jobs/data-analyst/in-berlin?radius=30&wfh=1`), company pages (`https://www.stepstone.de/cmp/de/targobank-2672/jobs` = all its job ads) or single job ads (`https://www.stepstone.de/stellenangebote--Data-Analyst--14659293-inline.html`). When this list is not empty, the search fields below (keywords, locations, countries, site filters) are ignored; filters, caps and monitoring still apply. Max 1 000 URLs.

## `companyIds` (type: `array`):

All job ads of these employers, by StepStone company number (the companyId column of the results, e.g. `2672`). Digits only, max 200. Each employer is read on every selected country; a Search keyword narrows each employer's job ads (clear the keyword to get all of them). The site filters below apply; the Location does not. Handy with **New job ads only** to monitor employers.

## `jobIds` (type: `array`):

Read known job ads again by StepStone job ad number (the id column of the results, e.g. `14740497`). Digits only, max 1 000. A number belongs to one country: the first selected country is used. Each job ad is read from its own page, as a job ad URL in Start URLs.

## `query` (type: `string`):

Job title, skill or company, exactly as typed in the StepStone search box (e.g. `Software Entwickler`, `Pflegefachkraft`, `SAP`). Empty = every job ad of the country (capped by Max job ads, default 100).

## `searchQueries` (type: `array`):

Several keywords in one run: one search per keyword (times each location and each country). Added to **Search keyword**; a job ad found by several searches is saved once.

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

City or postcode, as typed on StepStone (e.g. `Berlin`, `München`, `Wien`, `Amsterdam`). Empty = every job ad of the country (capped by Max job ads, default 100). Not used with Employer numbers or Job ad numbers.

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

Several locations in one run: every keyword is searched in every location (3 keywords × 4 locations = 12 searches per country, max 500 searches). Added to **Location**.

## `radius` (type: `integer`):

Distance around the location, in kilometres, passed to StepStone as on its site. Used only with a location. It mostly changes the nearby job ads added by Include related job ads: the job ads that match the search can stay the same.

## `countries` (type: `array`):

StepStone sites to search. Each keyword × location (or employer) is searched on each selected site. Ignored for Start URLs (the country is read from the URL); Job ad numbers use the first one.

## `belgiumLanguage` (type: `string`):

stepstone.be runs in 3 languages: the search pages, URLs and site texts (contract type, work type) follow this language. Used only when Belgium is selected.

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

Maximum number of job ads to save for the whole run (after deduplication and filters). 0 = no limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (keyword × location × country, or start URL), so that the first search cannot use up the whole **Max job ads** budget. 0 = no per-search cap.

## `includeRelatedJobs` (type: `boolean`):

StepStone pads its results with job ads that do not match the search exactly: nearby places (`regional`) and similar job titles (`semantic`), often several times more ads (Software-Entwickler in Berlin: 454 matching ads, 2 857 with the related ones). Off = only the ads that match the keyword and location (`main`). On = the related ones too, each tagged in the `section` field. Ads that StepStone recommends outside the search are never returned.

## `includeSearchStats` (type: `boolean`):

For each search, saves in the key-value store (record `SEARCH_STATS`) the total number of job ads and how they split by city, region, sector, discipline, contract type, experience, work from home, working time, application method, language, skill, category and salary step. These are the figures StepStone shows for the search, at no extra charge. The `id` of a skill, city or category can be used in **Skill IDs**, **City IDs** and **Category IDs**.

## `postedWithin` (type: `string`):

Only job ads published in the last 24 hours, 3, 7, 14 or 30 days. 1, 3, 7 and 14 are StepStone filters; 30 days is applied by the Actor on the publication date, like **Posted after** (a later Posted after wins). For any other date, use **Posted after** below.

## `sortBy` (type: `string`):

Order of the results, as on StepStone. Newest first: StepStone then sends neither the salary nor the end of publication in the results list — they come only from the job ad page (Full job ad or Recruiter contacts), and the salary filters need it.

## `workFromHome` (type: `string`):

Only job ads that allow working from home partly, or fully remote ones.

## `workType` (type: `string`):

Full-time or part-time job ads only.

## `contractTypes` (type: `array`):

Keep only these contract types (several = any of them). Not every type exists on every site: a type a site does not have is left out for that site (the run log says so), and a site with none of them is not searched.

## `experience` (type: `array`):

Keep only these experience levels (several = any of them).

## `applicationMethod` (type: `string`):

Quick application on StepStone, or application on the employer's website.

## `jobLanguage` (type: `string`):

Only job ads written in this language (StepStone detects it), e.g. English job ads in Germany.

## `bundesland` (type: `string`):

Germany only: job ads in this federal state. Can be combined with a location or used without one. With several countries it applies to the stepstone.de searches only; Countries must include stepstone.de.

## `disciplines` (type: `array`):

Keep only job ads of these fields of work (several = any of them), e.g. IT and Marketing. `advertising` exists on stepstone.de only: on a site that lacks a discipline it is left out (the run log says so), and a site with none of them is not searched.

## `sectors` (type: `array`):

Keep only job ads of employers in these sectors (several = any of them). stepstone.de and stepstone.at have the full list; stepstone.be and stepstone.nl have a shorter one with other cuts, so only the sectors they share with stepstone.de are sent there (a sector without an equivalent is left out, the run log says so).

## `austriaState` (type: `string`):

Austria only: job ads in this state. Can be combined with a location or used without one. With several countries it applies to the stepstone.at searches only; Countries must include stepstone.at.

## `belgiumProvince` (type: `string`):

Belgium only: job ads in this province, Brussels included. Can be combined with a location or used without one. With several countries it applies to the stepstone.be searches only; Countries must include stepstone.be.

## `netherlandsProvince` (type: `string`):

The Netherlands only: job ads in this province. Can be combined with a location or used without one. With several countries it applies to the stepstone.nl searches only; Countries must include stepstone.nl.

## `skillIds` (type: `array`):

Keep only job ads that ask for these skills (several = any of them). The codes are the numbers in the address of a search filtered by skill on StepStone (`673826`): set the filter on the site, copy the number. Digits only. Codes belong to one country.

## `cityIds` (type: `array`):

Keep only job ads in these cities (several = any of them). The codes are the numbers in the address of a search filtered by city on StepStone (`419239`): set the filter on the site, copy the number. Digits only. Codes belong to one country.

## `categoryIds` (type: `array`):

Keep only job ads of these job categories (several = any of them). The codes are the numbers in the address of a search filtered by job category on StepStone: set the filter on the site, copy the number. Digits only. Codes belong to one country.

## `extractDetails` (type: `boolean`):

Open each job ad: full description (tasks, profile, benefits, contact sections), contract type, working hours, street address and GPS, end of publication, cover-letter badge, and the company profile (size, industries, address, About us, benefits, rating and number of reviews). Off = the result-list fields only (title, company, location, salary range, home office, snippet, benefits).

## `descriptionFormat` (type: `string`):

Format of the `description` field and of each `descriptionSections` text (with **Full job ad**).

## `descriptionMaxLength` (type: `integer`):

Cut `description` and each text of `descriptionSections` after this many characters (smaller exports, LLM prompts). 0 = the whole text.

## `extractContacts` (type: `boolean`):

Read the recruiter's name, e-mail addresses and phone numbers written by the employer in the job ad (found in about 1 job ad in 5). Opens the job ad page of every job ad you get: each one is charged **Full job ad**, and the contacts option is added only where an e-mail address or a phone number is found.

## `postedAfter` (type: `string`):

Only job ads published on or after this date (the StepStone publication date, `publishedAt`): `2026-09-01`, or a period before now such as `7 days`, `2 weeks`, `1 month` (API: `24 hours` and full ISO date-times work too). Job ads without a publication date are dropped. With Sort by Newest first, StepStone dates the results up to about 20 hours before the job ad page, or days after it for a job ad its employer re-publishes: the date of a row is the page's when it is read (Full job ad or Recruiter contacts), else the list's.

## `postedBefore` (type: `string`):

Only job ads published on or before this date (the whole day is included), or older than a period such as `30 days`.

## `includeKeywords` (type: `array`):

Keep only the job ads whose title contains at least one of these words (case and accents ignored), e.g. `Senior`, `Werkstudent`.

## `excludeKeywords` (type: `array`):

Drop the job ads whose title contains one of these WHOLE words (case and accents ignored): `art` drops "Art deco" but keeps "Smart watch". Several words in one entry (`hand made`) must appear together, in that order. Chinese, Japanese, Korean, Thai, Lao, Khmer and Burmese words are found anywhere in the title (no spaces there).

## `excludeCompanies` (type: `array`):

Drop the job ads of these companies (part of the company name, case and accents ignored), e.g. staffing agencies.

## `includeCompanies` (type: `array`):

Keep only the job ads of these companies (part of the company name, case and accents ignored), e.g. `SAP`, `Bosch`. Job ads that show no company name are dropped.

## `minSalary` (type: `integer`):

Keep only the job ads whose salary range reaches at least this yearly amount, in the ad's currency (monthly × 12, hourly × 2 080; StepStone's estimates count, see `salaryIsEstimate`). Only stepstone.de gives salaries: on the other sites every job ad is dropped. With Sort by Newest first, the salary is read on the job ad page and needs Full job ad or Recruiter contacts (ignored when neither is on). Job ads without a salary are dropped. 0 = off.

## `maxSalary` (type: `integer`):

Drop the job ads whose salary range starts above this yearly amount, in the ad's currency (monthly × 12, hourly × 2 080; StepStone's estimates count, see `salaryIsEstimate`). Job ads without a salary are KEPT (add Only job ads with a salary to drop them). Only stepstone.de gives salaries. With Sort by Newest first, the salary is read on the job ad page and needs Full job ad or Recruiter contacts (ignored when neither is on). 0 = off.

## `onlyWithSalary` (type: `boolean`):

Drop the job ads that show no salary figure (a range or an amount). Only stepstone.de gives salaries. With Sort by Newest first, it is judged on the job ad page and needs Full job ad or Recruiter contacts (ignored when neither is on).

## `excludeSponsored` (type: `boolean`):

Drop the job ads that StepStone marks as sponsored. Top and highlighted job ads are kept.

## `excludeAnonymous` (type: `boolean`):

Drop the job ads whose employer hides its name or gives none (often staffing agencies).

## `excludePartnerJobs` (type: `boolean`):

Drop the job ads that StepStone marks as partner, cross-posted or backfilled (copies of ads published on other job boards).

## `excludeRecruitmentAgencies` (type: `boolean`):

Drop the job ads of employers that StepStone files as a recruitment agency (read on the job ad page: needs Full job ad or Recruiter contacts, ignored when neither is on). Job ads whose employer profile says nothing are kept.

## `descriptionIncludeKeywords` (type: `array`):

Keep only the job ads whose whole text contains at least one of these WHOLE words (case and accents ignored), e.g. `Führerschein`. Read on the job ad page: needs Full job ad or Recruiter contacts (ignored when neither is on). The whole text is searched, even when Max description length cuts the text you get. Job ads without a text are dropped.

## `descriptionExcludeKeywords` (type: `array`):

Drop the job ads whose whole text contains one of these WHOLE words (case and accents ignored), e.g. `Schichtdienst`. Read on the job ad page: needs Full job ad or Recruiter contacts (ignored when neither is on). The whole text is searched, even when Max description length cuts the text you get.

## `onlyWithContacts` (type: `boolean`):

Keep only the job ads where an e-mail address or a phone number was found (a recruiter name alone is not enough). Needs Recruiter contacts: the run is refused without it.

## `onlyNew` (type: `boolean`):

Skip the job ads that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and their page is not even opened. First run = everything is new.

## `stateKey` (type: `string`):

Name of the memory used by **Only new job ads**. Give each schedule / task its own key (e.g. `berlin-data-jobs`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every job ad again. Untick it afterwards.

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

Apify Proxy or your own proxies. Keep the default: it is included in the price. The residential Apify proxy is not available in this Actor.

## `maxConcurrency` (type: `integer`):

Maximum number of requests processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Most requests to StepStone in any 60 seconds, all of them counted: result pages and job ad pages. A budget, not an even pace: up to this many can leave at once when the minute starts (spread them with the minimum delay below). Lower it if the site answers HTTP 429 / 403 in the log.

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests, in milliseconds. Unlike the per-minute rate, this spreads the requests evenly instead of letting them go out in a burst. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed. Behind a proxy, a request the site turns away is also retried on a new proxy session up to 10 times without using up these retries.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "startUrls": [],
  "companyIds": [],
  "jobIds": [],
  "query": "Data Analyst",
  "searchQueries": [],
  "location": "Berlin",
  "locations": [],
  "radius": 30,
  "countries": [
    "de"
  ],
  "belgiumLanguage": "fr",
  "maxItems": 50,
  "maxItemsPerQuery": 0,
  "includeRelatedJobs": false,
  "includeSearchStats": false,
  "postedWithin": "",
  "sortBy": "relevance",
  "workFromHome": "",
  "workType": "",
  "contractTypes": [],
  "experience": [],
  "applicationMethod": "",
  "jobLanguage": "",
  "bundesland": "",
  "disciplines": [],
  "sectors": [],
  "austriaState": "",
  "belgiumProvince": "",
  "netherlandsProvince": "",
  "skillIds": [],
  "cityIds": [],
  "categoryIds": [],
  "extractDetails": false,
  "descriptionFormat": "text",
  "descriptionMaxLength": 0,
  "extractContacts": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "excludeCompanies": [],
  "includeCompanies": [],
  "minSalary": 0,
  "maxSalary": 0,
  "onlyWithSalary": false,
  "excludeSponsored": false,
  "excludeAnonymous": false,
  "excludePartnerJobs": false,
  "excludeRecruitmentAgencies": false,
  "descriptionIncludeKeywords": [],
  "descriptionExcludeKeywords": [],
  "onlyWithContacts": false,
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8,
  "maxRequestsPerMinute": 120,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

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

No description

## `searchStats` (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 = {
    "query": "Data Analyst",
    "location": "Berlin",
    "countries": [
        "de"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/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 = {
    "query": "Data Analyst",
    "location": "Berlin",
    "countries": ["de"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/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 '{
  "query": "Data Analyst",
  "location": "Berlin",
  "countries": [
    "de"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/stepstone-jobs-scraper --silent --output-dataset

```

## MCP server setup

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