# Stepstone Jobs Scraper (`automation-lab/stepstone-jobs-contact-enrichment`) Actor

Search StepStone Germany and export jobs with employer websites, application links, and public contact fields.

- **URL**: https://apify.com/automation-lab/stepstone-jobs-contact-enrichment.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

Search **stepstone jobs** by keyword or StepStone.de URL and export structured vacancies with employer websites, application links, and public contact details shown in each posting.

The Actor is designed for recurring recruiting research, vacancy monitoring, German hiring-market analysis, and employer lead enrichment. It uses StepStone's public result pages and structured job metadata; no login is required.

### What can the Stepstone Jobs Scraper do?

- Build StepStone Germany searches from one or more keywords.
- Narrow generated searches by city or region and radius.
- Accept existing StepStone search-results URLs.
- Accept individual StepStone job-detail URLs.
- Follow result pagination until `maxItems` is reached.
- Deduplicate jobs by the stable StepStone listing ID.
- Extract company, location, date, salary, remote-work, skills, and description fields.
- Enrich records with employer career websites and application links found in the posting.
- Extract public recruiter emails, phone numbers, and named contacts when StepStone displays them.
- Return clean JSON rows in the default Apify dataset for download or automation.

### Who is this StepStone jobs extractor for?

#### Recruiters and staffing teams

Build a current vacancy list for a role and region, identify hiring employers, and keep the public contact fields supplied in the job advertisement next to each opportunity.

#### B2B sales and lead-research teams

Use active hiring as a company signal. Export the employer, role, location, career website, application URL, and available public contact information into a CRM or research sheet.

#### Labor-market analysts

Collect reproducible samples of job titles, employers, locations, posting dates, salary fields, and remote-work signals for analysis.

#### Job-data and automation teams

Schedule the same search URLs or keywords, then send dataset rows to a database, webhook, spreadsheet, or monitoring pipeline.

### Why use this Actor?

The output joins the search result with public details from the matching job advertisement. This avoids a second manual enrichment step for fields such as the full description, employer careers URL, application URL, and advertised contact person.

The Actor also preserves `sourceSearchUrl` and the stable listing `jobId`, making it practical to compare scheduled runs and identify records that appeared, disappeared, or changed.

It does not invent employer contacts. Contact arrays remain empty when a posting does not display that information.

### What StepStone job data is extracted?

| Field | Meaning |
| --- | --- |
| `jobId` | Stable StepStone listing identifier |
| `title` | Advertised job title |
| `url` | StepStone job-detail URL |
| `companyName` | Hiring employer |
| `companyId` | StepStone employer identifier |
| `companyPageUrl` | Employer page on StepStone |
| `companyLogoUrl` | Employer logo when available |
| `location` | Advertised location |
| `postCode` | Postal code when available |
| `datePosted` | Source publication date |
| `salaryText` | Salary text supplied by StepStone |
| `salaryMin`, `salaryMax` | Normalized salary bounds when available |
| `salaryCurrency` | Salary currency |
| `workFromHome` | Remote or hybrid signal |
| `descriptionText` | Plain-text job description or preview |
| `skills` | Skills supplied in structured metadata |
| `labels` | StepStone listing labels |
| `employerWebsite` | Public employer or careers website in the posting |
| `applicationUrl` | Public external application URL |
| `contactEmails` | Public email addresses displayed in the posting |
| `contactPhones` | Public phone numbers displayed in the posting |
| `contactNames` | Named contacts displayed in the posting |
| `sourceSearchUrl` | Input/search page that produced the row |
| `scrapedAt` | UTC extraction timestamp |

### How to scrape StepStone jobs

1. Open the Actor input page.
2. Add one or more job keywords, StepStone URLs, or both.
3. Optionally set a location and radius for keyword searches.
4. Keep **Enrich job and employer contacts** enabled for detail fields.
5. Set `maxItems` to bound the run.
6. Click **Start**.
7. Open the **Dataset** tab to preview, download, or integrate the results.

A useful first run is:

```json
{
  "keywords": ["software engineer"],
  "location": "Berlin",
  "radiusKm": 30,
  "maxItems": 25,
  "includeDetails": true
}
```

### Input parameters

#### `keywords`

An array of role or skill searches. The Actor creates StepStone.de URLs for each value. Empty keyword values are rejected.

#### `startUrls`

StepStone.de search-results or individual job-detail URLs. Other domains and non-HTTPS URLs are rejected. Search URLs are useful when you already configured filters on StepStone.

#### `location` and `radiusKm`

