# karriere.at Jobs Scraper (Austria: karriere.at, jobs.at) (`swissalpinedata/austria-jobs-scraper`) Actor

Scrapes job postings for a keyword and location from karriere.at and jobs.at into one common schema.

- **URL**: https://apify.com/swissalpinedata/austria-jobs-scraper.md
- **Developed by:** [WebAlpine Studio](https://apify.com/swissalpinedata) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 job listings

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

## karriere.at Jobs Scraper (Austria: karriere.at, jobs.at)

Search Austria's two largest job boards, karriere.at and jobs.at, with one keyword and one location, and get every matching posting back as a clean, deduplicated JSON record.

### Why this actor

- Public data only: the JSON search endpoints and public job pages of karriere.at and jobs.at, the two largest Austrian job boards.
- No login, no cookies, no browser and no proxy. Plain HTTP with polite delays.
- Structured, deduplicated fields with one schema for both boards: title, company, location, Bundesland, employment type, salary text, date, description and URL.

### What it does

You give it a search term such as "Softwareentwickler" or "Pflege" and an optional town or region such as "Wien" or "Graz". The actor runs that search on karriere.at and on jobs.at, walks through all result pages, removes postings that appear on both boards (jobs.at republishes many karriere.at ads) and pushes one flat record per job to the dataset.

For each job you get the title, company, location, Austrian Bundesland (state), employment type, salary text, publish date and a short teaser. With the optional `fetchDetails` switch the actor also opens each job's own page and adds the full plain-text description, the exact publish timestamp and the state as declared by the employer.

The actor reads the same JSON responses the two sites use for their own "load more" buttons and the schema.org JobPosting data on detail pages, so the fields are taken straight from structured data rather than guessed from layout.

### Why use it

Comparing openings across Austrian job boards normally means repeating the same search on every site and copying results by hand. This actor runs the search once and returns one table that you can filter, export to Excel or CSV, feed into a spreadsheet, a CRM, a salary study or a job alert of your own. Typical uses:

- Recruiters and staffing agencies tracking which companies are hiring for a role in a region.
- Job seekers who want a daily list of new postings without visiting each site.
- Analysts studying salary ranges, employment types or demand for a skill across the Bundesländer.
- Companies watching competitor hiring.

### Input

| Field | Type | Description |
|---|---|---|
| `query` | string, required | Job title or keyword, for example "Softwareentwickler", "Pflege", "Buchhaltung". |
| `location` | string | Town, district or region, for example "Wien", "Graz", "Tirol". Leave empty to search all of Austria. |
| `sources` | array | Which boards to scrape: `karriere_at`, `jobs_at`. Both by default. |
| `fetchDetails` | boolean | Also open every job page for the full description, exact publish timestamp and exact state. Slower, roughly one extra request per job with a polite delay. Off by default. |
| `maxItems` | integer | Maximum number of records in total, default 100, up to 5000. The limit is split evenly across the selected boards; if one board has fewer results the other fills the rest. |

Example input:

```json
{
  "query": "Pflege",
  "location": "Graz",
  "sources": ["karriere_at", "jobs_at"],
  "fetchDetails": false,
  "maxItems": 100
}
```

### Output example

One record from a real run without `fetchDetails`:

```json
{
  "source": "karriere_at",
  "job_id": "10028680",
  "url": "https://www.karriere.at/jobs/10028680",
  "apply_url": null,
  "title": "Senior Database Developer (m/w/d) SQL Server · T-SQL · Performance Engineering",
  "company": "Sportsbook Software GmbH",
  "location": "Wien 22. Bezirk (Donaustadt)",
  "state": "Wien",
  "employment_type": "Vollzeit",
  "workload": null,
  "salary": "ab 68.000 € jährlich",
  "published_at": "2026-09-13",
  "home_office": true,
  "snippet": null,
  "description": null,
  "scraped_at": "2026-09-22T20:37:20.359941+00:00"
}
```

A jobs.at record with `fetchDetails` enabled:

```json
{
  "source": "jobs_at",
  "job_id": "7902017",
  "url": "https://www.jobs.at/i/7902017",
  "apply_url": "https://www.karriere.at/jobs/7875091?utm_source=jobsat&utm_medium=basic_high&utm_campaign=metajobbörse",
  "title": "Java SW-Entwickler:in (m/w/d)",
  "company": "TECHSEARCH",
  "location": "Wien",
  "state": "Wien",
  "employment_type": "Vollzeit",
  "workload": "38.5 Std./Woche",
  "salary": "4.500,00 bis 5.500,00 EUR monatlich",
  "published_at": "2026-09-11T13:01:28+00:00",
  "home_office": true,
  "snippet": "Sie entwickeln eine zentrale Serviceplattform mit Java und Spring Boot, arbeiten im Backend, und achten auf sauberen, wartbaren Code sowie die Integration von Backend-Services.",
  "description": "Java SW-Entwickler:in\nWir suchen für unseren Kunden eine:n Java SW-Entwickler:in mit mehrjähriger Erfahrung und sehr guten Kenntnissen in Java und Spring Boot, um eine zentrale Serviceplattform weiterzuentwickeln und ...",
  "scraped_at": "2026-09-22T20:40:24.174197+00:00"
}
```

Fields:

| Field | Meaning |
|---|---|
| `source` | `karriere_at` or `jobs_at`. |
| `job_id` | The id the board uses for the posting. |
| `url` | The posting on the board itself. |
| `apply_url` | External employer or application page, when the board links to one (jobs.at only). |
| `title`, `company`, `location` | As shown on the board. Several locations are comma separated. |
| `state` | Austrian Bundesland. Taken from the job page when `fetchDetails` is on, otherwise looked up from the town name or postal code; `null` when the town is not known. |
| `employment_type` | Board wording such as "Vollzeit", "Teilzeit", "Vollzeit, Teilzeit". |
| `workload` | Weekly hours when jobs.at provides them. |
| `salary` | Salary as text, exactly as the board shows it, or built from jobs.at's structured salary. |
| `published_at` | ISO 8601 date. For karriere.at listings this is a day-precision date derived from the board's own "Heute", "vor 3 Tagen" or "14.9.2026" label; with `fetchDetails` it is the exact timestamp from the job page. |
| `home_office` | Whether the board flags the job as home office. |
| `snippet` | Short teaser text from the listing. |
| `description` | Full plain-text description, only with `fetchDetails`. |
| `scraped_at` | When the record was collected. |

Any field the board does not provide is `null`. Values are never invented.

### Pricing

This Actor uses pay per result. You pay **USD 0.003 per job record**, which is **USD 3.00 per 1,000 results**. There is no charge per run or per request, and a run that returns no results produces no result charges.

| Results | Price |
| --- | --- |
| 100 | USD 0.30 |
| 1,000 | USD 3.00 |
| 10,000 | USD 30.00 |

A daily alert with 50 new jobs costs USD 0.15 per run, about USD 4.50 per month. Set `maxItems` to cap the cost of a run.

### Limitations

- AMS eJob-Room (jobs.ams.at), the public employment service board, is not included. Its search API sits behind an OAuth2 login and rejects every anonymous request with HTTP 401, so there is no honest way to scrape it without a user account. It is therefore not offered as a source.
- Postings listed on jobs.at that link to karriere.at are counted once, under `karriere_at`. jobs.at usually contributes fewer unique records than its own result count suggests.
- Without `fetchDetails`, `state` comes from a lookup of Austrian town names and postal codes and stays `null` for small or ambiguous places.
- The actor searches with the boards' own relevance ranking and a default 20 km radius around the location, the same as a visitor on the site.
- No proxy is used. Runs of several thousand records with `fetchDetails` on are slow by design (polite delay of up to one second per request).

### Legal

The actor only reads pages and JSON responses that are publicly accessible without logging in. Job postings can contain personal data such as contact names. How you store and use the data, and whether your use complies with the source sites' terms and with GDPR, is your responsibility.

### FAQ

**Why is a job missing that I can see on jobs.at?**
Most likely it is a karriere.at ad republished on jobs.at. It is in your dataset once, with `source` set to `karriere_at`.

**Can I search without a location?**
Yes, leave `location` empty to search all of Austria.

**Why is `published_at` a plain date for karriere.at?**
The listing only shows a label such as "vor 3 Tagen". The actor converts it to a date and does not pretend to know the time. Enable `fetchDetails` for the exact timestamp.

**Does it need a proxy?**
No. Both boards served every request during testing without one.

**Can you add AMS?**
Only if AMS opens its API or the actor is given an account, see Limitations.

### Changelog

**0.1.x** (2026-09-25): README with concrete pricing and a short summary of the data sources. No change to the output.

**0.1** Initial release with karriere.at and jobs.at, JSON pagination, cross-board deduplication, optional detail fetch.

# Actor input Schema

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

Job title or keyword to search for, e.g. "Softwareentwickler".

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

City or region to search in, e.g. "Wien". Leave empty to search all of Austria.

## `sources` (type: `array`):

Which Austrian job boards to include. AMS eJob-Room is not available because its search API requires an authenticated session that could not be reached anonymously.

## `fetchDetails` (type: `boolean`):

When enabled, each job's own page is fetched to get the full plain-text description, an exact posting date and the Bundesland. This is slower and uses a polite delay between requests.

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

Maximum number of job records to return in total. The limit is split evenly across the selected boards; if one board has fewer results, the other fills the rest.

## Actor input object example

```json
{
  "query": "Softwareentwickler",
  "location": "Wien",
  "sources": [
    "karriere_at",
    "jobs_at"
  ],
  "fetchDetails": false,
  "maxItems": 100
}
```

# Actor output Schema

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

All records returned by this run, as JSON.

# 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": "Softwareentwickler",
    "location": "Wien"
};

// Run the Actor and wait for it to finish
const run = await client.actor("swissalpinedata/austria-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": "Softwareentwickler",
    "location": "Wien",
}

# Run the Actor and wait for it to finish
run = client.actor("swissalpinedata/austria-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": "Softwareentwickler",
  "location": "Wien"
}' |
apify call swissalpinedata/austria-jobs-scraper --silent --output-dataset

```

## MCP server setup

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