# Úřad práce Scraper ($0.95/1K): Czech Labour Office Jobs (`tsutseisoftware/urad-prace-scraper`) Actor

All Czech Labour Office vacancies (Úřad práce, MPSV open data) with salary, region, profession, shifts and foreigner flags. Track new, changed and filled jobs. Optional ARES company data. Unofficial.

- **URL**: https://apify.com/tsutseisoftware/urad-prace-scraper.md
- **Developed by:** [Tomáš Buchta](https://apify.com/tsutseisoftware) (community)
- **Categories:** Jobs
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 1,000 vacancies

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Úřad práce Scraper: Czech Labour Office Jobs (MPSV)

Get **every job vacancy registered at the Czech Labour Office** (Úřad práce ČR) as clean structured data, straight from the official **MPSV open data** that are published every night: about **40 000 vacancies with 105 000 open positions**, many of them never advertised on commercial job boards. Filter by **keywords**, **regions, districts and municipalities**, **CZ-ISCO profession codes**, **salary**, **employment type** (full-time, part-time, DPP, DPČ), **shift pattern**, **education**, **benefits** and **vacancies open to foreigners** (non-EU citizens, employee card, EU Blue Card). For each vacancy you get the title, employer with its **IČO**, place of work with **region (kraj) and district (okres)**, **salary for every vacancy** (with monthly and hourly equivalents), contract types, hours, shifts, required education, languages and skills, benefits, number of open positions and a link to the vacancy on the official portal.

Built for **watching the labour market**: schedule it daily in monitoring mode and you get, and pay for, only vacancies that are new or changed, plus, if you want, the vacancies that **disappeared** (filled or withdrawn) and how many days they were open. Every run also saves a free **market summary** (salary median and quartiles by region and field, top employers). Optional **company data from ARES**, the public Czech business register (legal form, size, main activity), found exactly by the IČO, for an extra charge.

*Source: MPSV / Úřad práce ČR open data* ([data.mpsv.cz](https://data.mpsv.cz/web/data/volna-mista-za-celou-cr), dataset "Volná místa za celou ČR"). Unofficial tool, not affiliated with MPSV or the Labour Office.

> **Česky:** Volná pracovní místa **Úřadu práce ČR** z otevřených dat MPSV (denně aktualizovaný celostátní registr): mzda u každé nabídky, firma a IČO, profese CZ-ISCO, obec a kraj, úvazek, směny, vzdělání, vhodnost pro cizince (zaměstnanecká a modrá karta). Filtry, monitoring a volitelně údaje z ARES. Výstup do Excelu, CSV nebo JSON. Podporu poskytujeme i česky.

### Why use this Úřad práce scraper?

- 🏛️ **The official register, complete.** All vacancies the Labour Office publishes, read from the MPSV open data file in one go: no website scraping, no pagination limits, no proxy, the same data the public portal shows.
- 💰 **A salary for every vacancy.** Employers must give a salary to the Labour Office, so every row has `salaryMin` (and often `salaryMax`), monthly or hourly, plus monthly and hourly equivalents. Amounts that don't fit their period (34 000 "per hour") are kept but not converted.
- 🗺️ **Codes translated to names.** Municipalities, districts, regions, CZ-ISCO professions, fields of activity, contract types, shifts, education, skills, languages and benefits come as readable names (official MPSV/ČSÚ code lists built into the actor), and as stable English values for filtering.
- 🌍 **Vacancies for foreigners.** Flags for vacancies open to non-EU citizens, in the employee card register (zaměstnanecká karta) or the EU Blue Card register, and for employers looking for EU workers, with a filter.
- 🕑 **Shift pattern, hours and positions.** Single, two, three or four shifts, continuous operation, night, flexible hours; hours per week; how many people the employer is hiring.
- 📬 **Monitoring mode:** a daily feed of new and changed vacancies (`changeType`), optionally with **removed vacancies** (`removedAt`, `daysOnline`) to see how fast positions are filled.
- 📊 **Free market summary** after every run (`SUMMARY` record): median and quartiles of monthly salary overall, by region and by field, top 20 employers, employment types, regions, number of open positions.
- 🏢 **Company data from ARES** (optional, extra charge): legal form, registered office, employee count range, main activity (CZ-NACE), founding date, matched by the IČO (no guessing by name).
- 🔒 **Privacy first.** Contact persons only if you turn them on (off by default); e-mails and phone numbers in the free text are replaced and the contact person's name is masked; employers that are private persons (sole traders) are never named.
- ⚡ **Fast and cheap:** the whole register is one ~18 MB download; a run that needs 20 vacancies stops reading after the first megabyte or two.

### What data can you get?

| Field | Example |
|---|---|
| Title, employer, IČO | Řidič/ka sk. C+E, POSPIECH SD, s.r.o., 26838869 |
| Place of work | Ostrava, district Ostrava-město, region Moravskoslezský kraj; street Luční 1210/20, postal code 72100, city part Svinov (`cityDistrict` e.g. "Praha 3") |
| Salary | 30 000 – 45 000 CZK per month (monthly 30 000 – 45 000, hourly 187.5 – 281.25) |
| Contract | fullTime, employee ("Pracovní poměr - plný úvazek"); DPP, DPČ; 40 hours per week |
| Shifts, positions | twoShifts ("Dvousměnný provoz"), 2 open positions |
| Profession | CZ-ISCO 83322 "Řidiči tahačů", field "Doprava" |
| Requirements | education "Střední odborné (vyučen)" (level `apprenticeship`), languages "Angličtina (aktivní)", skills "Řidičský průkaz sk. C" |
| Foreigners | openToNonEuForeigners, employeeCard, blueCard, euWorkersWanted |
| Benefits | "Podnikové stravování: stravenky", "Dovolená navíc: 5 týdnů" |
| Dates | posted 2026-05-05, start 2026-06-01, fixed-term until, last change |
| Description | the employer's free text, e-mails, phone numbers and the contact person's name removed |
| Labour office | Krajská pobočka pro hlavní město Prahu |
| With **Add company data from ARES** | Společnost s ručením omezeným, 25-49 employees, 43210 Elektrické instalace, founded 2001-06-27 |
| With **Monitoring: include removed vacancies** | changeType `removed` (removedAt, firstSeenAt, lastSeenAt, daysOnline) and `reappeared` |

See the **Output** tab for all fields. The dataset has views for **Overview**, **Salaries**, **Companies**, **Foreign workers**, **Requirements**, **Places**, **Monitoring** and **Removed vacancies**.

### How to get Czech Labour Office vacancies

1. Choose what you need: **Keywords** (e.g. `řidič`, `svářeč`, `účetní`), **Regions**, **Districts** or **Municipalities**, and any **Job filters** (profession codes, salary, employment type, shifts, education, foreigners, benefits...). Empty input = the most recently changed vacancies of the whole country.
2. Set **Max vacancies** (0 = no limit) and the order (**Sort by**), and turn on **Add company data from ARES** if you need it.
3. Click **Start** and download the results as JSON, CSV or Excel, or use the API. The market summary is in the **Storage → Key-value store** tab as `SUMMARY` (and in the **Output** tab).

### Use cases

#### New vacancies for drivers in Prague every morning

Save this input as a task, add a **Schedule** (daily, the data are updated every night) and connect an **integration** (e-mail, Slack, Google Sheets, Make, Zapier or a webhook). Each run returns only vacancies that are new or changed.

```json
{
  "keywords": ["řidič"],
  "regions": ["praha"],
  "maxItems": 0,
  "onlyNewOrChanged": true
}
```

#### Vacancies open to foreign workers with accommodation

```json
{
  "foreigners": ["employeeCard"],
  "benefits": ["accommodation"],
  "sortBy": "positions",
  "maxItems": 500
}
```

#### Salary research for a profession group

All software developers (CZ-ISCO 2512) in the country, highest salary first; the free `SUMMARY` record has the median and quartiles by region.

```json
{
  "professionCodes": ["2512"],
  "sortBy": "salary",
  "maxItems": 0
}
```

#### Filled vacancies and time to fill

Run daily with removed vacancies turned on. Vacancies that are no longer in the data come back as rows with `changeType: "removed"`, `removedAt` and `daysOnline` (days from posting to the last run that still saw the vacancy).

```json
{
  "districts": ["Brno-město", "Brno-venkov"],
  "maxItems": 0,
  "onlyNewOrChanged": true,
  "includeRemovedJobs": true
}
```

#### Shift work in manufacturing, apprenticeship at most, posted this week

```json
{
  "categories": ["Výroba a provoz"],
  "shiftPatterns": ["twoShifts", "threeShifts", "continuous"],
  "maxEducation": "apprenticeship",
  "postedWithinDays": 7,
  "maxItems": 200
}
```

#### Hiring employers with company data

```json
{
  "municipalities": ["Plzeň"],
  "employerType": "directEmployer",
  "includeCompanyInfo": true,
  "maxItems": 100
}
```

#### Filters (all applied by the actor; filtered-out vacancies are free)

| Input | What it does |
|---|---|
| **Keywords**, **Exclude keywords** | words in the job title or the CZ-ISCO profession name, at the start of a word; typed with diacritics they must match them (`řidič` does not find `řídící`), typed without any accents match (`ridic` finds `řidič`) |
| **Regions**, **Districts**, **Municipalities** | the place of work; a vacancy in any of the given places is kept. **Include vacancies for the whole country** adds those whose place of work is the whole Czech Republic |
| **Profession codes (CZ-ISCO)** | code prefixes: `8332` truck drivers, `2512` software developers, `25` ICT professionals, `93` labourers |
| **Categories** | field of activity of the profession (obor činnosti, MPSV code list): Doprava, Výroba a provoz, Zdravotnictví... |
| **Minimum salary (CZK per month)** | top of the salary range at least this much (hourly × 160) |
| **Employment type** | full-time, part-time, DPP, DPČ, civil service |
| **Shift pattern** | single, two, three, four shifts, split shifts, continuous, night, flexible hours, rotation |
| **Education: at least / at most** | the minimum education the employer requires, from none to doctorate |
| **Suitable for foreigners** | open to non-EU citizens, employee card, EU Blue Card |
| **Suitable for** | graduates, under 18, people with disabilities, wheelchair users, asylum holders |
| **Benefits** | accommodation, meals, extra holiday, bonuses, travel, kindergarten... |
| **Employer type**, **Public sector** | direct employers or employment agencies (agentury práce); civil service and local government positions |
| **Posted / Changed in the last N days** | by the date the vacancy was entered or last changed |
| **Employer IČO**, **Exclude employer IČO**, **Company name contains**, **Exclude company names** | by employer |
| **Vacancy IDs or URLs** | only these vacancies (check whether they are still open) |

#### Monitoring mode explained

With **Monitoring: only new or changed vacancies** each run compares the matching vacancies with the previous run that used the same **Monitoring: key**. A vacancy is returned as `changeType: "new"` when it wasn't seen before, or `"updated"` when its title, employer, salary, place, contract, hours, shifts, number of positions or education changed (`changedFields` says which of title, salary and positions). The Labour Office touches many vacancies every night (the "last changed" date), and employers edit their texts; neither counts as a change. Vacancies not seen for 90 days are forgotten. Use one key per watched search, and keep the same filters for that key.

**Monitoring: include removed vacancies** adds vacancies from the previous run that are **no longer in the Labour Office data** (filled, withdrawn or expired), with their last known title, employer, place, salary and URL, `changeType: "removed"`, `firstSeenAt`, `lastSeenAt`, `removedAt` and `daysOnline`. Each removed vacancy is reported once; if it comes back, it is returned once as `"reappeared"`. A vacancy that is still in the data but no longer matches your filters is not reported as removed. Removed vacancies are checked **only when the run read the whole file**: keep **Max vacancies** at 0 (or high enough). **Removed rows are normal dataset rows and are charged like any other vacancy.**

#### Market summary (SUMMARY)

Every run writes a free JSON record `SUMMARY` to the run's default key-value store (link in the **Output** tab). It covers all vacancies the run found that match your filters (in monitoring mode also the unchanged ones), each once.

| Key | Content |
|---|---|
| `counts` | vacancies in the data, matched, saved, open positions; in monitoring mode new, updated, unchanged, removed and reappeared |
| `salary` | monthly CZK median and quartiles (`p25`, `median`, `p75`) overall, `byRegion` and `byCategory` (groups of at least 5 vacancies) |
| `topCompanies` | top 20 employers by number of vacancies |
| `employmentTypes`, `regions`, `workArrangement` | number and share per value |
| `data` | which MPSV file was read, when MPSV published it, bytes downloaded |

The monthly figure of a vacancy is the middle of its salary range; hourly wages count as 160 hours per month. The summary contains no personal data: employers only (never private persons), no contacts, no descriptions.

#### Company data from ARES (optional, extra charge)

With **Add company data from ARES (extra charge)** the actor looks up each employer in **ARES** (Administrativní registr ekonomických subjektů), the public register of the **Ministry of Finance of the Czech Republic** (ares.gov.cz), **by the IČO given in the Labour Office data**, and adds `companyIco`, `companyLegalForm`, `companyAddress` (registered office), `companyEmployeeRange` (e.g. `25-49`), `companyNace` (main activity) and `companyFoundedAt`, with `companyInfoSource: "ARES"`, `companyInfoMatch: "ico"` and `companyInfoRetrievedAt`.

- **Off by default.** Without this option the actor never contacts ARES.
- **Exact:** the IČO comes from the Labour Office, so there is no name matching. For an employment agency the data describe the agency (the employer in the data).
- **No private persons.** When ARES says the employer is a natural person (a sole trader), nothing from ARES is returned and the vacancy's employer name, IČO and address are removed too.
- Each IČO is looked up once per run, one request at a time (at most about 60 per minute), always directly. Results are kept for 30 days in a key-value store `urad-prace-ares-cache` in your account (sole traders are never stored). If ARES is unavailable or limits requests, vacancies are saved without company data and the status message says so.
- **Price:** you pay the **Company info** event only for saved vacancies that got company data. Your **maximum cost per run** is respected.
- About 1–2 seconds per new employer, so a run with company data takes longer.

This actor is not affiliated with or endorsed by the Ministry of Finance of the Czech Republic.

#### Contact person and privacy (optional, personal data)

**Include contact person (personal data)** adds `recruiterName`, `recruiterPhone` and `recruiterEmail`: the person the employer named for applicants, as the Labour Office portal shows it. Off by default.

- **When not.** Never for employers that look like a private person (also when ARES says so), for vacancies published without employer data, or for people who asked to be left out. No list of contact persons, no count per person, no contact in the `SUMMARY` record.
- **Nothing is kept by the actor.** Contacts go only into your run's dataset: never into the monitoring state, the ARES cache, the `SUMMARY` record or the log. A change of the contact person doesn't count as a change in monitoring mode. No extra charge.
- **You are the data controller (GDPR).** You need your own legal basis, typically a legitimate interest, and only for **responding to that specific vacancy** (e.g. as an applicant or on an applicant's behalf).
- **No marketing.** In Czechia, commercial e-mails and SMS without prior consent are prohibited (Act No. 480/2004 Coll., § 7), also to business addresses, and marketing calls need consent (Act No. 127/2005 Coll., § 96). Don't use the contacts for marketing, don't resell them and don't build contact databases from them.
- **Inform and delete.** Tell the person who you are, why you contact them and where you got the contact (Labour Office vacancy), and that they may object (Art. 14 GDPR). Delete a dataset with contacts as soon as you no longer need it.
- **To be left out of future results:** open an issue in the **Issues** tab of this actor in Apify Store, or write to Apify's privacy contact privacy@apify.com.

### How much does it cost to get Úřad práce vacancies?

Pay per result, see the **Pricing** tab for the current prices and discounts for higher Apify plans:

| What | Price |
|---|---|
| Vacancy (every saved row, including removed vacancies in monitoring mode) | **$0.95 per 1 000 vacancies** ($0.89 Bronze, $0.85 Silver, $0.75 Gold and higher Apify plans) |
| **+ Company info** (only vacancies that got company data from ARES) | **+$1.00 per 1 000 vacancies** |
| Contact person (optional) | no extra charge |
| Filtered-out vacancies, unchanged vacancies in monitoring mode, the `SUMMARY` record | free |

There is also a start fee of **$0.005 per run** (half a cent): every run reads the Labour Office file, so a daily check that finds only a few new vacancies still covers its cost. Example: a daily monitoring run with 3 new vacancies costs $0.005 + 3 × $0.00095 ≈ $0.008, about $0.24 a month.

Platform usage is included. Typical runs (512 MB):

| Scenario | Data downloaded | Typical time |
|---|---|---|
| 20 vacancies (most recently changed, with filters) | ~1–2 MB | a few seconds |
| 100 vacancies sorted by salary (whole file read) | ~18 MB | about a minute |
| The whole register (~40 000 vacancies) | ~18 MB | 1–3 minutes |
| Daily monitoring of a search, whole file read | ~18 MB | about a minute |

### Input example

```json
{
  "keywords": ["řidič"],
  "regions": ["praha"],
  "maxItems": 20
}
```

### Output example

```json
{
  "id": "uradprace:67256333",
  "source": "up.gov.cz",
  "url": "https://up.gov.cz/volna-mista-v-cr#/volna-mista-detail/67256333",
  "jobId": "67256333",
  "referenceNumber": "33083960721",
  "title": "Řidič/ka sk. C+E",
  "company": "POSPIECH SD, s.r.o.",
  "companyId": "26838869",
  "isAgency": false,
  "publicSector": false,
  "employerUrl": null,
  "location": "Ostrava",
  "locations": ["Ostrava"],
  "region": "Moravskoslezský kraj",
  "district": "Ostrava-město",
  "regions": ["Moravskoslezský kraj"],
  "locationType": "workplaceAddress",
  "municipalityCode": "554821",
  "districtCode": "3807",
  "streetAddress": "Luční",
  "houseNumber": "1210/20",
  "postalCode": "72100",
  "cityPart": "Svinov",
  "cityDistrict": "Svinov",
  "workplaceName": "POSPIECH SD, s.r.o.",
  "workplaceAddress": null,
  "workArrangement": "onsite",
  "salaryMin": 70000,
  "salaryMax": null,
  "salaryCurrency": "CZK",
  "salaryPeriod": "month",
  "salaryMonthlyMin": 70000,
  "salaryMonthlyMax": null,
  "salaryHourlyMin": 437.5,
  "salaryHourlyMax": null,
  "employmentType": ["fullTime"],
  "contractTypes": ["employee"],
  "contractTypeNames": ["Pracovní poměr - plný úvazek"],
  "hoursPerWeek": null,
  "shiftPattern": "continuous",
  "shiftPatternName": "Nepřetržitý provoz",
  "positions": 2,
  "education": "Základní + praktická škola",
  "educationLevel": "elementary",
  "educationFields": [],
  "languagesRequired": [],
  "skills": [],
  "experienceIn": [],
  "professionCode": "83322",
  "profession": "Řidiči tahačů",
  "categories": ["Doprava"],
  "suitableFor": ["graduates"],
  "openToNonEuForeigners": true,
  "employeeCard": true,
  "blueCard": false,
  "euWorkersWanted": true,
  "benefits": [],
  "benefitTypes": [],
  "startDate": "2026-06-01",
  "endDate": null,
  "postedAt": "2026-05-05",
  "updatedAt": "2026-11-05T22:01:44Z",
  "validThrough": null,
  "labourOffice": "Kontaktní pracoviště Ostrava",
  "labourOfficeCode": "OTA",
  "description": "83322   Řidiči tahačů\nZamK\nKontakt e-mailem, telefonicky.\nNáplň práce:\n- řízení a nakládání nákladního vozidla nad 3,5 t…",
  "changeType": null,
  "firstSeenAt": null,
  "changedFields": null,
  "lastSeenAt": null,
  "removedAt": null,
  "daysOnline": null,
  "scrapedAt": "2026-11-06T10:00:00Z"
}
```

### Limitations

- **What the Labour Office has.** The data contain the vacancies employers registered at the Labour Office (by law or voluntarily). Many of them are also on commercial job boards, many are not; office and IT jobs are fewer than on Jobs.cz or Prace.cz, manual, driving, care and shift work more.
- **Updated once a day.** MPSV publishes the file every night (around midnight); vacancies added during the day appear the next morning. The status message and `SUMMARY` say which version a run read. The actor reads the compressed copy of the file and switches to the uncompressed one (about 10× more data) when the compressed copy is older than the data.
- **Salary** is given for every vacancy, but often only as the bottom of the range (in our sample `salaryMax` was set for about 40 %), frequently at the minimum wage.
- **Region and district** are known for about 98.7 % of vacancies with a place of work; the rest gave neither an address nor a recognisable place. Vacancies for the whole country have no region.
- **Work arrangement** (`hybrid`, `remote`) is read from the ad text, because the Labour Office form has no field for it: under 1 % of vacancies mention home office.
- **Employer names that look like a private person** (sole traders, about 6 % of vacancies) are returned as `null` together with their IČO, website and workplace address; municipality, district and region stay. A name counts as a person when it has the shape of a personal name and a given name, a Czech female surname or an academic title; in a random sample of 80 of the 1 662 hidden names (of 18 000 employers) all were people, mostly sole traders. 22 vacancies (0.06 %) are published by the Labour Office without employer data at all.
- **Descriptions** are written by employers and may mention other people by name; e-mails, phone numbers and the named contact person are removed, other names in the free text are not. Use descriptions for analysis, not for republishing.
- **Removed vacancies** are checked only after a run that read the whole file; see *Monitoring mode explained*.
- If the download breaks, it is resumed where it stopped (up to 3 times); if the file can't be read to the end, the run keeps what it read and says that the results may be incomplete.

### For AI agents and API users

- **Minimal input:** `{"keywords": ["řidič"], "regions": ["praha"], "maxItems": 20}`; `{}` returns the 100 most recently changed vacancies.
- One row = one vacancy = one charge. `includeCompanyInfo: true` adds the **Company info** charge only for rows with `companyInfoSource: "ARES"`.
- `maxItems` counts saved rows. With `sortBy: "recentlyChanged"` (the default) the run stops reading once it has enough; other orders read the whole file.
- Enum values: `employmentType` ⊂ `fullTime`, `partTime`; `contractTypes` ⊂ `employee`, `dpp`, `dpc`, `civilService`; `shiftPattern` ∈ `singleShift`, `twoShifts`, `threeShifts`, `fourShifts`, `splitShifts`, `continuous`, `night`, `flexibleHours`, `rotation`, `unspecified`; `educationLevel` ∈ `none`, `elementary`, `lowerSecondary`, `apprenticeship`, `maturita`, `higherVocational`, `bachelor`, `master`, `doctorate`; `salaryPeriod` ∈ `month`, `hour`; `changeType` ∈ `new`, `updated`, `removed`, `reappeared`; `regions` input ⊂ `praha`, `stredocesky-kraj`, `jihocesky-kraj`, `plzensky-kraj`, `karlovarsky-kraj`, `ustecky-kraj`, `liberecky-kraj`, `kralovehradecky-kraj`, `pardubicky-kraj`, `kraj-vysocina`, `jihomoravsky-kraj`, `olomoucky-kraj`, `zlinsky-kraj`, `moravskoslezsky-kraj`.
- Field names match the Jobs.cz and Prace.cz scrapers of the same author where they overlap (`title`, `company`, `location`, `region`, `district`, `salary*`, `employmentType`, `contractTypes`, `categories`, `postedAt`, monitoring fields), so the datasets can be merged.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<username>/urad-prace-scraper").call(run_input={
    "keywords": ["svářeč"],
    "regions": ["moravskoslezsky-kraj"],
    "maxItems": 100,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["district"], job["salaryMin"], job["url"])
summary = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("SUMMARY")["value"]
print(summary["salary"]["monthlyCzk"])
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('<username>/urad-prace-scraper').call({
    keywords: ['řidič'], regions: ['praha'], maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((j) => `${j.title} (${j.company}, ${j.salaryMin} CZK)`));
```

You can also connect the actor to Make, Zapier, n8n, Google Sheets, Slack, e-mail or webhooks and schedule it in Apify Console.

### Troubleshooting

| Status message | What to do |
|---|---|
| `"Regions": unknown region` | Use one of the listed values, e.g. `praha`, `jihomoravsky-kraj`. |
| `"Districts": unknown district` | Use the district (okres) name, e.g. `Brno-venkov`, `Praha-východ`; the message suggests similar names. |
| `"Municipalities": unknown municipality` | Use the official name (`Mladá Boleslav`, not `MB`) or the 6-digit ČSÚ code. |
| `Saved 0 vacancies (new or changed since last run…)` | Nothing changed since the previous monitoring run; that's expected. |
| `removed vacancies were not checked because the run stopped reading at Max vacancies` | Set **Max vacancies** to 0 (or high enough). |
| `the compressed copy … was older than the data file, so the uncompressed file was read` | Nothing to do: the run used the newest data (a larger download). |
| `the data file could not be read to the end …, so the results may be incomplete` | data.mpsv.cz broke the connection; run it again for complete results. |
| `The Labour Office data could not be downloaded from data.mpsv.cz` | The MPSV server is not available; try again later. |
| `company info unavailable for the rest of the run: ARES rate limit` | ARES limited requests; the vacancies were saved without company data and without the extra charge. Try again later. |

### More Czech job scrapers

The same output format for the other Czech job sources (many jobs are published on several of them):

- [Czech Jobs Aggregator](https://apify.com/tsutseisoftware/czech-jobs-aggregator): all these Czech job boards in one run: duplicates merged, one output format, monitoring
- [Jobs.cz Scraper](https://apify.com/tsutseisoftware/jobs-cz-scraper): Czech jobs with salary, region, requirements, monitoring and optional ARES company data
- [Prace.cz Scraper](https://apify.com/tsutseisoftware/prace-cz-scraper): Czech jobs with salary, region, monitoring and optional ARES company data
- [Pracezarohem.cz Scraper](https://apify.com/tsutseisoftware/pracezarohem-scraper): jobs near a town (GPS distance search) from all big Czech job sources, with the portal of every ad
- [JenPráce.cz Scraper](https://apify.com/tsutseisoftware/jenprace-scraper): Czech jobs and side jobs with salary, own ads told apart from Labour Office vacancies
- [StartupJobs.cz Scraper](https://apify.com/tsutseisoftware/startupjobs-scraper): IT and startup jobs with salary, technologies, seniority, remote work, company profiles and an IT market overview
- [Profesia.sk & .cz Scraper](https://apify.com/tsutseisoftware/profesia-scraper): Slovak and Czech jobs from Profesia with salary, region and monitoring
- [Fajn-brigady.cz & INwork.cz Scraper](https://apify.com/tsutseisoftware/fajn-brigady-scraper): Czech temporary and part-time jobs from two websites: hourly wage, town, start date, monitoring
- [GastroJobs.cz Scraper](https://apify.com/tsutseisoftware/gastrojobs-scraper): Czech hotel, restaurant and catering jobs: salary, type of venue, employer company ID, monitoring

### Custom scrapers and changes

Need a custom version of this actor, another field or filter, or a scraper for a different website? Write to **info@tsutsei-software.com** with the website, the data you need and how often, and we will reply with a fixed quote. We work mainly with clients from the Czech Republic and from outside the EU.

More about us and all our actors: [tsutsei-software.com](https://tsutsei-software.com).

### FAQ

#### Is it legal to use the Labour Office data?

Yes. The vacancies are **open data of the Ministry of Labour and Social Affairs (MPSV)**, published for reuse; according to MPSV's terms of use they are not protected by copyright and there is no database right in them. The actor downloads the published file once per run, without logging in and without any load on the Labour Office's portal. The data contain personal data (the contact person of a vacancy, names and phone numbers in the free text, employers who are private persons): the actor leaves them out by default, as described above, and if you turn on **Include contact person (personal data)** you are responsible for using the contacts lawfully. If unsure, consult a lawyer.

#### Where do the data come from?

**Source: MPSV / Úřad práce ČR open data** ("Volná místa za celou ČR", data.mpsv.cz), updated every night. Each vacancy links to its page on the Labour Office portal (up.gov.cz). Code lists (municipalities, districts, regions, CZ-ISCO, education, shifts...) are the open MPSV and ČSÚ code lists, built into the actor.

#### How fresh are the data?

As fresh as the MPSV file: it is regenerated every night, so a run in the morning has yesterday's vacancies. The `SUMMARY` record (`data.lastModified`) says when the file the run read was published.

#### Do I need a proxy?

No. The actor downloads one open-data file; no proxy is used.

#### Does it scrape Jobs.cz or Prace.cz too?

No, only the Labour Office register. For those job boards use the scrapers linked above; the field names are the same.

#### Can I get the contact person's phone number?

Only if you turn on **Include contact person (personal data)**: the name, phone and e-mail of the person the employer named for applicants, never for private employers. These are personal data: use them only to respond to that specific vacancy, never for marketing (see *Contact person and privacy*).

#### Something doesn't work

Open an issue in the **Issues** tab and include the input you used.

This is an unofficial tool, not affiliated with or endorsed by the Ministry of Labour and Social Affairs of the Czech Republic (MPSV), the Labour Office of the Czech Republic (Úřad práce ČR) or the Ministry of Finance of the Czech Republic. It is also known as a Úřad práce API, Czech Labour Office vacancies API, "volná místa Úřad práce", "volná pracovní místa MPSV" or "nabídky práce ÚP ČR".

# Actor input Schema

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

Vacancies whose job title or CZ-ISCO profession name contains one of these words at the start of a word, e.g. "řidič", "svářeč", "účetní". Typed with diacritics, the word must match them ("řidič" does not find "řídící"); typed without, any accents match ("ridic" finds "řidič"). Empty = all vacancies.

## `excludeKeywords` (type: `array`):

Skip vacancies whose title or profession contains any of these words (same matching as Keywords), e.g. "brigáda".

## `regions` (type: `array`):

Only vacancies with a place of work in these regions (kraj). With Districts or Municipalities too, a vacancy in any of them is kept.

## `districts` (type: `array`):

Only vacancies in these districts (okres), e.g. "Brno-venkov", "Praha-východ", "Ostrava-město", "Kladno" (diacritics optional). Vacancies listed for several districts match any of them.

## `municipalities` (type: `array`):

Only vacancies in these municipalities (obec), e.g. "Brno", "Mladá Boleslav", "Plzeň", or 6-digit ČSÚ codes. A name shared by several municipalities matches all of them (add a District to narrow it).

## `includeNationwide` (type: `boolean`):

With Regions, Districts or Municipalities: also keep vacancies whose place of work is the whole Czech Republic (often driving or field jobs).

## `professionCodes` (type: `array`):

CZ-ISCO codes or their first digits: "8332" (truck drivers), "2512" (software developers), "25" (all ICT professionals), "93" (labourers), "2221" (nurses).

## `categories` (type: `array`):

Only vacancies in these fields of activity (obor činnosti of the profession, MPSV code list).

## `minSalary` (type: `integer`):

Only vacancies whose top of the salary range is at least this much a month, e.g. 40000. Hourly wages count as 160 hours a month. Every vacancy in the data has a salary.

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

Only these employment relationships. Several values = any of them.

## `shiftPatterns` (type: `array`):

Only vacancies with one of these shift patterns.

## `minEducation` (type: `string`):

Only vacancies whose minimum required education is at least this level (e.g. Bachelor's for jobs that need a degree).

## `maxEducation` (type: `string`):

Only vacancies whose minimum required education is at most this level (jobs a person with this education can apply for).

## `foreigners` (type: `array`):

Only vacancies the employer opened to foreigners: non-EU citizens, employee card holders (zaměstnanecká karta) or EU Blue Card holders. Several values = any of them.

## `suitableFor` (type: `array`):

Only vacancies the employer marked as suitable for these groups.

## `benefits` (type: `array`):

Only vacancies offering one of these benefits.

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

Direct employers only, or employment agencies (agentury práce) only.

## `publicSector` (type: `string`):

Civil service and local government positions (státní správa a samospráva) only, or without them.

## `postedWithinDays` (type: `integer`):

Only vacancies entered in the last N days (by date). 0 = any time.

## `changedWithinDays` (type: `integer`):

Only vacancies changed in the register in the last N days (the Labour Office updates many vacancies every night). 0 = any time.

## `employerIcos` (type: `array`):

Only vacancies of these employers, by IČO (company ID), e.g. "00177041". Employers hidden as private persons never match.

## `excludeEmployerIcos` (type: `array`):

Skip vacancies of these employers (IČO), e.g. agencies or your own company.

## `companies` (type: `array`):

Only vacancies of employers whose name contains one of these texts (case and diacritics don't matter).

## `excludeCompanies` (type: `array`):

Skip vacancies of employers whose name contains any of these texts.

## `vacancyIds` (type: `array`):

Only these vacancies: IDs (e.g. "67256333") or portal URLs (https://up.gov.cz/volna-mista-v-cr#/volna-mista-detail/67256333). Handy to check whether given vacancies are still open.

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

Maximum number of vacancies saved. You pay per saved vacancy. 0 = no limit (the whole register has about 40 000 vacancies).

## `sortBy` (type: `string`):

Order of the saved vacancies. Recently changed is the order of the data, so the run can stop reading as soon as Max vacancies is reached; the other orders read the whole file (about a minute longer).

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

The employer's free text (upřesňující informace), with e-mails and phone numbers removed and the contact person's name masked.

## `descriptionMaxLength` (type: `integer`):

Shorten the description to about this many characters (e.g. 300 for a snippet). 0 = full text.

## `includeCompanyInfo` (type: `boolean`):

Add data about the employer from ARES, the public register of economic subjects of the Czech Ministry of Finance, found by the IČO from the Labour Office data: legal form, registered office, employee count range, main activity (CZ-NACE) and founding date. Off by default: when off, the actor never contacts ARES. Extra charge only for vacancies that got company data. Natural persons (sole traders) never get any and their name is hidden too. About 1-2 seconds per new employer.

## `includeRecruiterContacts` (type: `boolean`):

Off by default. Adds recruiterName, recruiterPhone and recruiterEmail of the person to contact, as the Labour Office portal shows them. Never for private employers, vacancies without employer data or people who objected. These are personal data: use them only to respond to that vacancy, never for marketing (see the README). No extra charge.

## `onlyNewOrChanged` (type: `boolean`):

Return only vacancies that are new or whose title, employer, salary, place, contract, hours, shifts, positions or education changed since the previous run with the same Monitoring key. Unchanged vacancies are free.

## `monitoringKey` (type: `string`):

Name of the saved state. Use a different key for each watched search (e.g. 'ridic-praha'). Empty = "default". The value is stored encrypted.

## `includeRemovedJobs` (type: `boolean`):

With "Monitoring: only new or changed vacancies": also return vacancies from the previous run with the same Monitoring key that are no longer in the Labour Office data (filled or withdrawn), as rows with changeType "removed", removedAt, daysOnline and the last known title, employer, place and salary. Checked only when the run read the whole file (set Max vacancies to 0 or high enough).

## Actor input object example

```json
{
  "keywords": [
    "řidič"
  ],
  "regions": [
    "praha"
  ],
  "includeNationwide": false,
  "employerType": "any",
  "publicSector": "any",
  "maxItems": 20,
  "sortBy": "recentlyChanged",
  "includeDescription": true,
  "descriptionMaxLength": 0,
  "includeCompanyInfo": false,
  "includeRecruiterContacts": false,
  "onlyNewOrChanged": false,
  "includeRemovedJobs": false
}
```

# Actor output Schema

## `vacancies` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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": [
        "řidič"
    ],
    "regions": [
        "praha"
    ],
    "maxItems": 20,
    "includeCompanyInfo": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("tsutseisoftware/urad-prace-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": ["řidič"],
    "regions": ["praha"],
    "maxItems": 20,
    "includeCompanyInfo": False,
}

# Run the Actor and wait for it to finish
run = client.actor("tsutseisoftware/urad-prace-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": [
    "řidič"
  ],
  "regions": [
    "praha"
  ],
  "maxItems": 20,
  "includeCompanyInfo": false
}' |
apify call tsutseisoftware/urad-prace-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tsutseisoftware/urad-prace-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/wPVvGeL6ke52sbMC8/builds/8ZMnrats2rvXXKitz/openapi.json