These apply to generated keyword searches. The radius can be from 0 to 100 km.

#### `maxItems`

Maximum unique records across all keywords and URLs. Valid range: 1 to 5,000. The Actor stops scheduling work once this limit is reached.

#### `includeDetails`

When `true`, each result detail page is fetched for description, application, employer website, and public contact fields. Set it to `false` for a lighter search-results-only export.

#### `maxRequestRetries`

Bounded retries for temporary network, rate-limit, server, or challenge responses. Valid range: 0 to 5.

### Output example

A representative enriched row looks like this:

```json
{
  "jobId": "14361030",
  "title": "Senior Software Entwickler / Architekt (m/w/d)",
  "companyName": "BIOTRONIK Corporate Services SE",
  "location": "Berlin",
  "datePosted": "2026-08-04T17:16:14+02:00",
  "employerWebsite": "https://www.biotronik.com/karriere",
  "applicationUrl": "https://www.biotronik.com/karriere",
  "contactEmails": [],
  "contactPhones": ["+49 30689053513"],
  "contactNames": ["Juan Sánchez"],
  "sourceSearchUrl": "https://www.stepstone.de/jobs/software-entwickler/in-berlin"
}
```

Fields are nullable because employers do not supply every field on every job. Empty contact arrays mean the advertisement did not expose that contact type.

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

This Actor uses pay-per-event pricing: one small `start` charge per run plus an `item` charge for each job saved to the dataset. Failed, duplicate, or rejected rows are not charged as items.

At the current FREE tier, the prices are:

- `$0.005` per run start;
- `$0.00184` per saved job.

Examples at that tier:

| Saved jobs | Estimated Actor charge |
| ---: | ---: |
| 1 | $0.00684 |
| 25 | $0.05100 |
| 100 | $0.18900 |
| 1,000 | $1.84500 |

Higher Apify plan tiers receive lower per-item prices. Platform resource usage can vary by input; the Console estimate is the final source for a run.

### Monitoring new or changed jobs

Run the same input on a schedule and compare records by `jobId`.

A typical workflow is:

1. Schedule the Actor daily.
2. Store `jobId`, `datePosted`, and selected fields in your database.
3. Treat previously unseen IDs as new vacancies.
4. Compare tracked fields for changed vacancies.
5. Mark IDs absent from later complete runs according to your own retention policy.

The Actor emits current source records; it does not maintain historical state or send alerts by itself.

### Lead enrichment workflow

For each job, use `companyName`, `employerWebsite`, `applicationUrl`, and the contact arrays as source-attributed research fields. Keep the StepStone job URL with the record so a reviewer can inspect context and freshness.

Do not infer that a job contact has consented to unrelated outreach. Apply your organization's legal basis, suppression lists, and contact policies before using public data.

### Export StepStone jobs to a spreadsheet or database

From the Dataset tab, download JSON, CSV, Excel, XML, or RSS. For automation, use the dataset API URL in the run output.

Common destinations include:

- Google Sheets through Make or Zapier;
- Airtable or a CRM staging table;
- PostgreSQL, BigQuery, Snowflake, or a data lake;
- Slack or email notifications for newly observed IDs;
- internal recruiter dashboards.

### Run with the Apify API

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~stepstone-jobs-contact-enrichment/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords":["data engineer"],"location":"Hamburg","maxItems":50,"includeDetails":true}'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/stepstone-jobs-contact-enrichment').call({
    keywords: ['data engineer'],
    location: 'Hamburg',
    maxItems: 50,
    includeDetails: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token="YOUR_APIFY_TOKEN")
run = client.actor("automation-lab/stepstone-jobs-contact-enrichment").call(
    run_input={
        "keywords": ["data engineer"],
        "location": "Hamburg",
        "maxItems": 50,
        "includeDetails": True,
    }
)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI agents

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/stepstone-jobs-contact-enrichment"
```

#### Claude Desktop MCP setup

Add this server to Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/stepstone-jobs-contact-enrichment"
    }
  }
}
```

#### Cursor MCP setup

Use the same `mcpServers.apify.url` value in Cursor's MCP settings.

#### VS Code MCP setup

Add the same HTTP MCP server URL to your VS Code MCP configuration.

Example prompts:

- "Find up to 30 current StepStone data engineer jobs in Hamburg and return employer websites."
- "Extract this StepStone results URL and group jobs by hiring company."
- "Compare today's StepStone job IDs with yesterday's dataset and list new employers."

### Reliability, retries, and limits

