# JenPráce.cz Scraper ($1.44/1K): Czech Jobs & Salaries (`tsutseisoftware/jenprace-scraper`) Actor

Scrape JenPráce.cz jobs and side jobs with salary, company, region and contract type. Tell own ads from Labour Office vacancies, track new and removed jobs. Unofficial.

- **URL**: https://apify.com/tsutseisoftware/jenprace-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 $1.14 / 1,000 jobs

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

## JenPráce.cz Scraper: Czech Jobs, Salaries & Labour Office

Get job listings from **JenPráce.cz**, a large Czech job board with about 24 000 vacancies, as clean structured data. Search by **keywords**, **towns with a radius**, **regions** and the **website's own filters** (employment type, contract type, minimum salary, education, work from home, languages, "suitable for", accommodation, driving licence), on the job board and in **side jobs (brigády)**, or paste any JenPráce.cz search URL. For each job you get the title, employer, place of work with its **region (kraj) and district (okres)**, **salary when the employer shows it** (with monthly and hourly equivalents), employment type, date of the ad and labels. Optionally the actor opens each job page and adds the **description** (with e-mails, phone numbers and contact names removed), contract type, minimum education, languages, driving licence, benefits, categories and postal code.

JenPráce.cz lists its own ads and, after them, **vacancies of the Czech Labour Office (Úřad práce ČR)**. This actor tells them apart (`isLabourOfficeJob`) and lets you keep **only the website's own ads**, only Labour Office vacancies, or both.

Built for **watching the job market**: schedule it daily in monitoring mode and you get, and pay for, only jobs that are new or changed, plus, if you want, the jobs that **disappeared** since the last run and how many days they were online. Every run also saves a free **market summary** (salary median and quartiles by region, top employers, employment types).

> **Česky:** Scraper nabídek práce z **JenPráce.cz**: mzda, firma, kraj a okres, typ úvazku a vlastní nabídky odlišené od nabídek Úřadu práce. Víc výrazů a lokalit najednou, okruh kolem místa, monitoring nových a odstraněných nabídek a volitelně údaje z ARES. Výstup do Excelu, CSV nebo JSON. Podporu poskytujeme i česky.

### Why use this JenPráce.cz scraper?

- 🏛️ **Own ads vs. Labour Office vacancies.** About 70 % of the vacancies on JenPráce.cz come from the Labour Office's public database. Every job has `isLabourOfficeJob`, and **Ad source** keeps only the website's own ads (faster too: the actor stops reading once only Labour Office vacancies follow) or only Labour Office vacancies.
- 🔎 **The website's filters, applied by the website.** Employment type (full-time, part-time, trainee, side jobs), contract type (HPP, OSVČ, DPP/DPČ, civil service), minimum salary, minimum education, workplace (on site, hybrid, from home), languages, "suitable for" (graduates, foreigners, students, seniors, parents, people with disabilities), accommodation and driving licence are sent to JenPráce.cz in the URL, so the results match the website and filtered-out jobs cost nothing.
- 🗺️ **Towns with a radius, regions, and a region for almost every job**, worked out from the place of work ("Radotín, Praha", "Němčice, Svitavy") with the official list of Czech municipalities (ČSÚ / RÚIAN), without extra requests. With a radius, each job has its `distanceKm`.
- 💰 **Salaries you can compute with.** `salaryMin`, `salaryMax`, currency and period as numbers, plus monthly and hourly equivalents and the text as shown. Only salaries the website shows are returned; obviously wrong amounts (e.g. 6 720 000 CZK a month) are kept but not converted.
- 🎯 **Position matches vs. text matches.** A keyword search on the website first lists jobs matching the position and then jobs that only mention the word somewhere in the text. `matchedBy` says which, and **Skip text-only matches** keeps just the first kind.
- 📬 **Monitoring mode:** a daily feed of new and changed jobs (`changeType`), optionally with **removed jobs** (`removedAt`, `daysOnline`).
- 🏢 **Company data from ARES** (optional, extra charge): IČO, legal form, registered office, employee count range, main activity (CZ-NACE), founding date.
- 🔒 **Privacy first.** The contact person and phone number of a job page are never read. E-mails, phone numbers and named contact persons inside descriptions are replaced with `[e-mail removed]`, `[phone removed]` and `[name removed]`. Employers that are private persons are never named.
- ⚡ **Fast and light:** one request gives 100 jobs. No browser, no proxy needed. Optional **fast mode** with automatic slow-down.

