# Jobs.cz Scraper (`crawlerbros/jobs-cz-scraper`) Actor

Scrape Jobs.cz - one of the largest Czech job boards. Keyword search, browse by region/city, browse by category/profession, with salary, date-posted, employment-type, education, language and home-office filters.

- **URL**: https://apify.com/crawlerbros/jobs-cz-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Jobs.cz Scraper

Scrape **Jobs.cz** — one of the largest Czech job boards, used by thousands of employers across the Czech Republic. Search by keyword, browse all open positions in a region/city, browse by profession/category, or browse jobs.cz's separate part-time/temp-gig board ("brigády") — with salary (Kč), date-posted, employment-type, education, language, home-office and other filters. HTTP-only via the public `jobs.cz` search pages. No auth, no proxy required.

### What this actor does

- **Four modes:** `search` (keyword), `byLocation` (region/city browse), `byCategory` (profession browse), `brigady` (part-time / temp / student gigs — a separate board on jobs.cz with its own listings)
- **Rich filters:** minimum salary (Kč), posted-within window, employment type (incl. internships/trainee programs), contract type, education level, required languages, home-office arrangement, suitable-for group, employer type (direct/agency/NGO), minimum hourly rate (mode=brigady), search radius in km around a location (every mode, incl. brigady)
- **Combinable axes:** narrow a keyword search or a category browse to a specific city; narrow a city browse to a specific profession; narrow a brigády browse to a keyword and/or city
- **Bonus fields:** salary range parsed into numeric min/max, posted date normalized to ISO where derivable, employer Atmoskop rating link, home-office/response-time tags
- **Empty fields are omitted**

### Output per job

