# GastroJobs.cz Scraper ($1.75/1K): Czech Hospitality Jobs (`tsutseisoftware/gastrojobs-scraper`) Actor

Scrape GastroJobs.cz, the Czech job board for hotels, restaurants and catering: jobs with salary, employer, type of venue, place and company ID. Track new and removed jobs. Unofficial.

- **URL**: https://apify.com/tsutseisoftware/gastrojobs-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.59 / 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

## GastroJobs.cz Scraper: Czech Hotel, Restaurant & Hospitality Jobs

Get job listings from **GastroJobs.cz**, the Czech job board for **hotels, restaurants, bars, cafés, catering and spas** (about 430 open jobs, most of them in Prague), as clean structured data. For each job you get the title, the employer and its **type of venue** (hotel, restaurant, bar, bistro, café, resort, catering…), the place of work with its **region (kraj) and district (okres)**, the **salary as numbers** (employers type it as free text; the actor turns "40 - 50.000 Kč", "220–240 Kč/hod. hrubého" or "3100kč čistého za směnu + tipy" into a range, a period, net or gross and monthly and hourly equivalents), employment types, the date of the ad and its labels. Optionally the actor opens each job page and adds the **description** (with e-mails and phone numbers removed), the **address of the venue**, the employer's website, the **legal entity behind the venue with its company ID (IČO)**, required languages, software skills and the start date.

Filter by **keywords**, **place or region**, **employment type**, **type of employer** and **salary**. The filters are applied on the list of jobs, before any job page is opened, so you never pay for a job you filtered out (only a small fee for listing pages read beyond the saved jobs, see Pricing).

Built for **watching the hospitality 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 and type of employer, top employers, employment types).

> **Česky:** Scraper nabídek práce z **GastroJobs.cz** (hotely, restaurace, gastronomie, lázně): mzda převedená na čísla, zaměstnavatel a typ provozu, kraj a okres, typ úvazku, volitelně popis, adresa provozu a IČO provozovatele. Filtry podle pozice, místa, úvazku, typu provozu a mzdy, monitoring nových a odstraněných nabídek. Výstup do Excelu, CSV nebo JSON. Podporu poskytujeme i česky.

### Why use this GastroJobs.cz scraper?

- 🍽️ **The whole niche in one run.** GastroJobs.cz is where Czech hotels and restaurants hire cooks, waiters, receptionists, bartenders and housekeeping. The whole website is 15 requests; 20 jobs take a few seconds.
- 🏨 **Type of venue for every job** (`employerType`): Hotel, Restaurace, Bar, Bistro, Kavárna, Resort, Party-/Eventcatering, Lázně and others, known for 98 % of jobs. Filter by it to get only hotels or only restaurants.
- 💰 **Salaries you can compute with.** Employers type the salary into a free-text box. The actor returns `salaryMin`, `salaryMax`, currency, period (hour, day or shift, week, month, year), `salaryBasis` (net or gross, when the text says so) and monthly and hourly equivalents, plus the text as shown. Tips, bonuses and allowances after "+" are not counted as salary; amounts that make no sense for their period are kept but not converted.
- 🧾 **The company behind the venue** (with details): hotels and restaurants advertise under their brand ("Buddha bar"); the job page also names the legal entity that runs it ("Cherres a.s.") and its **company ID (IČO)**, which you can join with company registers. Found for about 90 % of jobs.
- 🗺️ **Region and district for almost every job**, worked out from the place of work as the employer typed it ("Praha 1", "BRNO", "Špindlerův Mlýn") with the official list of Czech municipalities, without extra requests.
- 📬 **Monitoring mode:** a daily feed of new and changed jobs (`changeType`), optionally with **removed jobs** (`removedAt`, `daysOnline`).
- 🔒 **Privacy first.** The contact person and phone number of a job page are never read. E-mails and phone numbers inside descriptions are replaced with `[e-mail removed]` and `[phone removed]`. Employers that are private persons are never named.
- ⚡ **Fast and light:** one request gives 30 jobs. No browser, no proxy needed. Optional **fast mode** with automatic slow-down.

### What data can you get?

