# XING Jobs Scraper API - Germany, Austria, Switzerland (`dami_studio/xing-jobs-scraper`) Actor

Scrape XING job postings across the DACH region: title, company, full address, employment type, career level, remote/hybrid/on-site flag, exact posted date, apply link and salary when XING shows one. No login. At $0.51 per 1,000 jobs, the lowest price of any XING jobs scraper on Apify.

- **URL**: https://apify.com/dami\_studio/xing-jobs-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.51 / 1,000 job returneds

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/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

## XING Jobs Scraper API — Germany, Austria & Switzerland

Pulls job postings off **XING** (xing.com), the professional network used across the German-speaking
market. Give it a keyword, a city, or a XING search URL. You get structured rows back: title,
company, full address, employment type, career level, remote/hybrid/on-site, the exact timestamp the
posting went live, the apply link, and the salary when XING has one.

No login. No cookies to paste. No browser, so a 300-posting run finishes in about 28 seconds.

***

### What one row looks like

Real output from a live run:

```json
{
  "jobId": "156657850.09f9ef",
  "title": "Founding Software Engineer (m/w/d)",
  "companyName": "Mathe Buddy",
  "jobUrl": "https://www.xing.com/jobs/geislingen-steige-founding-software-engineer-156657850",
  "applyUrl": "https://api.relaxx.center/r/c6d0f2b4e7af4f719e3c9e635ed1c626?pid=2616477",
  "city": "Geislingen an der Steige",
  "region": "Baden-Württemberg",
  "zipCode": "73312",
  "street": "Bahnhofstraße 27",
  "country": "Deutschland",
  "countryCode": "DE",
  "employmentType": "Vollzeit",
  "careerLevel": "Mit Berufserfahrung",
  "industry": "Schulen, Kindergärten",
  "discipline": "IT und Softwareentwicklung",
  "remoteOptions": ["NON_REMOTE"],
  "workplaceType": "On-site",
  "isRemote": false,
  "isHybrid": false,
  "isOnsite": true,
  "salaryMin": 70000,
  "salaryMax": 95000,
  "salaryCurrency": "EUR",
  "salaryIsEstimate": false,
  "postedAt": "2026-07-23T16:18:26Z",
  "refreshedAt": "2026-08-07T16:18:26Z",
  "activeUntil": "2026-09-21T16:18:28Z",
  "postingLanguage": "de"
}
```

Two more from the same runs:

- `Softwareentwickler:in (m/w/d)` — agmadata GmbH — Garrel — Vollzeit — EUR 50,000–75,000 (employer
  figure) — on-site — posted 2026-07-30
- `Java Web-/ Softwareentwickler (m/w/d)` — Statistisches Landesamt Rheinland-Pfalz — Bad Ems —
  Vollzeit — EUR 45,500–54,500 (XING estimate) — hybrid — posted 2026-07-27

***

### Field coverage — measured, not promised

Across **365 unique postings** from six live runs:

| Field | Present |
|---|---|
| `title`, `companyName`, `jobUrl`, `city`, `countryCode` | 100% |
| `employmentType`, `careerLevel`, `industry`, `discipline` | 100% |
| `postedAt`, `refreshedAt`, `activeUntil` | 100% |
| `workplaceType` / `remoteOptions` | 100% |
| `region` | 95% |
| `companyLogo` | 89% |
| `companySize`, `companyUrl` | ~68% |
| `applyUrl` | 63% |
| `jobCode` | 58% |
| `zipCode` | 36% |
| `street` | 26% |

#### About salary — read this before you rely on it

XING publishes three different things, and this actor keeps them apart:

| What | `salaryIsEstimate` |
|---|---|
| A salary the **employer** published | `false` |
| XING's **own estimate** for that role | `true` |
| Nothing at all | `null` |

The split moves with the search, a lot. Across 365 German-heavy postings it was 15%
employer-published, 73% XING estimate, 12% blank. On a mixed DE/AT/CH sample of 296 it was 26% /
52% / 22%. On 164 Vienna postings it was 10% / 28% / 62% — Austrian ads carry far less salary data
than German ones. So: **roughly one posting in five carries a real employer number**, most of the
rest carry XING's guess, and in Austria most carry nothing.

A XING scraper that puts a salary on nearly every row is handing you the estimate without saying so.
Check `salaryIsEstimate` before you show a figure to anyone.