- `jobId` — jobs.cz internal ad ID
- `title` — job title
- `company` — employer name
- `location` — city/district as shown on the listing
- `salaryText` — raw salary label as displayed (e.g. `"70 000 – 85 000 Kč"`)
- `salaryMinCzk`, `salaryMaxCzk` — parsed numeric salary bounds in Czech crowns (equal when only one figure is shown)
- `salaryPeriod` — `monthly` or `hourly`
- `postedDateText` — raw status label as shown (e.g. `"13. srpna"`, `"Přidáno dnes"`, `"Končí za 3 dny"`)
- `postedDate` — ISO `YYYY-MM-DD` posting date, only included when confidently derivable from `postedDateText` (absolute dates and "today/yesterday/X minutes|hours ago" labels; deadline labels like "Ends in 3 days" don't imply a posting date and are omitted)
- `badge` — promotional/status badge when present (e.g. `"Příležitost dne"` = Opportunity of the day, `"Nové"` = New)
- `tags[]` — additional listing tags (e.g. home-office note, response-time note)
- `companyLogoUrl` — employer logo image
- `atmoskopRating` — employer rating summary from Atmoskop.cz (e.g. `"65 hodnocení na Atmoskopu"`)
- `atmoskopUrl` — link to the employer's Atmoskop.cz review page
- `url` — canonical apply/detail URL on jobs.cz
- `recordType: "job"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byLocation` / `byCategory` / `brigady` |
| `searchQuery` | string | `python` | Free-text keyword (mode=search, required; mode=brigady, optional) |
| `location` | select | – | Curated list of 30 major Czech cities/regions |
| `locationSlugCustom` | string | – | Free-text jobs.cz city slug override, for cities not in the dropdown. Not supported in mode=brigady |
| `category` | select | – | Curated list of 25 common professions/categories. Not supported in mode=brigady |
| `categorySlugCustom` | string | – | Free-text jobs.cz profession slug override. Not supported in mode=brigady |
| `salaryMinCzk` | int | `0` | Minimum gross monthly salary in Kč (0–200 000). mode=search/byLocation/byCategory only |
| `hourlyRateMin` | select | `any` | `any` / `100` / `200` / `300` / `400` / `500` (Kč/h). mode=brigady only |
| `radiusKm` | select | `(jobs.cz default)` | `0` / `10` / `20` / `30` / `40` / `50` km around `location`/`locationSlugCustom`. Only has an effect when a location is set (any mode, incl. brigady) |
| `datePosted` | select | `any` | `any` / `24h` / `3d` / `7d`. Works in every mode |
| `employmentTypes` | array | – | `full`, `part`, `internships`. mode=search/byLocation/byCategory only |
| `contractTypes` | array | – | `employment_contract`, `identification_number`, `agreement`. mode=search/byLocation/byCategory only |
| `education` | select | `any` | `any` / `primary` / `high` / `uni`. mode=search/byLocation/byCategory only |
| `languageSkills` | array | – | Required languages (`cs`, `en`, `de`, `fr`, `ru`, `pl`, `it`, `es`). mode=search/byLocation/byCategory only |
| `homeOffice` | select | `any` | `any` / `partial-work-from-home` / `work-mostly-from-home` / `flexible-hours`. mode=search/byLocation/byCategory only |
| `suitableFor` | select | `any` | `any` / `graduates` / `retired` / `maternity` / `disabled` / `ukraine_refugees`. mode=search/byLocation/byCategory only |
| `employerType` | select | `any` | `any` / `direct` / `agency` / `ngo`. mode=search/byLocation/byCategory only |
| `maxItems` | int | `30` | Hard cap on emitted records (1–500) |

#### Example: keyword search narrowed to a city

```json
{
  "mode": "search",
  "searchQuery": "python",
  "location": "praha",
  "maxItems": 50
}
```

#### Example: browse all jobs in a region

```json
{
  "mode": "byLocation",
  "location": "brno",
  "datePosted": "7d",
  "maxItems": 100
}
```

#### Example: browse a profession with a salary floor

```json
{
  "mode": "byCategory",
  "category": "programator",
  "salaryMinCzk": 60000,
  "employmentTypes": ["full"],
  "maxItems": 50
}
```

#### Example: browse part-time/temp gigs (brigády) in a city with a minimum hourly rate

```json
{
  "mode": "brigady",
  "location": "praha",
  "hourlyRateMin": "200",
  "datePosted": "7d",
  "maxItems": 50
}
```

### Use cases

- **Salary benchmarking** — track advertised Kč ranges by profession or region across the Czech job market
- **Labor-market research** — measure job volume by category/city over time
- **Recruitment intelligence** — monitor competitor job postings and hiring velocity
- **HR tech / job aggregators** — feed structured Czech job listings into a meta-search product
- **Relocation/expat services** — surface English-language-friendly roles by city

### FAQ

**What is the data source, and how fresh is it?**
This actor reads the public search-results pages of `jobs.cz`, a leading Czech job board (part of the LMC group, which also operates Prace.cz). Each run fetches live listings at request time — there's no caching layer. It is an independent, third-party scraper and is not affiliated with or endorsed by jobs.cz or LMC.

**Why do some jobs have no salary fields?**
Many employers don't disclose salary. `salaryText`/`salaryMinCzk`/`salaryMaxCzk` are only included when the listing displays a figure — no fabricated values are ever emitted. This also applies when you set the `salaryMinCzk` input filter: jobs.cz matches that filter against each ad's internal salary data even when the figure isn't publicly displayed, so a filtered run can still return jobs with no visible salary fields — the filter does not exclude non-disclosing ads.

**Why does a `mode=search` keyword result occasionally include an off-topic job?**
jobs.cz always shows one promoted "Opportunity of the day" ad as the very first search-result card, regardless of how well it matches your `searchQuery` — this is dropped automatically from keyword searches. Beyond that, jobs.cz's own free-text relevance ranking can still surface loosely-related results for broad single-word queries; narrowing with `location`, `category`, or more specific keywords improves precision.

**Why do some jobs have no `postedDate`?**
jobs.cz shows some listings with a countdown label ("Ends in 3 days") instead of a posting date, and some with a promotional badge ("Opportunity of the day") instead of either. Those don't imply a reliable posting date, so `postedDate` is omitted for them — `postedDateText` still shows the raw label.

**Can I combine a keyword search with a category browse?**
No — jobs.cz's own category-browse pages (`mode=byCategory`) don't apply a free-text keyword filter, so combining them would silently return unfiltered category results. Use `mode=search` with `location` to narrow a keyword search by city, or `mode=byCategory` with `location` to narrow a profession browse by city — both of those combinations work.

**Why do `location`/`byLocation` results for smaller cities include jobs in other cities or "Česká republika" (nationwide)?**
This mirrors jobs.cz's own behavior for the same city page. For less job-dense cities, jobs.cz's own matching widens beyond the literal city and mixes in nationwide/remote-eligible postings as recommended matches — the `location` value is sent to jobs.cz exactly as clicking that city in a browser would. Larger cities (Praha, Brno, Ostrava) rarely show this because they have enough genuinely local postings to fill the page on their own.

**Can I look up a city or profession that isn't in the dropdown?**
Yes — use `locationSlugCustom` or `categorySlugCustom` with the exact jobs.cz URL slug for that city/profession (lowercase, no diacritics, hyphens for spaces). This only applies to `search`/`byLocation`/`byCategory` — `mode=brigady` only supports the curated `location` dropdown (see below).

**What is `mode=brigady`, and why does it only support the curated `location` list?**
Jobs.cz runs a separate board at `jobs.cz/brigady/` for part-time, temporary, student and seasonal gigs (retail shifts, warehouse work, event staffing, etc.) — distinct from its main full-time job listings, with its own filters (posted-within window, minimum hourly rate) and its own city-matching mechanism that only recognizes a fixed set of cities rather than arbitrary URL slugs, so `locationSlugCustom` isn't supported there. Every other main-board filter (`salaryMinCzk`, `employmentTypes`, `contractTypes`, `education`, `languageSkills`, `homeOffice`, `suitableFor`, `employerType`, `category`) has no effect on `mode=brigady` and is ignored.

**What does `radiusKm` do, and why only 6 fixed values?**
jobs.cz widens or narrows how far from `location`/`locationSlugCustom` it looks for matches — 50 km by default, or a per-city default (10-50 km) on the brigády board. jobs.cz's own UI offers exactly these 6 fixed radius steps (0/10/20/30/40/50 km) rather than a free numeric range, so this actor mirrors that. It only has an effect when a location is set.

**Is a proxy or login required?**
No. The actor works with the default Apify datacenter proxy settings and needs no cookies or account credentials.

# Actor input Schema

## `mode` (type: `string`):

What to fetch. `search` = free-text keyword search (optionally narrowed to a city). `byLocation` = browse all jobs in a region/city (optionally narrowed to a category). `byCategory` = browse all jobs in a profession/category (optionally narrowed to a city). `brigady` = browse jobs.cz's separate part-time/temp-gig/student-job board (optionally narrowed by keyword, city and hourly rate).

## `searchQuery` (type: `string`):

Free-text keyword, e.g. `python`, `účetní`, `řidič`. Required for mode=search; optional for mode=brigady (leave empty to browse all recent gigs). Ignored in mode=byLocation and mode=byCategory (jobs.cz does not support combining a free-text query with a category/location browse page — see README FAQ).

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

Curated list of major Czech cities/regions. Required for mode=byLocation. In mode=search, narrows keyword results to this city. In mode=byCategory, narrows the category browse to this city. In mode=brigady, narrows gigs to a ~10-50km radius around this city (jobs.cz's own per-city default radius; brigády has no city-path URLs so this uses jobs.cz's location-lookup API instead — only the curated cities below are supported for mode=brigady, not `locationSlugCustom`). Pick `(none)` to leave unrestricted.

## `locationSlugCustom` (type: `string`):

Free-text jobs.cz URL slug for a city/region not in the dropdown (e.g. `vsetin`, `havirov`). Overrides `location` when set. Use the jobs.cz slug exactly as it appears in the site's own URLs (lowercase, no diacritics, hyphens for spaces). Not supported in mode=brigady (jobs.cz's brigády board has no city-path URLs) — use the curated `location` dropdown there instead.