StepStone can vary response timing and anti-bot behavior by route. The Actor verifies recognizable structured data instead of treating a challenge page as an empty result. It starts with direct HTTP and bounded exponential backoff, then escalates exhausted requests to datacenter sessions, German residential sessions, and finally resource-limited browser rendering/network requests.

Cookies and proxy identity stay together in bounded session pools. Healthy sessions are reused; challenged sessions are retired and rotated rather than retried indefinitely. Detail enrichment can still be unavailable for an individual result even when the search row succeeds. In that case, the Actor emits the useful search record and leaves unavailable detail/contact fields empty rather than inventing data.

Use conservative limits and schedules. Very broad keywords can return thousands of results and naturally take longer when detail enrichment is enabled.

### Troubleshooting

#### The run says that input is missing

Provide at least one non-empty `keywords` value or one valid StepStone.de URL in `startUrls`.

#### I received jobs but no contact email

Many advertisements do not publish an email address. Check `contactPhones`, `contactNames`, `employerWebsite`, and `applicationUrl`; empty arrays are expected when the source does not display that field.

#### A detail record has only search fields

The detail route may have timed out or returned a temporary challenge. Increase `maxRequestRetries` modestly and try again later. Avoid repeated aggressive retries.

#### My URL was rejected

Only public HTTPS URLs on `stepstone.de` are supported. Other StepStone country domains are outside this Actor's current scope.

### Responsible and legal use

Scrape only public data and follow StepStone's terms, robots guidance, applicable database rights, privacy law, and your organization's policies. Minimize collection, respect individuals' rights, and keep source URLs and timestamps for auditability.

Publicly displayed contact information is not blanket consent for marketing. Users are responsible for establishing a lawful purpose, honoring opt-outs, and securing exported data.

This Actor is an independent automation tool and is not affiliated with or endorsed by StepStone.

### Frequently asked questions

#### Does it require a StepStone login?

No. It is designed for public StepStone.de job pages.

#### Does it cover StepStone Austria, Belgium, or the Netherlands?

No. The current input contract intentionally validates `stepstone.de` only.

#### Can it monitor jobs continuously?

Use an Apify schedule and compare stable job IDs between runs. The Actor itself returns the current source state and does not retain history.

#### Does it guarantee employer contact details?

No. It extracts public contact fields only when they appear in a posting. Results without those fields remain useful job records with empty contact arrays.

#### Can I disable detail requests?

Yes. Set `includeDetails` to `false` for faster search-list exports without full descriptions or contact enrichment.

#### Are duplicate jobs charged twice?

No. Jobs are deduplicated by source ID within each run, and item charges apply only when a unique row is saved.

### Related automation-lab Actors

Use the Apify Store profile for [automation-lab](https://apify.com/automation-lab) to find related job-board and employer-research Actors. This Actor is intentionally StepStone.de-specific so its fields and route validation remain clear.

# Actor input Schema

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

Job searches to run on stepstone.de, for example software engineer or pflegefachkraft.

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

StepStone.de results pages or individual job detail URLs. You can combine these with keywords.

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

Optional German city or region applied to keyword searches.

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

Radius around the location for generated keyword searches.

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

Stop after saving this many unique job records across all inputs.

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

Fetch each job detail page for description, employer website, application URL, public email, phone, and named contact fields.

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

Retries for temporary network, rate-limit, server, or challenge responses.

## Actor input object example

```json
{
  "keywords": [
    "software engineer"
  ],
  "startUrls": [
    {
      "url": "https://www.stepstone.de/jobs/software-entwickler/in-berlin"
    }
  ],
  "location": "",
  "radiusKm": 30,
  "maxItems": 10,
  "includeDetails": true,
  "maxRequestRetries": 2
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing all scraped jobs.

# 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": [
        "software engineer"
    ],
    "startUrls": [
        {
            "url": "https://www.stepstone.de/jobs/software-entwickler/in-berlin"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/stepstone-jobs-contact-enrichment").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": ["software engineer"],
    "startUrls": [{ "url": "https://www.stepstone.de/jobs/software-entwickler/in-berlin" }],
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/stepstone-jobs-contact-enrichment").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": [
    "software engineer"
  ],
  "startUrls": [
    {
      "url": "https://www.stepstone.de/jobs/software-entwickler/in-berlin"
    }
  ]
}' |
apify call automation-lab/stepstone-jobs-contact-enrichment --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/stepstone-jobs-contact-enrichment"
        }
    }
}

```

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/AqouzD66qXf9dSlRe/builds/3AC9edf9EYbZ3CdwZ/openapi.json