***

### How to use it

**By keyword and city**

```json
{
  "searchQueries": ["Softwareentwickler", "Data Analyst"],
  "location": "Berlin",
  "radius": 30,
  "remoteOption": "hybrid",
  "postedWithin": "week",
  "maxItems": 200
}
```

**By pasted URL** — a whole search page, or a single posting:

```json
{
  "startUrls": [
    { "url": "https://www.xing.com/jobs/search?keywords=data%20analyst&location=Berlin" },
    { "url": "https://www.xing.com/jobs/berlin-senior-software-engineer-155853218" }
  ]
}
```

**With the posting text** — set `includeDescription: true`. It arrives in the same request, so it
costs no extra time and no extra charge. You get `descriptionHtml` and `descriptionText`.
Measured coverage: **about 1 posting in 4** carries text XING holds itself. The other three quarters
are ads XING syndicates from an employer's own site, and XING does not store the body — for those,
`applyUrl` is the link to the full ad.

***

### Filters

| Input | What it does |
|---|---|
| `location` + `radius` | City or region, plus a radius in km |
| `remoteOption` | `remote`, `hybrid` or `onsite` |
| `employmentType` | Vollzeit, Teilzeit, Selbstständig, Studierende, Aushilfe, Saisonarbeit, Ehrenamt |
| `careerLevel` | Student through executive |
| `postedWithin` | Last 24 hours / week / month — this is XING's own **refresh** window, so a posting first published in June can appear in "last week" if the employer bumped it. `postedAt` always holds the true first-published timestamp |
| `salaryMin` | Minimum yearly salary in EUR |
| `resultLanguage` | `de` or `en` for XING's own labels |

***

### What this does **not** do

- **It does not go past ~1,000 postings per individual search.** That is XING's ceiling, not one we
  added — asking XING for result number 1,000 returns an error. Split the work across several
  keywords or cities; each search gets its own 1,000-row budget.
- **It does not return the full text for every posting.** See the note above: roughly a quarter.
- **It does not return recruiter or applicant contact details.** XING does not publish them.
- **It does not scrape XING member profiles or company pages.** Jobs only.
- **It does not log in**, so postings XING shows only to signed-in members are not in the output.
- **It does not invent a salary.** No figure from XING means `null`, not a guess.
- **It is not a live feed.** It reads what XING shows at the moment you run it.

***

### Cost

Pay per event, whole price on the table:

| Event | Price |
|---|---|
| Actor start | $0.001 per run |
| Job returned | **$0.51 per 1,000 postings** |

100 postings ≈ **$0.052**. 1,000 postings ≈ **$0.51**.

Nothing is charged for a run that returns no postings, for the sample row an empty run emits, or for
a request that fails. Those rows are marked `_sample` or `_diagnostic` and carry `charged: false`.

***

### FAQ

**Is there an official XING jobs API?**
XING retired its public developer API for outside developers years ago. This actor talks to the same
public, logged-out endpoint that xing.com's own job search page uses, so there is no key and no
account to manage.

**Do I need a XING account or cookies?**
No. Nothing signs in and nothing is kept between runs.

**Which countries does XING cover?**
Germany, Austria and Switzerland, with the odd posting from a neighbour like Luxembourg. The mix in
your output follows your search — a plain German keyword run came back 95% German, while adding
`"location": "Wien"` returned mostly Austrian postings. XING is not a useful source outside the DACH
region.

**Are postings in German or English?**
Mostly German — 345 of 365 in our runs. `postingLanguage` tells you per posting. XING's own labels
(`employmentType`, `careerLevel`, `industry`) follow the `resultLanguage` setting.

**How accurate is the posted date?**
It is XING's own timestamp, to the second, in ISO 8601 — not a parsed "vor 3 Tagen". `postedAt` is
when the posting first went live, `refreshedAt` is the last time it was bumped, and `activeUntil` is
when XING will take it down.

**Can I tell remote jobs from hybrid ones?**
Yes. `workplaceType` is `Remote`, `Hybrid` or `On-site`, backed by `isRemote` / `isHybrid` /
`isOnsite` booleans and the raw `remoteOptions` array from XING. Present on 100% of rows. In our
runs: 48% on-site, 39% hybrid, 13% remote.

