# XING Jobs Scraper with Salary Estimates (DACH) (`mochiboo/xing-jobs-salary-scraper`) Actor

XING job search results for Germany, Austria and Switzerland: salary estimate (min / median / max), full description, career level, discipline, industry, remote options and company size, all at one flat price per job. No proxy, no login.

- **URL**: https://apify.com/mochiboo/xing-jobs-salary-scraper.md
- **Developed by:** [mochi](https://apify.com/mochiboo) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## XING Jobs Scraper with Salary Estimates (DACH)

**Every XING job it can see for your keywords and city, with the salary figure XING shows, the full job description and company details, at one flat price per job.** No login, no proxy, no extra charge for the job page.

**Price:** Pay per result, at the rate shown in the pricing panel of this page, plus a very small per-run start fee. You are charged only for the results delivered.

### What you get

- **Salary on most jobs.** XING's salary estimate as numbers (`salaryMin`, `salaryMedian`, `salaryMax`, `salaryCurrency`), plus a `minSalaryMedian` filter. In a 50-job test run on the Apify platform (python, Berlin), 35 jobs carried a salary range and 30 of those are XING estimates with a median. `salaryType` tells you which kind of figure you got (see "Salary fields").
- **The full job page, included in the price.** Plain-text description, career level, discipline, industry, remote options, address, language and the company's size, industry and XING page. There is no per-job-page surcharge.
- **Emails and phone numbers are replaced where recognised.** In the description text, email addresses (including spellings such as `name(at)host.com`) and phone numbers in the German, Austrian, Swiss, international and North American formats we have seen are replaced with `[email redacted]` and `[phone redacted]`. Unusual formats can slip through, and an occasional look-alike number may be replaced, so do not treat the text as free of contact details.

### What to know before you buy

- **XING decides which postings a logged-out visitor sees.** This actor never logs in. It writes every posting XING shows it and counts the ones XING holds back from it (the run log says, for example, `python: 52 visible, 48 hidden by XING (login-only), 5 pages`). In our tests the share held back varied a lot: none of 60 postings in an Apify platform run, about half (48 of 100) in a run from a machine in Singapore. Expect fewer rows than XING's own result count suggests.
- **XING's search is a "semantic" search.** Results are close matches for your keyword, not exact keyword matches.
- **One search returns at most 1,000 results** (50 pages of 20). To go deeper, split by city or by keyword. Jobs found by several keywords are returned once.
- **Employment type, career level and remote option are one value each.** XING does not accept several values in one search. With remote option "Full remote", XING ignores the location.
- **A very large run may stop early.** Before the run's time limit the actor stops starting new requests, finishes the ones in flight, writes what it has and ends normally. The `RUN_SUMMARY` record in the key-value store then says `complete: false` and `terminationReason: "time_budget"`. Start a new run for the rest.

### Input

| Field | What it does | Default |
|---|---|---|
| `keywords` | One XING search per keyword, for example `python`, `Projektmanager`, `Pflege`. | `["python"]` |
| `location` | City or region as you would type it into XING (`Berlin`, `München`, `Wien`, `Zürich`). Empty means all locations. | empty |
| `employmentType` | Full-time, part-time, self-employed / freelance, student / intern, seasonal, temporary, volunteer. | any |
| `careerLevel` | Student / intern up to senior executive. | any |
| `remoteOption` | Full remote, hybrid, on-site. | any |
| `minSalaryMedian` | Only jobs whose XING salary estimate (median) is at least this amount per year, in the job's own salary currency (EUR or CHF, see `salaryCurrency`). Jobs without a median are skipped when it is set. | off |
| `includeDetails` | Open each job page for the description and company details. | `true` |
| `maxResultsPerKeyword` | Stop a keyword after this many jobs (1 to 1000). | `100` |
| `maxResults` | Stop the run after this many jobs in total (1 to 5000). | `200` |

Example, tested on the platform: `{"keywords": ["python"], "location": "Berlin", "maxResults": 50, "includeDetails": true}` returned 50 jobs in 16 seconds.
Example with a filter: `{"keywords": ["Projektmanager"], "location": "Hamburg", "employmentType": "PART_TIME", "maxResults": 20}` returned 20 jobs, all part-time.

### Output

One row per job. Fields:

| Group | Fields |
|---|---|
| Job | `jobId`, `title`, `url`, `employmentType` (XING's English label, for example Full-time, Part-time, Student), `careerLevel`, `discipline`, `industry`, `remoteOptions` (array: `NON_REMOTE`, `PARTLY_REMOTE`, `FULL_REMOTE`), `keywords` (XING's tags for the job), `language` (of the posting), `jobCode` (the employer's reference, when given), `descriptionText` |
| Place | `city`, `allCities`, `region`, `countryCode`, `street`, `zipCode` |
| Company | `company` (display name), `companyLogoUrl`, `companyLegalName`, `companySize`, `companyIndustry`, `companyCity`, `companyXingUrl` (the company fields are `null` when the posting has no XING company page: 14 of 50 jobs in one platform run) |
| Salary | `salaryMin`, `salaryMedian`, `salaryMax`, `salaryCurrency`, `salaryType` |
| Applying | `applyType`, `applyUrl` |
| Dates and flags | `activatedAt`, `refreshedAt`, `activeUntil`, `isTopJob`, `isPaid`, `redirectsToThirdPartyUrl` |
| This search | `searchKeyword`, `searchLocation`, `searchRank` (0-based position in XING's results for that keyword, counting postings XING did not show), `scrapedAt` |

With `includeDetails` off, or when a job page cannot be read, the fields that come from the job page (`activatedAt`, `region`, `countryCode`, `street`, `zipCode`, `careerLevel`, `discipline`, `industry`, `remoteOptions`, `keywords`, `language`, `jobCode`, the five company detail fields and `descriptionText`) are `null`.

#### Salary fields

- `salaryType: "SalaryEstimate"` is XING's own estimate: `salaryMin`, `salaryMedian` and `salaryMax` in `salaryCurrency` (EUR for the German jobs we tested, CHF for most Zürich jobs; for example 59,000 / 76,000 / 86,000 EUR for a Python developer in Berlin). It is not a salary the employer published.
- `salaryType: "SalaryRange"` is a range with only `salaryMin` and `salaryMax` (`salaryMedian` is `null`). It appeared on 5 of 50 jobs in one platform run, all of them rows with `isPaid: true`. The actor does not read or convert a pay period: one student tutor job showed 500 to 1,500, so check the job before treating a range as a yearly figure.
- `salaryType: "Salary"` appeared on 2 of 50 jobs in one platform run with a currency but no min, median or max; the actor does not read an amount for these.
- No salary on XING for the job: all salary fields are `null`.

#### Applying

`applyType` is `external` when the job links to the employer's own application page (`applyUrl` holds it), `xing` when applications go through XING (`applyUrl` is `null`), and otherwise XING's own name for the form; `JobXingCustomApplication` appeared on 12 of 50 jobs in one platform run (`applyUrl` `null`).

### Notes

- Plain HTTPS to XING's public job pages. No login, no cookies, no proxy.
- If XING answers a request with an access refusal or a challenge page, the actor stops that run with the message `XING blocked the request (HTTP <status>); stopping.` and keeps the rows already written. It does not retry or work around a block.
- Network errors, HTTP 429 and 5xx are retried up to three times (2 s, 4 s, 8 s). A job page that still cannot be read becomes a row without the job-page fields.
- Speed in our platform tests: 50 jobs with job pages in 16 seconds, 20 jobs in 7 seconds. Peak memory was about 80 MB.

Search terms people use for this: XING jobs scraper, XING scraper, XING salary, Gehalt, Stellenangebote, jobs Germany, DACH jobs, Germany salary data, job market data Germany, XING API alternative.

# Actor input Schema

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

One XING job search per keyword, e.g. "python", "Projektmanager", "Pflege". Jobs found by several keywords are returned once.

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

City or region as you would type it into XING, e.g. Berlin, München, Wien, Zürich. Leave empty for all locations. Ignored by XING when Remote = Full remote.

## `employmentType` (type: `string`):

Only jobs of this employment type. XING takes one value per search; leave on Any for all types.

## `careerLevel` (type: `string`):

Only jobs for this career level. XING takes one value per search; leave on Any for all levels.

## `remoteOption` (type: `string`):

Only jobs with this remote option. XING takes one value per search. With Full remote XING ignores the location.

## `minSalaryMedian` (type: `integer`):

Only return jobs whose XING salary estimate (median) is at least this amount per year, in the job's own salary currency (EUR or CHF, see salaryCurrency). Jobs without a median are skipped when this is set.

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

Opens each job page for the description, career level, discipline, industry, remote options and company size. Included in the price.

## `maxResultsPerKeyword` (type: `integer`):

Stop a keyword after this many jobs. XING serves at most 1,000 results per search and hides about half of them from logged-out visitors.

## `maxResults` (type: `integer`):

Stop the whole run after this many jobs in total, across all keywords.

## Actor input object example

```json
{
  "keywords": [
    "python"
  ],
  "location": "Berlin",
  "employmentType": "",
  "careerLevel": "",
  "remoteOption": "",
  "includeDetails": true,
  "maxResultsPerKeyword": 100,
  "maxResults": 200
}
```

# Actor output Schema

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

One row per job: salary estimate, full description, career level, discipline, industry, remote options and company details.

## `runSummary` (type: `string`):

What the run wrote and how it ended (the RUN_SUMMARY record in the default key-value store).

# 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": [
        "python"
    ],
    "location": "Berlin"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mochiboo/xing-jobs-salary-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": ["python"],
    "location": "Berlin",
}

# Run the Actor and wait for it to finish
run = client.actor("mochiboo/xing-jobs-salary-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": [
    "python"
  ],
  "location": "Berlin"
}' |
apify call mochiboo/xing-jobs-salary-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mochiboo/xing-jobs-salary-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/dlmynJhKyaQV9jtTN/builds/ADRcjhldI3VAQ3IoF/openapi.json