| Field | Example |
|---|---|
| Title, employer, logo | Číšník/Servírka do restaurace na Václavském nám., Hotel Prague Inn \*\*\*\* |
| Type of employer | Hotel, Restaurace, Bar, Bistro, Kavárna, Resort, Party-/Eventcatering, Lázně… |
| Location, region, district | Praha 1, Hlavní město Praha, Praha |
| Salary | "1500kč/den" → 1 500 CZK per day (monthly 30 000, hourly 187.5); "220–240 Kč/hod. hrubého" → 220 – 240 per hour, gross |
| Employment type | fullTime, partTime, temporary (brigáda), seasonal, eventHelp, freelance, internship, trainee |
| Date, labels | postedAt 2026-11-10, isPromoted (TOP), suitableFor graduates |
| With **Add description and details** | description, street, postal code, city, country, employer website, legal entity and its IČO, required languages, software skills, start date |
| With **Monitoring: include removed jobs** | changeType `removed` (removedAt, firstSeenAt, lastSeenAt, daysOnline) and `reappeared` |

Open the results as a table in Apify Console (views **Overview**, **Salaries**, **Details**, **Employers**, **Monitoring**, **Removed jobs**) or export them to **Excel, CSV, JSON or XML**.

### How to scrape GastroJobs.cz

1. Open the actor and leave the input empty to get the newest jobs, or fill in **Search queries** (e.g. `kuchař`), **Locations**, **Regions** or the filters.
2. Set **Max jobs** (you pay per saved job) and turn on **Add description and details** if you need descriptions, addresses and company IDs; **Description format** gives the description as plain text, HTML or Markdown.
3. Click **Start**. When the run finishes, open the **Output** tab or download the dataset.

### Use cases

#### New cook jobs in Prague every morning

```json
{
  "searchQueries": ["kuchař", "kuchařka"],
  "regions": ["praha"],
  "onlyNewOrChanged": true,
  "includeDetails": true,
  "maxItems": 0
}
```

Schedule it daily. The first run returns all matching jobs, the next ones only new and changed jobs.

#### Salary research for waiters and bartenders

```json
{
  "searchQueries": ["číšník", "servírka", "barman"],
  "onlyWithSalary": true,
  "maxItems": 0
}
```

Use the **Salaries** view, or the `SUMMARY` record with the median and quartiles.

#### Hotels that are hiring, with the company behind each of them

```json
{
  "employerTypes": ["Hotel", "Resort"],
  "includeDetails": true,
  "descriptionMaxLength": 300,
  "maxItems": 100
}
```

The **Employers** view shows the venue, the legal entity, its IČO, website and address: a list of hospitality businesses with open positions (for suppliers, staffing agencies or HR software).

#### Side jobs and seasonal work outside Prague

```json
{
  "employmentTypes": ["temporary", "seasonal", "eventHelp"],
  "regions": ["kralovehradecky-kraj", "liberecky-kraj", "jihocesky-kraj"],
  "maxItems": 0
}
```

#### Which jobs were filled or withdrawn this week

```json
{
  "onlyNewOrChanged": true,
  "includeRemovedJobs": true,
  "monitoringKey": "all-jobs",
  "maxItems": 0
}
```

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

GastroJobs.cz keeps its own filters in a server session, not in the address, so a filtered search can't be passed as a URL. The actor reads the list of jobs (15 pages for the whole website) and applies your filters to what the list shows, before any job page is opened:

| Input | Keeps |
|---|---|
| **Search queries** | jobs whose title, employer name or type of employer contains one of the words (`kuchař` also finds "Kuchař/ka"; case and diacritics don't matter) |
| **Locations**, **Regions** | jobs by the place of work, its district or region |
| **Employment type** | jobs with at least one of the chosen types |
| **Type of employer** | hotels, restaurants, bars, cafés, catering, spas… |
| **Only jobs with a salary**, **Salary from** | jobs that show an amount / at least this monthly amount (hourly and daily amounts converted; jobs without an amount pass **Salary from** unless you also turn on **Only jobs with a salary**) |
| **Only jobs suitable for graduates** | jobs with the website's graduate label |
| **Posted in the last N days** | jobs by the date in the list; the actor stops reading once only older jobs follow |
| **Title must (not) contain**, **Employer**, **Exclude employers** | jobs by words in the title or the employer name |

The website's profession and experience filters are not in the list of jobs; use **Search queries** for professions.

#### 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). Employers type the place freely ("Praha 1", "Praha1", "BRNO", "Praha 3 - Vinohrady"). On 10 November 2026, 98 % of the 428 jobs got a region; places abroad and ambiguous village names have none.

#### Salary

`salaryText` is always what the employer typed, also when it has no amount ("Dohodou", "Plat řešíme individuálně"). When the text has an amount, the actor fills `salaryMin` and `salaryMax` (one amount is both; "od 35 000" has only the lower one, "až 58 000" only the upper one), `salaryCurrency`, `salaryPeriod` and `salaryBasis`:

- thousands written as "38.000", "34,000", "40 000" or shortened ("40 - 50.000", "85 - 95 tis") are understood,
- the period is the unit in the text (hod, hodina, směna, den, týdně, měsíc); without a unit it is a month, or an hour when the amounts are between 80 and 999 CZK,
- amounts after "+", "plus", bonuses, tips or allowances are not part of the salary,
- "čistého" gives `salaryBasis: "net"`, "hrubého" `"gross"`; most ads don't say,
- monthly and hourly equivalents use 160 hours and 20 days (shifts) a month; a shift is counted as a day.

On 10 November 2026, 57 % of jobs had a salary text and 43 % an amount.

#### 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, employer, 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 set of filters, and keep the same filters for that key.

**Monitoring: include removed jobs** adds jobs from the previous run that are no longer in the list, with their last known title, employer, 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 list**: if it stopped at **Max jobs** or **Max pages**, 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 filters, each job once; in monitoring mode also the unchanged jobs that were not saved again.

| Key | Content |
|---|---|
| `counts` | jobs listed, matched and saved; in monitoring mode new, updated, unchanged, removed and reappeared |
| `salary` | number and share of jobs with a salary; monthly CZK median and quartiles (`p25`, `median`, `p75`) overall, `byRegion` and `byCategory` (= type of employer; groups with at least 5 jobs) |
| `topCompanies` | top 20 employers by number of jobs |
| `employmentTypes`, `regions` | 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. Net and gross amounts are not told apart in the summary. The summary contains no personal data: employers only, no contacts and no descriptions.

#### Words in the description

**Title or description must contain** keeps only jobs with at least one of your words in the title or in the description, e.g. `sushi`, `ubytování`, `angličtina`. The description is only on the job page, so the option turns on **Add description and details** for the run by itself (the log says so; the price per job is the same). The other filters are checked on the list first; job pages read for jobs without the words are not saved and count as extra pages ($0.0002 each).

#### Notifications (job alerts)

Fill in at least one channel and after each run the actor sends the saved jobs there: title, employer, place, salary and link, at most **Notifications: max jobs per message** (10 by default), then "…and N more", with links to the run and the dataset. With **Monitoring: only new or changed jobs** that is a ready job alert: schedule the run and only new, changed and removed jobs arrive; a run that saved nothing sends nothing. Descriptions and contacts are never sent, and the webhook addresses are stored encrypted and never logged.

| Input | What to paste |
|---|---|
| **Notifications: Slack webhook URL** | an incoming webhook of your channel (`https://hooks.slack.com/services/…`) |
| **Notifications: Discord webhook URL** | a channel webhook (`https://discord.com/api/webhooks/…`) |
| **Notifications: Telegram bot token** + **Telegram chat ID** | the token from @BotFather and the chat, group or channel ID |
| **Notifications: webhook URL** | any HTTPS URL (Zapier, Make, n8n, your server): a POST with JSON `{title, summary, totalSaved, runUrl, datasetUrl, items}` |

A delivered notification costs **$0.001 per run** (not per channel). Nothing is charged when no channel is filled in, when the run saved nothing or failed, or when no channel accepted the message; a channel that fails never fails the run.

#### Compact output

**Compact output** keeps only the core fields of every row (id, title, employer, type of employer, place, region, salary, employment type, posting date, link and the monitoring fields); **Leave out empty fields** drops fields that are null or empty. Both make rows smaller for AI agents, MCP clients and dashboards; the price per job is the same. Off by default.

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

**Fast mode** reads GastroJobs.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 only with **Add description and details** (one request per job).

### How much does it cost to scrape GastroJobs.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.75 per 1 000 jobs** ($1.69 Bronze, $1.65 Silver, $1.59 Gold and higher Apify plans) |
| Description and details | no extra charge |
| **+ 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.20 per 1 000 listing pages** (one page = 30 jobs; the whole website is about 15 pages = $0.003 per run) |
| **Extra page** (outside monitoring: a page read beyond what the saved jobs explain) | **$0.20 per 1 000 pages** ($0.0002 per page, at most about $0.003 per run) |
| Run start | **$0.005 per run** |
| **Notification** (only with a notification channel filled in) | **$0.001 per run** whose notification was delivered |
| Filtered-out jobs, unchanged jobs in monitoring mode, the `SUMMARY` record | free |

**Why the extra page:** GastroJobs.cz cannot filter its list by URL, so the actor reads the list and filters it itself. The saved jobs explain one listing page per 30 jobs and one job page per job (with **Add description and details**, or for job URLs you gave). Pages read beyond that are extra pages: a narrow filter that reads all 15 listing pages to find 2 jobs pays 2 jobs + 14 extra pages ($0.0028), and a job URL that no longer exists pays 1 extra page. Runs without filters have no extra pages. Second attempts and pages the website rejected are never charged. Your maximum cost per run covers these fees too: the run stops reading the list before it would exceed it.

| Example run | You pay |
|---|---|
| 20 jobs with descriptions, no filter | $0.005 + 20 jobs = **$0.04** |
| 20 jobs for a keyword found on the first 3 listing pages | $0.005 + 20 jobs + 2 extra pages = **$0.0404** |
| A narrow filter that finds 1 job on the whole website (15 pages) | $0.005 + 1 job + 14 extra pages = **$0.0096** |
| A filter that finds nothing (15 pages) | $0.005 + 15 extra pages = **$0.008** |
| Daily monitoring run without changes (15 pages) | $0.005 + 15 monitoring pages = **$0.008** |
| A job URL that no longer exists | $0.005 + 1 extra page = **$0.0052** |
| The website rejects the run or does not answer | **$0.005** (start only) |

Platform usage is included; GastroJobs.cz works without a proxy. All jobs on the website (about 430) with descriptions and details cost about $0.75; with the $5 of monthly free credit on Apify's free plan you can get about 2 800 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 GastroJobs.cz | Typical time |
|---|---|---|
| 20 jobs for a keyword | 3 | a few seconds |
| All 428 jobs | 15 | ~30 seconds |
| 12 jobs with description and details | 14 | ~30 seconds |
| 40 jobs with description and details | 42 | ~1.5 minutes |

### Input example

```json
{
  "searchQueries": ["kuchař"],
  "maxItems": 20,
  "includeDetails": false
}
```

### Output example

With **Add description and details**:

```json
{
  "id": "gastrojobs:12524-11783",
  "source": "gastrojobs.cz",
  "url": "https://www.gastrojobs.cz/cs/inzerat/12524-11783-cisnik-servirka-do-restaurace-na-vaclavskem-nam/",
  "jobId": "12524-11783",
  "title": "Číšník/Servírka do restaurace na Václavském nám.",
  "company": "Hotel Prague Inn ****",
  "companyLegalName": "Prague Inn s.r.o.",
  "companyIco": "27092577",
  "companyWebsite": "http://www.hotelpragueinn.cz",
  "companyLogoUrl": "https://www.gastrojobs.cz/images/place-logos/15532-210504184936-logo-retina.png",
  "employerType": "Hotel",
  "location": "Praha 1",
  "region": "Hlavní město Praha",
  "district": "Praha",
  "regions": ["Hlavní město Praha"],
  "street": "28.října 378/15",
  "postalCode": "110 00",
  "city": "Praha 1",
  "country": "Česká republika",
  "salaryText": "1500kč/den",
  "salaryMin": 1500,
  "salaryMax": 1500,
  "salaryCurrency": "CZK",
  "salaryPeriod": "day",
  "salaryBasis": null,
  "salaryMonthlyMin": 30000,
  "salaryMonthlyMax": 30000,
  "salaryHourlyMin": 187.5,
  "salaryHourlyMax": 187.5,
  "employmentType": ["temporary", "partTime", "fullTime"],
  "languagesRequired": ["Čeština"],
  "softwareSkills": [],
  "suitableFor": ["graduates"],
  "startDate": "Ihned",
  "postedAt": "2026-11-10",
  "isPromoted": false,
  "description": "Restaurace na Václavském náměstí příjme číšníka/servírku na HPP. Nástup možný ihned.\nPracovní doba, krátký/dlouhý týden.\n…\nPro bližší info volejte na tel.číslo:\n[phone removed]\n\nNáplň práce:\nObsluha zákazníků. Přijímání a zanášení objednávek. …\n\nPožadujeme:\nSpolehlivost, dochvilnost, příjemné vystupování, …\n\nNabízíme:\nStabilní zaměstnání, přátelský kolektiv, personální stravování. …",
  "detailScraped": true,
  "changeType": null,
  "firstSeenAt": null,
  "changedFields": null,
  "lastSeenAt": null,
  "removedAt": null,
  "daysOnline": null,
  "sourceUrl": "https://www.gastrojobs.cz/cs/inzeraty/",
  "scrapedAt": "2026-11-10T18:04:38Z"
}
```

Without details, the fields from the job page (`description`, `street`, `postalCode`, `city`, `country`, `companyWebsite`, `companyLegalName`, `companyIco`, `languagesRequired`, `softwareSkills`, `startDate`) are `null` or empty and `detailScraped` is `false`.

### Limitations

- **A small, specialised job board:** about 430 jobs, roughly two thirds of them in Prague, 45 % in hotels and a third in restaurants (10 November 2026).
- **The website's own filters can't be used**, because it keeps them in a server session instead of the URL. The actor filters by what the list of jobs shows; professions ("obor") and required experience are not there.
- **Salary:** employers type it as free text. 57 % of jobs had a salary text and 43 % an amount (10 November 2026). The conversion to numbers follows the rules above; unusual texts can be read wrongly, so `salaryText` is always returned as well. Net and gross are known only when the text says so.
- **Dates:** `postedAt` is the date the website shows in the list, which moves when an ad is refreshed (all ads were at most 3 weeks "old"). A job read from its URL has no date and no TOP or graduate label, because the job page doesn't show them.
- **Details** (40 jobs, 10 November 2026): description and address 100 %, employer website 97 %, legal entity 92 %, valid IČO 90 %, start date 87 %, languages 62 %, software skills 17 %. The IČO is returned only when the page gives 8 digits; some employers type something else into that field.
- **Type of employer and languages** are returned in Czech, as the website shows them.
- **Employer names that look like a private person** are returned as `null`, together with the logo, website, street and postal code, and the name is masked in the title and description. A legal entity that is a person (a sole trader) is never named and its IČO is not returned. Venues are brands, so this is rare: on 10 November 2026 none of the 165 employer names was hidden.
- **Descriptions** are written by employers. E-mails and phone numbers are removed; names mentioned in free text ("ask for Jarda") 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`). A job that was removed between the list and its page is not returned.
- This is not a copy of the GastroJobs.cz database: it returns the jobs matching your 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
- [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

### FAQ

#### Is it legal to scrape GastroJobs.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 GastroJobs.cz or its operator. If in doubt, ask a lawyer.

#### Do I need a proxy?

No. GastroJobs.cz works without a proxy. You can still set Apify Proxy or your own proxies in **Proxy**.

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

#### Can I paste a filtered search from the website?

No. GastroJobs.cz doesn't put its filters into the address, so every link to the list shows all jobs. Use the actor's filters instead; they cost nothing for the jobs they skip.

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

Check the status message: it lists filtered-out jobs and unread pages. In monitoring mode only new and changed jobs are returned.

### For AI agents and API users

- **Minimal input:** `{"searchQueries": ["kuchař"], "maxItems": 20}`. An empty input returns the newest 100 jobs.
- One row = one job = one charge. `includeDetails: true` adds 1 request per job, same price. Per run also the start fee and, for pages read beyond the saved jobs, `monitoring-page` (monitoring mode, every listing page) or `extra-page` (otherwise).
- `descriptionKeywords` (words in the title or description; turns `includeDetails` on), `compact` and `excludeEmptyFields` (smaller rows), `slackWebhookUrl` / `discordWebhookUrl` / `telegramBotToken` + `telegramChatId` / `webhookUrl` (job alerts, $0.001 per delivered run).
- `descriptionFormat`: `text` (default), `markdown` (best for LLM pipelines) or `html`; contacts are removed in every format.
- 30 jobs per listing page, about 15 pages for the whole website. `maxItems` counts saved jobs (0 = all).
- Enum values: `employmentType` ⊂ `fullTime`, `partTime`, `temporary`, `seasonal`, `eventHelp`, `freelance`, `internship`, `trainee`; `salaryPeriod` ∈ `hour`, `day`, `week`, `month`, `year`; `salaryBasis` ∈ `net`, `gross`; `changeType` ∈ `new`, `updated`, `removed`, `reappeared`; `employerTypes` input ⊂ `Hotel`, `Resort`, `Ost. Ubytováni`, `Restaurace`, `Bar`, `Bistro`, `Kavárna`, `Diskotéka/Club`, `Party-/Eventcatering`, `Závodní nebo školní stravování`, `Průmyslový catering`, `Lázně`, `Dodavatele služeb`, `Dodavatele softwaru`; `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 other Czech job scrapers where they overlap (`title`, `company`, `location`, `region`, `salaryMin`, `salaryMax`, `salaryPeriod`, `employmentType`, `postedAt`, `description`…), so the data can go into one table.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<username>/gastrojobs-scraper").call(run_input={
    "searchQueries": ["kuchař"],
    "regions": ["praha"],
    "maxItems": 100,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["employerType"], job["salaryMin"], job["url"])