## `category` (type: `string`):

Curated list of common jobs.cz profession/category slugs. Required for mode=byCategory. In mode=byLocation, narrows the city browse to this profession. Ignored in mode=brigady (jobs.cz's brigády board has no category browse). Pick `(none)` to leave unrestricted.

## `categorySlugCustom` (type: `string`):

Free-text jobs.cz URL slug for a profession not in the dropdown (e.g. `architekt`, `ucitel`). Overrides `category` when set. Use the jobs.cz slug exactly as it appears in the site's own URLs. Ignored in mode=brigady.

## `salaryMinCzk` (type: `integer`):

Only return jobs jobs.cz's own server-side filter matches at or above this gross monthly salary (in Czech crowns). Jobs.cz caps this filter at 200 000 Kč. Note: jobs.cz applies this filter using each ad's internal salary data even when that figure isn't shown publicly — many matching results will still have no visible `salaryText`/`salaryMinCzk`/`salaryMaxCzk` in the output (jobs.cz upstream behavior, not a bug). Non-disclosing ads are NOT excluded by this filter. Ignored in mode=brigady — use `hourlyRateMin` there instead.

## `hourlyRateMin` (type: `string`):

Only return gigs jobs.cz's own server-side filter matches at or above this hourly rate (Kč/hod). Only applies to mode=brigady; ignored in all other modes (which use `salaryMinCzk`, a monthly figure, instead). jobs.cz offers exactly these 5 fixed thresholds — not a free numeric range.

## `radiusKm` (type: `string`):

Widen or narrow jobs.cz's own distance match around `location`/`locationSlugCustom` (mode=search/byLocation/byCategory) or the curated `location` in mode=brigady. Only has an effect when a location is set — ignored otherwise. Leave as `(jobs.cz default)` to use jobs.cz's own default (50 km on `/prace/...` pages; a per-city default of 10-50 km on the brigády board). jobs.cz's own UI offers exactly these 6 fixed radius steps — not a free numeric range. Verified server-side: narrowing `location=praha` from 50 km to 0 km shrinks the total from ~7 800 to ~6 000 matching jobs.

## `datePosted` (type: `string`):

Restrict results to jobs posted/updated within this time window. Works in every mode, including mode=brigady.

## `employmentTypes` (type: `array`):

Full-time / part-time / internship-trainee programs. Leave empty for any. Ignored in mode=brigady (jobs.cz's brigády board doesn't expose this facet).

## `contractTypes` (type: `array`):

Type of legal working relationship. Leave empty for any. Ignored in mode=brigady.

## `education` (type: `string`):

Required education level. Ignored in mode=brigady.

## `languageSkills` (type: `array`):

Only return jobs requiring these languages. Leave empty for any. Ignored in mode=brigady.

## `homeOffice` (type: `string`):

Remote-work arrangement. Ignored in mode=brigady.

## `suitableFor` (type: `string`):

Only return jobs explicitly marked suitable for this group. Ignored in mode=brigady.

## `employerType` (type: `string`):

Whether the ad was posted by the direct employer or a recruitment agency/NGO. Ignored in mode=brigady.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "python",
  "location": "",
  "category": "",
  "salaryMinCzk": 0,
  "hourlyRateMin": "any",
  "radiusKm": "",
  "datePosted": "any",
  "employmentTypes": [],
  "contractTypes": [],
  "education": "any",
  "languageSkills": [],
  "homeOffice": "any",
  "suitableFor": "any",
  "employerType": "any",
  "maxItems": 30
}
```

# Actor output Schema

## `jobs` (type: `string`):

Dataset containing all scraped Jobs.cz job listings.

# 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 = {
    "mode": "search",
    "searchQuery": "python",
    "location": "",
    "category": "",
    "salaryMinCzk": 0,
    "hourlyRateMin": "any",
    "radiusKm": "",
    "datePosted": "any",
    "employmentTypes": [],
    "contractTypes": [],
    "education": "any",
    "languageSkills": [],
    "homeOffice": "any",
    "suitableFor": "any",
    "employerType": "any",
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/jobs-cz-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 = {
    "mode": "search",
    "searchQuery": "python",
    "location": "",
    "category": "",
    "salaryMinCzk": 0,
    "hourlyRateMin": "any",
    "radiusKm": "",
    "datePosted": "any",
    "employmentTypes": [],
    "contractTypes": [],
    "education": "any",
    "languageSkills": [],
    "homeOffice": "any",
    "suitableFor": "any",
    "employerType": "any",
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/jobs-cz-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 '{
  "mode": "search",
  "searchQuery": "python",
  "location": "",
  "category": "",
  "salaryMinCzk": 0,
  "hourlyRateMin": "any",
  "radiusKm": "",
  "datePosted": "any",
  "employmentTypes": [],
  "contractTypes": [],
  "education": "any",
  "languageSkills": [],
  "homeOffice": "any",
  "suitableFor": "any",
  "employerType": "any",
  "maxItems": 30
}' |
apify call crawlerbros/jobs-cz-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/jobs-cz-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/H9McZs1zGgmGVCc8v/builds/3k9duPAhB3whtqxxs/openapi.json