### What data can you get?

| Field | Example |
|---|---|
| Title, employer, logo | Řidič nákladního auta, INOS Zličín, a.s. |
| Location, region, district, distance | Praha, Hlavní město Praha, Praha; `distanceKm` 11 with a radius |
| Salary | 40 000 – 45 000 CZK per month (monthly 40 000 – 45 000, hourly 250 – 281.25), "40 000 – 45 000 Kč" |
| Employment type | fullTime, partTime, trainee, temporary (brigáda) |
| Labour Office vacancy, section | `isLabourOfficeJob` false; `section` jobs or sideJobs |
| Suitable for | graduates, foreigners, students, seniors, parentsOnLeave, disabled |
| Date, labels | postedAt 2026-11-06, isPromoted ("Nutně vás hledají"), matchedBy position / text |
| With **Add description and details** | description, contract types, minimum education, languages, driving licences, benefits, categories, professions, postal code, company profile ID, valid through |
| With **Add company data from ARES** | IČO, legal form, registered office, employees, CZ-NACE, founding date |
| With **Monitoring: include removed jobs** | changeType `removed` (removedAt, firstSeenAt, lastSeenAt, daysOnline) and `reappeared` |

See the **Output** tab for all fields. The dataset has views for **Overview**, **Salaries**, **Details**, **Companies**, **Ad source**, **Monitoring** and **Removed jobs**.

### How to scrape JenPráce.cz

1. Enter **Search queries** (e.g. `skladník`, `účetní`) and **Locations** (e.g. `Praha`, `Brno`, `Jihomoravský kraj`) with an optional **Distance from the town**, pick **Regions**, or paste JenPráce.cz URLs into **JenPráce.cz URLs**: set your search and filters on the website and copy the URL, e.g. `https://www.jenprace.cz/nabidky/brno`. With nothing entered, the actor reads the newest jobs in the whole country.
2. Optionally choose **Ad source**, **Website filters** and **Filters**, set **Max jobs**, and turn on **Add description and details** or **Add company data from ARES** if you need them.
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 jobs in a town every morning, without Labour Office duplicates

Save this input as a task, add a **Schedule** (e.g. daily at 7:00) and connect an **integration** (e-mail, Slack, Google Sheets, Make, Zapier or a webhook). Each run returns only jobs that are new or changed, plus the ones that disappeared.

```json
{
  "locations": ["Brno"],
  "adSource": "jenprace",
  "maxItems": 0,
  "onlyNewOrChanged": true,
  "includeRemovedJobs": true,
  "monitoringKey": "brno-daily"
}
```

#### Salary research for a profession

Read jobs with a salary and open the free `SUMMARY` record: median and quartiles of the monthly salary overall and by region. The **Salaries** view shows the individual jobs.

```json
{
  "searchQueries": ["skladník", "řidič VZV"],
  "locations": ["Praha", "Brno", "Ostrava"],
  "onlyWithSalary": true,
  "excludeTextMatches": true,
  "maxItems": 500
}
```

#### Side jobs (brigády) near a town, paid per hour

```json
{
  "jobTypes": ["temporary"],
  "locations": ["Ostrava"],
  "radiusKm": 20,
  "maxItems": 100
}
```

#### Jobs for foreigners with accommodation, with details

```json
{
  "suitableFor": ["foreigners"],
  "accommodation": ["provided"],
  "includeDetails": true,
  "maxItems": 100
}
```

#### Labour Office vacancies in a region

```json
{
  "adSource": "labourOffice",
  "regions": ["moravskoslezsky-kraj"],
  "maxItems": 200
}
```

#### Website filters (applied by JenPráce.cz)