```

#### JavaScript

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('<username>/gastrojobs-scraper').call({
    searchQueries: ['kuchař'], 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 |
|---|---|
| `Skipping unsupported URL` / `No supported URL` | Use the list of jobs (`https://www.gastrojobs.cz/cs/inzeraty/`) or a job URL (`https://www.gastrojobs.cz/cs/inzerat/<numbers>-<name>/`). |
| `… URL could not be read` | The job has expired (the website answers with an error page) or the address is wrong; open it in your browser. |
| `The list of jobs on GastroJobs.cz could not be read` | The website answered with an error; try again later. |
| `GastroJobs.cz is rejecting requests` | Try again later. |
| `GastroJobs.cz is not answering or answers too slowly` / `the website answered too slowly, so the run stopped early` | The website (or the proxy you set) did not answer in time, so the run stopped instead of waiting; what it had read is saved. Try again later, and without your own proxy. |
| `… 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. |
| `removed jobs were not checked` | The run didn't read the whole list (the message says why); removed jobs are reported by the next complete run. |

Also known as a GastroJobs.cz API, GastroJobs jobs scraper, Czech hospitality jobs scraper or "nabídky práce v gastronomii a hotelnictví" export.

# Actor input Schema

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

Optional. Job URLs from GastroJobs.cz, e.g. https://www.gastrojobs.cz/cs/inzerat/16194-15372-customer-support-specialist-hpp/ (each is read with its details), or the list of jobs https://www.gastrojobs.cz/cs/inzeraty/. Empty = the whole list of jobs. The website keeps its own filters in a server session, not in the URL, so use the filters below instead.

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

Keep only jobs whose title, employer name or type of employer contains at least one of these words, e.g. 'kuchař', 'číšník', 'recepční', 'barman' (case and diacritics don't matter). Checked by the actor on the list of jobs, so skipped jobs are not charged (only listing pages read beyond the saved jobs, $0.0002 each). Empty = all jobs.

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

Keep only jobs whose place of work, district or region contains one of these texts, e.g. 'Praha', 'Brno', 'Špindlerův Mlýn', 'Jihomoravský'. Most jobs on GastroJobs.cz are in Prague.

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

Only jobs in these regions (kraj). The region comes from the place of work and the official list of Czech municipalities (known for about 97 % of jobs).

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

Maximum number of jobs saved. You pay per saved job. 0 = no limit (the whole website has about 430 jobs).

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

Open each job page to add the description (e-mails, phone numbers removed), the address of the workplace, the employer's website, the legal entity behind the venue with its company ID (IČO), required languages, software skills and the start date. Included in the price per job; one more request per job, so the run takes longer. The page's phone number and contact person are never read.

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

## `descriptionFormat` (type: `string`):

With "Add description and details": the description as plain text (default), clean HTML or Markdown. HTML and Markdown keep the ad's headings (Náplň práce, Požadujeme, Nabízíme), paragraphs, lists and bold text; e-mails and phone numbers are removed in every format.

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

Only jobs with at least one of these employment types (a job can have several).

## `employerTypes` (type: `array`):

Only jobs of these kinds of venues, as the website labels the employer (about 60 % hotels, 30 % restaurants).

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

Skip jobs that don't show a salary amount on the website (employers type the salary as free text; about a third of the ads give an amount).

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

Only jobs offering at least this monthly salary, e.g. 40000 (hourly and daily amounts are converted: 160 hours or 20 days a month). Jobs without an amount pass; add "Only jobs with a salary" to drop them.

## `onlyForGraduates` (type: `boolean`):

Keep only jobs the employer marked as suitable for graduates (the "A" label in the list).

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

Only jobs whose date on the website is within the last N days (the website moves the date when an ad is refreshed). The actor stops reading the list once only older jobs follow. 0 = any time.

## `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', 'pokojská'.

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