**Does every job have a salary?**
No — see the salary section. About one in five carries an employer-published figure; most of the
rest carry XING's own estimate, flagged by `salaryIsEstimate`.

**Can I get the full job description?**
For about a quarter of postings, yes — set `includeDescription: true`. For the rest, XING only holds
a link to the employer's ad, which you get as `applyUrl`.

**How do I get more than 1,000 results?**
Run several keywords, or the same keyword against several cities. Each search has its own ceiling.

**What happens if XING blocks the run?**
Nothing is charged. The dataset gets a row marked `_diagnostic` with an `errorCode` and a plain
explanation.

**Can I schedule it?**
Yes — it is a normal Apify actor. Pair a Schedule with `postedWithin: "day"` for a daily feed of
fresh DACH postings.

**Can I use my own proxies?**
Yes, via `proxyConfiguration`. You should not need to: XING serves a reduced job board to some
countries, and the actor already routes through addresses that get the full board.

***

### Output fields

`jobId`, `globalId`, `title`, `jobUrl`, `applyUrl`, `companyName`, `companyId`, `companyUrl`,
`companyLogo`, `companySize`, `city`, `region`, `zipCode`, `street`, `country`, `countryCode`,
`locations`, `employmentType`, `careerLevel`, `industry`, `discipline`, `remoteOptions`,
`workplaceType`, `isRemote`, `isHybrid`, `isOnsite`, `salaryMin`, `salaryMax`, `salaryMedian`,
`salaryCurrency`, `salaryIsEstimate`, `salaryText`, `postedAt`, `refreshedAt`, `activeUntil`,
`isPaidListing`, `isTopJob`, `appliesOffXing`, `jobCode`, `keywords`, `postingLanguage`,
`descriptionHtml`, `descriptionText`, `searchQuery`, `searchLocation`, `page`, `position`,
`scrapedAt`.

# Actor input Schema

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

One or more job searches, exactly as you would type them into XING. German or English both work. Each keyword is walked separately, so \["Softwareentwickler", "Data Analyst"] runs two searches.

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

City, region or country in the DACH area, for example "Berlin", "Wien" or "Zürich". Leave empty to search all of XING.

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

Search radius around the location, in kilometres. Only used when a location is set.

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

Restrict to fully remote, hybrid (home office part of the week) or on-site postings.

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

Restrict to one contract type. The labels in brackets are XING's own German wording.

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

Restrict to XING's seniority band for the role.

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

Only postings XING refreshed inside this window. Every row also carries the exact posted date, so you can filter afterwards too.

## `salaryMin` (type: `integer`):

Only postings at or above this yearly salary. XING applies this to the figure it holds for the posting, which is often its own estimate rather than an employer-published number.

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

Paste XING URLs instead of building a search. Works with a single posting (https://www.xing.com/jobs/berlin-data-analyst-155853218) and with a search page (https://www.xing.com/jobs/search?keywords=data%20analyst\&location=Berlin).

## `includeDescription` (type: `boolean`):

Adds the complete posting text as HTML and as plain text. It comes from the same request, so this costs no extra time and no extra charge - it only makes the rows larger.

## `resultLanguage` (type: `string`):

Language for XING's own labels (employment type, career level, industry). The posting text itself is always in whatever language the employer wrote it.

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

Stop after this many postings. XING serves at most ~1,000 results per individual search, so use several keywords or locations to go beyond that.

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

Leave as is. The actor already routes through addresses XING answers in full; supply your own servers here only if you have a reason to.

## Actor input object example

```json
{
  "searchQueries": [
    "Softwareentwickler",
    "Data Analyst"
  ],
  "location": "Berlin",
  "radius": 30,
  "remoteOption": "",
  "employmentType": "",
  "careerLevel": "",
  "postedWithin": "",
  "salaryMin": 60000,
  "startUrls": [
    {
      "url": "https://www.xing.com/jobs/search?keywords=data%20analyst&location=Berlin"
    }
  ],
  "includeDescription": false,
  "resultLanguage": "de",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "searchQueries": [
        "Softwareentwickler"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/xing-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 = { "searchQueries": ["Softwareentwickler"] }

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/xing-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 '{
  "searchQueries": [
    "Softwareentwickler"
  ]
}' |
apify call dami_studio/xing-jobs-scraper --silent --output-dataset

```

## MCP server setup

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