| Input | What it does |
|---|---|
| **Employment type** | Full-time, part-time, trainee program, side job (brigáda). Side jobs are a separate section of the website; without a choice both are searched. |
| **Contract type** | Employment contract (HPP), self-employed (OSVČ), work agreement (DPP, DPČ), civil service. |
| **Salary from (CZK per month)** | The website knows 10 000 – 60 000 in steps; other amounts are checked by the actor on the salary shown. The website also matches jobs without a salary; these come without one. |
| **Minimum education**, **Language skills**, **Suitable for**, **Accommodation**, **Driving licence** | As in the website's search form. |
| **Workplace** | On site, hybrid, from home. With one value the results have `workArrangement`. |
| **Locations**, **Distance from the town** | Towns, Prague or regions, one search each (at most 20); a radius of 0–50 km around a town. |
| **Regions** | Without Locations and URLs, one website search per region. |

Side jobs (brigády) have only the **Language** filter on the website, so with the other website filters only the job board is searched (the status message says so). The website filters are also added to your **JenPráce.cz URLs**, unless the URL already sets the same filter. One run makes at most 300 searches (search queries × locations × sections).

#### Filters (applied by the actor, you don't pay for filtered-out jobs)

| Input | Example |
|---|---|
| **Ad source** | all ads, only JenPráce.cz's own ads, only Labour Office vacancies |
| **Posted in the last N days** | `3`: the date of the ad as the website shows it (employers can refresh an ad, which moves the date) |
| **Skip text-only matches** | keep jobs the website matched by position, not by a word in the text |
| **Only jobs with a salary** | skip jobs without a visible salary |
| **Title must contain**, **Title must not contain** | `junior`, not `brigáda` |
| **Company**, **Exclude companies** | `Kaufland`, not `Manpower` |
| **Regions** (with Locations or URLs) | the region of each job's place of work must be one of them |

#### Own ads and Labour Office vacancies

JenPráce.cz shows two kinds of vacancies: its own ads (paid by employers, typically refreshed every few days) and vacancies from the public database of the Czech Labour Office (Úřad práce ČR, MPSV), which the website adds after its own ads. In November 2026 that was about 6 800 own ads and 17 100 Labour Office vacancies. The actor marks the second kind with `isLabourOfficeJob: true` by the website's own numbering of these ads; in our check, all 10 sampled ones were in the Labour Office's open data. Labour Office vacancies on JenPráce.cz have no end date (`validThrough` is null) and often a job title from the official classification of occupations ("Pomocní kuchaři"). Side jobs (brigády) are always the website's own ads.

The website's **region search** lists only its own ads. With **Ad source: Only Labour Office vacancies** and **Regions**, the actor therefore reads the whole country and checks the region of each job, which takes longer (about 170 pages for all Labour Office vacancies).

#### Region and district

`region` (kraj) and `district` (okres) come from the place of work shown in the list, matched against the official list of Czech municipalities (ČSÚ code lists and RÚIAN links, embedded in the actor, no extra requests). The website writes places as "town", "part, town" ("Radotín, Praha") or "town, district" ("Němčice, Svitavy"). With **Add description and details**, the region comes from the job page when it gives one. "Celá ČR" (the whole country) has no region. In our samples 99 % of jobs got a region.

#### Monitoring mode explained

With **Monitoring: only new or changed jobs** each run compares jobs with the previous run that used the same **Monitoring: key**. A job is returned as `changeType: "new"` when it wasn't seen before, or `"updated"` when its title, company, salary, place or employment type changed (`changedFields` says which of title and salary). A refreshed date alone is not a change. Jobs not seen for 90 days are forgotten. Use one key per watched search, and keep the same search and filters for that key.

**Monitoring: include removed jobs** adds jobs from the previous run that the current run no longer finds, with their last known title, company, place, region, salary and URL, `changeType: "removed"`, `firstSeenAt`, `lastSeenAt`, `removedAt` and `daysOnline`. Each removed job is reported once; if it comes back later, it is returned once as `changeType: "reappeared"`. Removed jobs are checked **only when the run read the whole search**: if it stopped at **Max jobs**, **Max jobs per search** or **Max pages per search**, at your maximum cost per run, or some pages could not be read, nothing is marked as removed and the status message says why. With **Posted in the last N days**, jobs that simply got older are not reported as removed. **Removed rows are normal dataset rows and are charged like any other job.** If a run crashes after saving jobs, the next run does not return them again (except jobs saved in the last few seconds before the crash).

