# Karriere.at Scraper — Austria's #1 Job Board (`memo23/karriere-at-scraper`) Actor

Scrape karriere.at — Austria's #1 job board. Structured EUR salary (min/max + pay period), employer website, apply URL, full descriptions, home-office flags. Search by keyword & location or paste any URL. Optional employer email enrichment. JSON/CSV for recruiting, leads & salary analytics.

- **URL**: https://apify.com/memo23/karriere-at-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (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 $1.50 / 1,000 job results

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

Learn more: https://docs.apify.com/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

## Karriere.at Scraper — Austria's #1 Job Board (with structured EUR salary)

Extract structured job data from [karriere.at](https://www.karriere.at/) — Austria's largest job board. Get the full description (text + HTML), **structured EUR salary** (min/max + pay period, not just a string), the employer's own website, the outbound apply URL, employment types, job level, and home-office flags for every posting. Paste any karriere.at search URL or use the built-in keyword/location filters; results arrive as clean JSON or CSV, one row per job.

#### How it works

![How Karriere.at Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-karriere-at.png)

#### ✨ Why use this scraper?

- **Austria's biggest job source** — karriere.at is the country's leading job platform, carrying openings from Austria's top employers across every industry and region.
- **Structured EUR salary on most rows** — Austrian postings must state pay, and this scraper turns it into numbers: `salary {min, max, currency, unit}` parsed from the site's own structured data, with the original string kept in `salaryRaw`. When a posting only states pay in prose, the description is mined as a fallback.
- **Employer website captured per job** — each posting links the company's own site (`companyWebsite` / `companyDomain`) — ready-made input for lead enrichment, not just a karriere.at profile link.
- **External apply URL captured** — when the employer routes applicants to their own careers page or ATS, the direct URL lands in `externalApplyUrl`.
- **Contacts mined from descriptions** — recruiter emails, Austrian phone numbers, and URLs are extracted into `extractedEmails` / `extractedPhones` / `extractedUrls`.
- **Optional employer-email enrichment** — flip `enrichEmails` to visit each employer's website and pull a verified contact email (`contactEmail`), billed only on hits.
- **Search exactly like the site** — keyword, location, radius, and home-office filters map 1:1 to karriere.at's own search; or paste any search URL (query-string or SEO form) with your filters already applied. Direct job URLs work too.
- **No browser, no drama** — the data comes from the site's own JSON responses, so runs are fast, cheap, and resilient to cosmetic layout changes. Full pagination is honored — no silent 15-row cap.

#### 🎯 Use cases

| Who | What for |
|---|---|
| **Recruiters & staffing agencies** | Monitor fresh postings in a region or profession; see what competitors pay |
| **Salary benchmarking & HR analytics** | Structured EUR min/max + pay period across Austrian postings, by role and region |
| **Job boards & aggregators** | Syndicate Austrian job data with stable structured fields |
| **Lead generation** | Companies that are hiring, each with its own website and mined contacts |
| **Relocation & talent platforms** | Track English-friendly and home-office roles across Austria |
| **Researchers & journalists** | Study the Austrian labour market with employment types, levels, and salary data |

#### 📥 Supported inputs

| Input | Example | What happens |
|---|---|---|
| Search URL | `https://www.karriere.at/jobs?keywords=software&locations=Wien` | Walks all result pages, scrapes each job |
| SEO search URL | `https://www.karriere.at/jobs/software-engineer/wien` | Same — both URL forms paginate fully |
| Search URL with site filters | `...jobs?keywords=sales&radius=20&homeoffice=1` | Filters pass through unchanged |
| Direct job URL | `https://www.karriere.at/jobs/10009538` | Scrapes that one job |
| Built-in filters (no URL) | `keyword: "Pflege"`, `location: "Graz"`, `remoteOnly: true` | Builds the search URL for you |

**Not supported:** company profile pages (`/f/{company}`) as start URLs, karriere.at's CV/candidate features, and any content behind a login.

#### 🔄 How it works

1. **Classify** every start URL — search page vs direct job detail.
2. **Walk** each search's result pages (~15 jobs per page) via the site's own JSON responses, streaming details in parallel while pagination continues.
3. **Fetch** each job's detail payload — keyfacts, description (text + HTML), apply action, and the embedded schema.org JobPosting in one request.
4. **Parse** structured EUR salary, employer website, employment types, job level, and locations; mine emails/phones/URLs from the description.
5. **Push** one normalized row per job to the dataset — JSON, CSV, or Excel export via the Apify platform.

#### ⚙️ Input parameters

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | — | karriere.at search URLs and/or direct job URLs. When set, the filters below are ignored |
| `keyword` | string | — | Search keyword — title, skill, or profession |
| `location` | string | — | City or region (`Wien`, `Graz`, `Salzburg`, …) |
| `radiusKm` | integer | — | Radius around the location in km |
| `remoteOnly` | boolean | `false` | Only jobs with a home-office option |
| `postedWithinHours` | integer | — | Post-scrape recency gate (24 = last day) for monitoring runs |
| `enrichEmails` | boolean | `false` | Opt-in: pull a contact email from each employer's website |
| `maxItems` | integer | `1000` | Hard cap on jobs collected |
| `maxConcurrency` | integer | `10` | Parallel detail fetches |
| `proxy` | object | Apify auto | Proxy configuration; default works fine |

#### 📊 Output overview

Each dataset row is one job. The canonical core (identity, company, location, dates, description, apply flow) is always present — fields the source doesn't provide are `null`, never missing. Karriere.at-specific extras follow the core: structured salary, employer profile (website, logo, size, main location), job level, sponsored/anonymous flags, and contacts mined from the description.

#### 📦 Output sample

Real row (trimmed) from a live run:

```json
{
  "type": "job",
  "source": "karriere.at",
  "jobId": "10009538",
  "jobUrl": "https://www.karriere.at/jobs/10009538",
  "title": "Senior Full Stack Software Engineer (all genders)",
  "companyName": "PRODYNA SE",
  "companyWebsite": "https://www.prodyna.com/",
  "companyDomain": "prodyna.com",
  "location": "Wien",
  "remote": false,
  "salary": { "currency": "EUR", "min": 4500, "max": 5000, "unit": "month", "raw": "4.500 € – 5.000 € monatlich" },
  "salaryRaw": "4.500 € – 5.000 € monatlich",
  "employmentTypes": ["Vollzeit"],
  "postedDate": "2026-08-01T00:00:00+02:00",
  "description": "<p>Bist du auf der Suche nach …</p>",
  "descriptionText": "Bist du auf der Suche nach …",
  "applyType": "external",
  "applyUrl": "https://de.prodyna.com/jobs/senior-full-stack-software-engineer-vienna",
  "externalApplyUrl": "https://de.prodyna.com/jobs/senior-full-stack-software-engineer-vienna",
  "companySlug": "prodyna",
  "companyProfileUrl": "https://www.karriere.at/f/prodyna",
  "companyLogoUrl": "https://kcdn.at/company/108321/1903002/logo-gross.companysquare.gif",
  "companyEmployees": "101 - 500",
  "companyMainLocation": "Wien",
  "region": "Wien",
  "country": "AT",
  "locations": [{ "city": "Wien", "region": "Wien", "postcode": null, "country": "AT", "street": null }],
  "jobLevel": "Berufserfahrung",
  "isSponsored": true,
  "isActive": true,
  "extractedEmails": [],
  "extractedPhones": [],
  "scrapedAt": "2026-08-04T09:43:01.239Z"
}
```

Postings that carry recruiter contacts in the text come out ready for outreach (real values from the same run):

```json
{
  "title": "Senior Software Entwickler:in C++",
  "companyName": "STEINER-HITECH GmbH",
  "salary": { "currency": "EUR", "min": 3500, "max": 5000, "unit": "month", "raw": "3.500 € – 5.000 € monatlich" },
  "applyType": "external",
  "extractedEmails": ["office@steiner-hitech.at"],
  "extractedPhones": ["01/ 876 77 88"]
}
```

With `enrichEmails: true`, employer contact discovery runs on the company's own website:

```json
{
  "companyName": "PÜSPÖK Erneuerbare Energie GmbH",
  "companyWebsite": "https://www.puespoek.at/",
  "contactEmail": "office@puespoek.at",
  "contactWebsite": "https://www.puespoek.at"
}
```

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Identity** | `jobId`, `jobUrl`, `title`, `snippet` |
| **Company** | `companyName`, `companyWebsite`, `companyDomain`, `companySlug`, `companyProfileUrl`, `companyLogoUrl`, `companyEmployees`, `companyMainLocation` |
| **Location** | `location`, `region`, `postcode`, `country`, `locations[]`, `remote` |
| **Compensation** | `salary {min, max, currency, unit}` — structured EUR from the site's own data, description-mined as fallback; `salaryRaw` — the original string |
| **Classification** | `employmentTypes[]` (`Vollzeit`, `Teilzeit`, …), `jobLevel` (`Berufserfahrung`, …) |
| **Dates** | `postedDate` (ISO-8601), `closingDate` |
| **Content** | `description` (HTML), `descriptionText` (plain text) |
| **Apply flow** | `applyType` (`internal` / `external` / `email`), `applyUrl`, `applyEmail`, `externalApplyUrl`, `directApply` |
| **Mined from description** | `extractedEmails[]`, `extractedPhones[]`, `extractedUrls[]` |
| **Signals** | `isSponsored` (boosted listing), `isAnonymousPosting` (Chiffre), `isStaffingAgency`, `isActive` |
| **Enrichment (opt-in)** | `contactEmail`, `contactWebsite`, `emailEnrichment{}` |

#### ❓ FAQ

**Is the salary really structured?**
Yes, on most rows. Austrian law requires job ads to state at least the collective-agreement minimum, and karriere.at publishes it as structured data per job — that becomes `salary {min, max, currency, unit}`. Where a posting only writes pay in prose, the description text is parsed as a fallback. `salaryRaw` always keeps the original wording.

**What do the `applyType` values mean?**
`external` — the posting routes applicants to the employer's own careers page or ATS (URL in `externalApplyUrl`). `email` — no external link, but a contact email was found in the description (in `applyEmail`). `internal` — applications go through the job's karriere.at page.

**How many jobs can I scrape?**
A focused search (keyword + city) typically returns tens to a few hundred jobs; broad searches return thousands. Every result page is walked — including on SEO-style URLs, where plain HTML scrapers silently get page 1 over and over. Use `maxItems` to control billing.

**Can I monitor for new postings?**
Yes — schedule the actor and set `postedWithinHours: 24` to keep only jobs published since yesterday's run. Pair it with a keyword/location search for a daily fresh-jobs feed.

**Are German and English postings both covered?**
Yes. Fields come out exactly as the employer wrote them — titles and descriptions may be German or English. `employmentTypes` and `jobLevel` use the site's German labels (`Vollzeit`, `Berufserfahrung`).

**Do I need a special proxy?**
No — the default Apify proxy works. If you ever see repeated 403s, switch the proxy input to RESIDENTIAL.

#### 💬 Support

- 🐛 Found a bug or need a field added? Open an issue on the actor's **Issues** tab in Apify Console.
- 💡 Custom requirements (different output shape, scheduled deliveries, other job boards)? Message me through Apify — details in **Additional services** below.

#### 🛠 Additional services

Need something beyond this actor? I build and maintain custom scraping solutions:

- **Custom scrapers** for any job board, directory, or listing site
- **Data pipelines** — scheduled runs, deduplication, delivery to your DB/S3/webhook
- **Monitoring setups** — daily fresh-postings feeds filtered to your criteria

#### 🔎 Explore more scrapers

Building a DACH hiring dataset? Pair this with my [Arbeitsagentur Scraper](https://apify.com/memo23/arbeitsagentur-scraper) — Germany's federal job board with 1M+ offers — for full German + Austrian coverage. More job-board and directory scrapers (UK boards, business directories, real-estate portals) are on my [Apify profile](https://apify.com/memo23).

#### 🤖 For AI Agents & LLM Apps

This actor is MCP-friendly: call it from Apify's MCP server or any agent framework and get back compact, predictable JSON — one object per job with stable field names, ISO dates, and numeric salary bounds. Typical agent patterns: "find Vienna backend jobs paying over €4,500/month and list the employers' websites", salary benchmarking by role, or a daily hiring-signals feed for account-based outreach. `descriptionText` gives clean plain text for LLM context windows; skip `description` (HTML) to save tokens.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by karriere.at GmbH or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available job listing pages — no authenticated endpoints, employer-only features, or content behind a karriere.at login. Users are responsible for ensuring their use complies with karriere.at's terms of use, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organisation.

***

### SEO Keywords

karriere.at scraper, scrape karriere.at, karriere.at api, austrian job board scraper, austria jobs api, scrape austrian jobs, jobs wien scraper, jobs österreich data, austrian salary data, gehalt daten österreich, job postings dataset austria, stellenangebote österreich scraper, recruiting data austria, hiring trends austria, austrian labour market data, vienna jobs scraper, graz jobs scraper, linz jobs scraper, karriere at jobs export, Apify karriere.at, stepstone austria alternative scraper, willhaben jobs alternative

# Actor input Schema

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

Full karriere.at URLs to crawl. Mix search and job-detail URLs in the same array if useful. When set, the search filters below are ignored.

## `keyword` (type: `string`):

Job title, skill, or profession — e.g. `Software`, `Pflege`, `Elektriker`. Leave empty to match all jobs.

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

City or region — e.g. `Wien`, `Graz`, `Salzburg`, `Linz`. Leave empty for all of Austria.

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

Radius around the location in kilometres. Only applied when a location is set.

## `remoteOnly` (type: `boolean`):

Only return jobs that offer a home-office option (the site's own `homeoffice` filter).

## `enrichEmails` (type: `boolean`):

If enabled, tries to find a contact email for each employer by reading the company website karriere.at links per job (or discovering it from the company name) and scanning its contact/about pages. Adds contactEmail + contactWebsite columns plus a detailed emailEnrichment object. Best-effort, billed per contact email found; only charged when an email is returned, never for misses.

## `postedWithinHours` (type: `integer`):

Filters on each job's publication date after scraping. Set 24 for the last day, 72 for the last 3 days, etc. Leave empty (or 0) to return everything regardless of age.

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

Hard cap on the number of jobs collected. karriere.at lists tens of thousands of offers across Austria; use this cap to limit billing.

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

Maximum number of job detail pages processed in parallel.

## `minConcurrency` (type: `integer`):

Minimum number of job detail pages processed in parallel.

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

Number of retries before a failed request is given up.

## `proxy` (type: `object`):

karriere.at serves its JSON payloads without heavy anti-bot — the default (automatic) Apify proxy works. Switch to RESIDENTIAL if you ever see repeated 403s.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.karriere.at/jobs?keywords=Software&locations=Wien"
  ],
  "keyword": "Software",
  "location": "Wien",
  "remoteOnly": false,
  "enrichEmails": false,
  "maxItems": 1000,
  "maxConcurrency": 10,
  "minConcurrency": 1,
  "maxRequestRetries": 5,
  "proxy": {
    "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 = {
    "startUrls": [
        "https://www.karriere.at/jobs?keywords=Software&locations=Wien"
    ],
    "keyword": "Software",
    "location": "Wien",
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/karriere-at-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 = {
    "startUrls": ["https://www.karriere.at/jobs?keywords=Software&locations=Wien"],
    "keyword": "Software",
    "location": "Wien",
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/karriere-at-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.karriere.at/jobs?keywords=Software&locations=Wien"
  ],
  "keyword": "Software",
  "location": "Wien",
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call memo23/karriere-at-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/karriere-at-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Sgv1IOVMCl8fBBtf1/builds/owRcJiH2PCy5gVriX/openapi.json