Keep only jobs of employers whose name contains one of these texts, e.g. 'Marriott', 'Ambiente'.

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

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

## `descriptionKeywords` (type: `array`):

Keep only jobs whose title or description contains at least one of these words, e.g. 'sushi', 'ubytování', 'angličtina' (case and diacritics don't matter). The description is only on the job page, so this turns on "Add description and details" for the run (same price per job). Job pages read for jobs without the words are not saved and count as extra pages ($0.0002 each); combine it with the other filters, which are checked on the list first.

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

Return only jobs that are new or whose title, employer, 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.0002 (the monitoring-page event; the whole website is about 15 pages = $0.003 per run).

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

Name of the saved state. Use a different key for each watched set of filters (e.g. 'kuchar-praha'). 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 list, as rows with changeType "removed", removedAt, firstSeenAt, daysOnline and the last known title, employer, place and salary; a job that comes back is "reappeared". Only after a run that read the whole list. Removed rows are charged like any other job.

## `compact` (type: `boolean`):

Keep only the core fields of every row: id, title, employer, type of employer, place, region, salary, employment type, posting date, link (and the monitoring fields).

## `excludeEmptyFields` (type: `boolean`):

Drop fields that are null or an empty list from every row (id, source, url, jobId, title and scrapedAt always stay).

## `slackWebhookUrl` (type: `string`):

Incoming webhook of your Slack channel (https://hooks.slack.com/services/...). Stored encrypted.

## `discordWebhookUrl` (type: `string`):

Webhook of your Discord channel (https://discord.com/api/webhooks/...). Stored encrypted.

## `telegramBotToken` (type: `string`):

Token of your Telegram bot (from @BotFather). Used with "Telegram chat ID". Stored encrypted.

## `telegramChatId` (type: `string`):

Chat, group or channel ID the bot writes to (e.g. -1001234567890).

## `webhookUrl` (type: `string`):

Any HTTPS URL (Zapier, Make, n8n, your server): gets a POST with JSON {title, summary, totalSaved, runUrl, datasetUrl, items}.

## `notificationLimit` (type: `integer`):

How many jobs are listed in one notification (the rest as "…and N more").

## `notifyOnlyChanges` (type: `boolean`):

Send nothing when the run saved no job (e.g. a monitoring run without new jobs).

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

Reads GastroJobs.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 goes back to the normal speed. Extra $0.01 per 1 000 jobs saved while the fast mode is on (the fast-mode event). Useful with "Add description and details"; the list alone is 15 requests.

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

Safety limit of listing pages read (30 jobs per page; the whole website has about 15 pages). 0 = no limit.

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

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

## Actor input object example

```json
{
  "searchQueries": [
    "kuchař"
  ],
  "maxItems": 20,
  "includeDetails": false,
  "descriptionMaxLength": 0,
  "descriptionFormat": "text",
  "onlyWithSalary": false,
  "onlyForGraduates": false,
  "onlyNewOrChanged": false,
  "includeRemovedJobs": false,
  "compact": false,
  "excludeEmptyFields": false,
  "notificationLimit": 10,
  "notifyOnlyChanges": true,
  "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": [
        "kuchař"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tsutseisoftware/gastrojobs-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": ["kuchař"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("tsutseisoftware/gastrojobs-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": [
    "kuchař"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call tsutseisoftware/gastrojobs-scraper --silent --output-dataset

```

## MCP server setup

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