#### Market summary (SUMMARY)

Every successful run writes a free JSON record `SUMMARY` to the run's default key-value store (link in the **Output** tab). It covers all jobs the run found that match your search and filters, each job once; in monitoring mode also the unchanged jobs that were not saved again.

| Key | Content |
|---|---|
| `counts` | jobs matched and saved, Labour Office vacancies saved; in monitoring mode new, updated, unchanged, removed and reappeared; jobs with company data |
| `salary` | number and share of jobs with a salary; monthly CZK median and quartiles (`p25`, `median`, `p75`) overall, `byRegion` and, with details, `byCategory` (groups with at least 5 jobs) |
| `topCompanies` | top 20 employers by number of jobs |
| `employmentTypes`, `regions`, `workArrangement` | number and share of jobs per value |

The monthly figure of a job is the middle of its salary range; hourly salaries are converted at 160 hours per month. The summary contains no personal data: companies only, no contacts and 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**, the public register of economic subjects run by the **Ministry of Finance of the Czech Republic** (ares.gov.cz), and adds `companyIco`, `companyLegalForm`, `companyAddress` (registered office, not the workplace), `companyEmployeeRange`, `companyNace`, `companyFoundedAt` and where the data come from.

- **Off by default.** Without this option the actor never contacts ARES.
- **Exact name matching.** Data are returned only for an unambiguous match: the same name including the legal form (case, diacritics and punctuation don't matter) and exactly one active company. Brand names without a legal form get no data. An agency's job gets the agency's data.
- **No private persons.** Employers whose name looks like a person are never sent to ARES. When ARES says the employer is a natural person (a sole trader), nothing from ARES is returned and the job's company name is removed as well.
- ARES data are informative only. Each name is looked up once per run, one request at a time, always directly; results are kept for 30 days in a key-value store `jenprace-ares-cache` in your account.
- **Price:** you pay the **Company info** event only for saved jobs that got company data. Your maximum cost per run is respected.

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

#### Fast mode (optional, small extra charge)

**Fast mode** reads JenPráce.cz up to 4× faster: at most **120 requests per minute and 4 at a time** instead of 30 per minute and 2 at a time. The moment the website answers "too many requests", "service unavailable" or slows down, the run switches back to the normal speed for the rest of the run; it waits when the website sends `Retry-After` and never changes IP address to get around a limit. The **Fast mode** event costs **$0.01 per 1 000 jobs**, only for jobs saved while the fast speed was on. It matters mostly with **Add description and details** (one request per job).

### How much does it cost to scrape JenPráce.cz?

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

| What | Price |
|---|---|
| Job (every saved row, including removed jobs in monitoring mode) | **$1.44 per 1 000 jobs** ($1.44 Bronze, $1.29 Silver, $1.14 Gold and higher Apify plans) |
| **+ Company info** (only jobs that got company data from ARES) | **+$1.00 per 1 000 jobs** |
| **+ Fast mode** (only jobs saved while the optional fast mode was on) | **+$0.01 per 1 000 jobs** |
| **Monitoring: listing page checked** (only with **Monitoring: only new or changed jobs**) | **$0.10 per 1 000 listing pages** (one page = up to 100 jobs; a search of 1 page costs $0.0001 per run) |
| Description and details | no extra charge |
| Filtered-out jobs, unchanged jobs in monitoring mode, the `SUMMARY` record | free |

There is also a tiny start fee of $0.00005 per run.

Platform usage is included; JenPráce.cz works without a proxy. With the $5 of monthly free credit on Apify's free plan you can get about 3 400 jobs. The actor makes at most 2 requests at a time and 30 per minute, to keep the load on the website low. Typical runs (measured locally, November 2026):

| Scenario | Requests to JenPráce.cz | Typical time |
|---|---|---|
| 20 jobs from a search | 1 | a few seconds |
| 1 000 jobs from searches | ~10 | under 1 minute |
| 12 jobs with description and details | 14 | ~30 seconds |
| 100 jobs with description and details | ~102 | ~3–4 minutes |

### Input example

```json
{
  "searchQueries": ["skladník"],
  "locations": ["Praha"],
  "maxItems": 100,
  "adSource": "all",
  "includeDetails": false
}
```

### Output example

```json
{
  "id": "jenprace:tnhwb6",
  "source": "jenprace.cz",
  "url": "https://www.jenprace.cz/nabidka/tnhwb6/ridic-nakladniho-auta",
  "jobId": "tnhwb6",
  "section": "jobs",
  "title": "Řidič nákladního auta",
  "company": "INOS Zličín, a.s.",
  "companyId": "inos-zlicin-a-s",
  "companyLogoUrl": "https://www.jenprace.cz/thumb/data/company/logo/inos-zlicin-a-s--b7458.jpg-l-166-1x.jpg",
  "isLabourOfficeJob": false,
  "location": "Praha",
  "region": "Hlavní město Praha",
  "district": "Praha",
  "regions": ["Hlavní město Praha"],
  "postalCode": null,
  "distanceKm": null,
  "workArrangement": null,
  "remote": null,
  "salaryText": "40 000 – 45 000 Kč",
  "salaryMin": 40000,
  "salaryMax": 45000,
  "salaryCurrency": "CZK",
  "salaryPeriod": "month",
  "salaryMonthlyMin": 40000,
  "salaryMonthlyMax": 45000,
  "salaryHourlyMin": 250.0,
  "salaryHourlyMax": 281.25,
  "employmentType": ["fullTime"],
  "contractTypes": ["employee"],
  "education": "Odborné vyučení bez maturity",
  "languagesRequired": ["Český jazyk (Pokročilý B2)"],
  "drivingLicences": ["C"],
  "suitableFor": ["graduates"],
  "categories": ["Doprava, logistika a zásobování"],
  "professions": ["Řidič / Řidička"],
  "benefits": ["Dovolená navíc", "Finanční bonusy a prémie", "Příspěvek na sport"],
  "postedAt": "2026-11-06",
  "validThrough": "2026-11-29T11:45:38Z",
  "isPromoted": true,
  "matchedBy": null,
  "companyIco": null,
  "companyLegalForm": null,
  "companyAddress": null,
  "companyEmployeeRange": null,
  "companyNace": null,
  "companyFoundedAt": null,
  "companyInfoSource": null,
  "companyInfoMatch": null,
  "companyInfoRetrievedAt": null,
  "description": "O nás\nNaše společnost se zabývá výstavbou venkovních inženýrských sítí…",
  "detailScraped": true,
  "changeType": null,
  "firstSeenAt": null,
  "changedFields": null,
  "lastSeenAt": null,
  "removedAt": null,
  "daysOnline": null,
  "sourceUrl": "https://www.jenprace.cz/nabidky?locations%5B0%5D=267&subjects%5B0%5D=%C5%99idi%C4%8D",
  "scrapedAt": "2026-11-06T10:00:00Z"
}
```

### Limitations

- **Salary:** shown only when the employer publishes it: in our samples about 70 % of the website's own ads, almost all Labour Office vacancies and 87 % of side jobs. Hidden salaries are never returned, also when the page's structured data contain one.
- **Labour Office vacancies** are marked by the website's numbering of these ads. They have no end date and the website's region search doesn't include them (see *Own ads and Labour Office vacancies*). The same vacancies are also in the Labour Office's own public database.
- **Region searches** on the website list only JenPráce.cz's own ads; use towns with a radius, or **Ad source: Only Labour Office vacancies**, for Labour Office vacancies in a region.
- **workArrangement** is known only when the search used exactly one **Workplace** value; the list doesn't show it otherwise.
- **Dates:** `postedAt` is the date the website shows, which moves when an employer refreshes an ad.
- **Side jobs (brigády)** have only the Language filter on the website; with other website filters they are not searched.
- **Locations** must exist in the website's list of places; a misspelled town is reported with suggestions and, if nothing could be searched, stops the run with a clear message.
- **Employer names that look like a private person** (e.g. a self-employed agent) are returned as `null`, together with their logo, profile and postal code, and the name is masked in the description. For Labour Office vacancies, whose records name a sole trader by the person's name, any name with the shape of a personal name and no word of an organisation counts as a person too (also foreign names like "Izzet Yilmaz"). In our sample of 1 991 jobs (1 030 employer names) that hid 81 jobs (4 %, 68 names), all of them persons (Czech and Vietnamese sole traders, insurance agents); no company was hidden.
- **Descriptions** are written by employers. E-mails, phone numbers and contact persons introduced as such ("Kontakt: …", "KO: …") are removed; other names in free text are not. Descriptions can be protected by copyright; use them for analysis, not for republishing.
- If the website rejects a request, it is asked once more after 30 seconds from the same IP address and session (never from another IP). If it keeps rejecting requests, the run stops and says so. Jobs whose page couldn't be read are returned with the listing data (`detailScraped: false`).
- This is not a copy of the JenPráce.cz database: it returns the jobs matching your search and filters, up to **Max jobs**.

### 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).

### 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
- [Úřad práce Scraper](https://apify.com/tsutseisoftware/urad-prace-scraper): all Czech Labour Office vacancies (MPSV open data) with salary, profession, shifts and jobs for foreigners
- [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
- [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

### FAQ

#### Is it legal to scrape JenPráce.cz?

The actor reads only public job ads that anyone can see without logging in, at a polite speed (at most 30 requests per minute by default), and it never solves CAPTCHAs or other challenges. It is built privacy first: it doesn't collect contact persons, phone numbers or e-mails, and it hides employers that are private persons. You are responsible for how you use the data, in particular under the GDPR and copyright law (descriptions). This actor is not affiliated with or endorsed by JenPráce.cz or Coweo Technologies s.r.o. If in doubt, ask a lawyer.

#### Do I need a proxy?

No. JenPráce.cz works without a proxy. You can still set Apify Proxy or your own proxies in **Proxy configuration**.

#### Can I use it through the API, in Make, Zapier or n8n?

Yes. Every Apify actor has an API and integrations, see below. You can also schedule runs and get the results by e-mail, Slack, Google Sheets or webhook.

#### Why do I get fewer jobs than the website shows?

The website's numbers count different things (e.g. only its own ads, or only position matches). Check the status message: it lists filtered-out jobs, unread pages and searches without results.

### For AI agents and API users

- **Minimal input:** `{"searchQueries": ["skladník"], "locations": ["Praha"], "maxItems": 20}`.
- One row = one job = one charge. `includeDetails: true` adds 1 request per job, same price. `includeCompanyInfo: true` adds the **Company info** charge only for rows with `companyInfoSource: "ARES"`.
- 100 jobs per listing page. `maxItems` counts saved jobs, `maxItemsPerStartUrl` limits each search or URL.
- Enum values: `employmentType` ⊂ `fullTime`, `partTime`, `trainee`, `temporary`; `section` ∈ `jobs`, `sideJobs`; `salaryPeriod` ∈ `hour`, `day`, `week`, `month`, `year`; `matchedBy` ∈ `position`, `text`; `changeType` ∈ `new`, `updated`, `removed`, `reappeared`; `adSource` input ∈ `all`, `jenprace`, `labourOffice`; `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`.
- The output has the same field names as our Prace.cz and Jobs.cz scrapers where they overlap, so the data can go into one table.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<username>/jenprace-scraper").call(run_input={
    "searchQueries": ["skladník"],
    "locations": ["Praha"],
    "maxItems": 100,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["region"], job["salaryMin"], job["isLabourOfficeJob"], job["url"])
```

#### JavaScript

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('<username>/jenprace-scraper').call({
    searchQueries: ['skladník'], locations: ['Praha'], maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((j) => `${j.title} (${j.company}, ${j.region})`));
```

### Troubleshooting

| Status message | What to do |
|---|---|
| `Location not found on JenPráce.cz` | Write the town as on the website (e.g. `Hradec Králové`, `Brno`); the log suggests similar places. |
| `Skipping unsupported URL` | Use a JenPráce.cz search URL (`https://www.jenprace.cz/nabidky/...`, `/brigady/...`) or a job URL (`/nabidka/<id>/...`). |
| `side jobs (brigády) were not searched` | Side jobs have only the Language filter; remove the other website filters to include them. |
| `This input makes N searches` | Use fewer locations or search queries (at most 300 searches per run). |
| `JenPráce.cz is rejecting requests` | Try again later. |
| `… listing pages could not be read, so the results may be incomplete` | The website didn't answer some pages; run it again later for complete results. |

Also known as a JenPráce.cz API, JenPráce jobs scraper or "nabídky práce JenPráce" export.

# Actor input Schema

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

Search or listing URLs from JenPráce.cz, e.g. https://www.jenprace.cz/nabidky/brno or https://www.jenprace.cz/brigady/cesko (set the search and filters on the website and paste the URL), or job URLs, e.g. https://www.jenprace.cz/nabidka/<id>/<title>. Website filters below are added to these URLs too, unless the URL already sets them.

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

Keywords to search for, e.g. 'skladník', 'účetní', 'python'. Each query is a separate search (combined with Locations and the website filters). The website first lists jobs matching the position and then jobs that only mention the word in their text (see "Skip text-only matches"). At most 20.

## `locations` (type: `array`):

Towns, Prague or regions, one search each, as on the website: 'Praha', 'Brno', 'Ostrava', 'Hradec Králové', 'Jihomoravský kraj', 'Celá ČR'. A town is looked up in the website's list of places (one small request). At most 20. Not used for JenPráce.cz URLs.

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

With a town in Locations: also jobs up to this distance (0, 10, 20, 30, 40 or 50 km, as on the website; other values are rounded down). Empty = the website's default for the town. Results then have distanceKm.

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

Only jobs in these regions (kraj). Without Locations and URLs, the actor runs one website search per region (the website's region search lists only its own ads, not Labour Office vacancies; with "Ad source: Labour Office vacancies only" the whole country is read and each job is checked by its region). With Locations or URLs, it checks the region of each job.

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

Maximum number of jobs saved. You pay per saved job. 0 = no limit.

## `maxItemsPerStartUrl` (type: `integer`):

Limit for each search or URL separately, so one large search doesn't use up the whole Max jobs. 0 = no limit.

## `includeDetails` (type: `boolean`):

Open each job page to add the description (e-mails, phone numbers and named contact persons removed), contract type, minimum education, languages, driving licence, benefits, categories, professions, postal code and the end of the ad. Slower: one extra request per job (2 seconds each). Same price per job.

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

With "Add description and details": shorten the description to about this many characters (e.g. 300 for a snippet). 0 = full text.

## `adSource` (type: `string`):

JenPráce.cz lists its own ads and, after them, vacancies of the Czech Labour Office (Úřad práce ČR). Keep both, only the website's own ads (in searches without a keyword the actor stops reading once only Labour Office vacancies follow, so it's also faster), or only Labour Office vacancies. Every job has isLabourOfficeJob.

## `jobTypes` (type: `array`):

Only these types. 'Side job (brigáda)' is the website's separate side jobs section; without a choice both the job board and side jobs are searched. Several values = any of them.

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

Only these contract types. Several values = any of them.

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

Only jobs offering at least this monthly salary, e.g. 40000. The website knows 10 000, 15 000, 20 000, 25 000, 30 000, 40 000, 50 000 and 60 000; other amounts are checked by the actor on the salary shown. The website also matches jobs that show no salary; such jobs are returned without a salary (combine with "Only jobs with a salary" to skip them).

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

Only jobs with this minimum education, as in the website's filter.

## `workArrangement` (type: `array`):

Only jobs on site, combined (hybrid) or from home. With exactly one value, the results have workArrangement set (the list doesn't show it otherwise).

## `languages` (type: `array`):

Only jobs that ask for one of these languages (or no language).

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

Only jobs the employer marked as suitable for these groups.

## `accommodation` (type: `array`):

Only jobs with accommodation provided or a housing allowance.

## `drivingLicence` (type: `string`):

Only jobs that ask for this driving licence.

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

Only jobs whose date on the website is within the last N days (employers can refresh an ad, which moves its date). Checked by the actor; searches without a keyword stop reading once only older jobs follow. 0 = any time.

## `excludeTextMatches` (type: `boolean`):

With Search queries: keep only the jobs the website matches by position (title, profession or company), not those that only mention the word in their text (matchedBy "text"). Saves pages too.

## `onlyWithSalary` (type: `boolean`):

Skip jobs that don't show a salary on the website.

## `titleKeywords` (type: `array`):

Keep only jobs whose title contains at least one of these words (case and diacritics don't matter).

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

Skip jobs whose title contains any of these words, e.g. 'brigáda', 'senior'.

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

Keep only jobs of companies whose name contains one of these texts, e.g. 'Kaufland', 'Globus'.

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

Skip jobs of companies whose name contains any of these texts, e.g. agencies.

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

Add data about the employer from ARES, the public register of economic subjects of the Czech Ministry of Finance: IČO (company ID), 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 "Company info" (see the Pricing tab) only for saved jobs whose company data were found and returned; jobs without a match cost nothing extra. Matching is by the exact company name including its legal form, so some jobs stay without company data. Private persons are never looked up or returned. About 1 second per new company name.

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

Return only jobs that are new or whose title, company, salary, place or employment type changed since the previous run with the same Monitoring key. Unchanged jobs are free; every listing page read in this mode is $0.0001 (the monitoring-page event).

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

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

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

With "Monitoring: only new or changed jobs": also return jobs from the previous run with the same Monitoring key that are no longer in the search, as rows with changeType "removed", removedAt, firstSeenAt, daysOnline and the last known title, company, place, salary and URL. Checked only when the run reads the whole search (Max jobs, Max jobs per search, Max pages per search, unread pages or rejected requests skip the check, and the status message says why). Removed rows are normal dataset rows and are charged like any other job.

## `fastMode` (type: `boolean`):

Reads JenPráce.cz up to 4x faster: at most 120 requests per minute and 4 at a time instead of 30 per minute and 2 at a time. It stays polite: the moment the website answers "too many requests", "service unavailable" or slows down, the run switches back to the normal speed for the rest of the run, it waits when the website asks it to wait, and it never changes IP address to get around a limit. Extra charge "Fast mode" (see the Pricing tab, $0.01 per 1 000 jobs) only for jobs saved while the fast speed was on. Please don't run several fast-mode runs at the same time.

## `maxPages` (type: `integer`):

Safety limit for each search or URL (100 jobs per page). The whole country has about 240 pages. 0 = no limit.

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

Not needed: JenPráce.cz works without a proxy. You can use Apify Proxy or your own proxies if you prefer.

## Actor input object example

```json
{
  "searchQueries": [
    "skladník"
  ],
  "locations": [
    "Praha"
  ],
  "maxItems": 20,
  "maxItemsPerStartUrl": 0,
  "includeDetails": false,
  "descriptionMaxLength": 0,
  "adSource": "all",
  "excludeTextMatches": false,
  "onlyWithSalary": false,
  "includeCompanyInfo": false,
  "onlyNewOrChanged": false,
  "includeRemovedJobs": false,
  "fastMode": false,
  "maxPages": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `jobs` (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 = {
    "searchQueries": [
        "skladník"
    ],
    "locations": [
        "Praha"
    ],
    "maxItems": 20,
    "includeCompanyInfo": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("tsutseisoftware/jenprace-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["skladník"],
    "locations": ["Praha"],
    "maxItems": 20,
    "includeCompanyInfo": False,
}

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

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "skladník"
  ],
  "locations": [
    "Praha"
  ],
  "maxItems": 20,
  "includeCompanyInfo": false
}' |
apify call tsutseisoftware/jenprace-scraper --silent --output-dataset

```

## MCP server setup

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