work.swiss Scraper: Export Swiss Jobs to CSV
Need job listings from the official Swiss Job-Room (work.swiss, also known as arbeit.swiss) in Excel or in your own analysis? The Arbeit.Swiss Scraper collects the jobs for your keywords and cantons and returns them as a table: title, employer, place, canton, workload percentage, date and a link to the listing. No code, a few minutes.
In this tutorial
What you get
The Job-Room, run by SECO (the Swiss State Secretariat for Economic Affairs), has no export function for jobs. Employers and the regional employment centres (RAV) post vacancies there, including some that may not appear on private job boards. The same data is served under four addresses: work.swiss (English), arbeit.swiss (German), travail.swiss (French) and lavoro.swiss (Italian). The Actor collects it in one run and stores it as a table you can download as CSV, Excel or JSON.
The Actor reads only publicly visible listings. You do not need a Job-Room account or an API key.
Two Swiss terms appear in the data. A canton (Kanton) is one of the 26 Swiss states, given as a two-letter code such as BE for Bern or ZH for Zürich. Workload (Pensum) is the job's share of a full-time position, in percent.
All fields at a glance
This is the field list from the Actor's output schema. Without includeJobDetails, the full listing text is missing and you only get the short snippet.
| Field | Type | Content |
|---|---|---|
id | Text | Unique Job-Room ID of the job (UUID) |
title | Text | Job title |
company | Text | Employer; for recruitment agencies, the agency name |
location / city / postal_code | Text | Place of work as “place, canton”, plus place and postal code of the workplace (not the company's head office) |
canton / country | Text | Canton code (for example BE) and country (CH) |
job_status | Text | online, offline, expired or unknown |
employment_type | Text | Employment type, in the example full-time or part-time |
workload_min / workload_max | Number | Workload percentage |
contract_type | Text | permanent or temporary |
start_date / starts_immediately / end_date | Date / Boolean | Start date, “start immediately” flag, and end date for fixed-term jobs |
work_forms | List | Special working patterns such as shift, night or Sunday work |
description_snippet | Text | Short excerpt of the description |
description_full / description_md | Text | Full listing text as plain text and as Markdown (with details) |
posted_at / expires_at | Date | Publication and expiry of the listing (day precision) |
source_url / source_platform | Text | Link to the job on job-room.ch and the platform (arbeit.swiss) |
apply_url / apply_email | Text | Application link and, if given, application email |
company_url | Text | Employer website or profile, if available |
contact_salutation, contact_firstname, contact_lastname, contact_email, contact_phone | Text | Contact person, if the listing names one |
salary_min / salary_max / salary_currency / salary_period | Number / Text | Salary where given. The Job-Room usually does not publish salaries |
remote_option / requirements | Text / List | In the schema, but not kept as structured data by the Job-Room. Empty in the example run |
search_query / scraped_at | Text | The keyword that found the job, and the time of collection |
Example: logistics in the canton of Bern
We ran the Actor once locally (21 Oct 2026): keyword “Logistik” (German for logistics, since most listings are in German), canton of Bern, newest first, at most 30 jobs, with full listing text. This was the input:
{
"searchQueries": ["Logistik"],
"cantonCodes": ["BE"],
"sortBy": "newest",
"maxResults": 30,
"includeJobDetails": true
}The run returned 30 jobs and finished after a few seconds (measured locally; times on Apify can differ). The Job-Room reported 345 matches for this search in the last 60 days. The run therefore stopped at our maxResults limit, not because there were no more jobs. Three results, shortened and without contact persons:
[
{
"id": "409c48a9-7faa-48d1-b61c-7cb66591158c",
"title": "Betriebsangestellte:r",
"company": "Jungfraubahnen Management AG",
"location": "Eigergletscher, BE",
"postal_code": "3823",
"canton": "BE",
"job_status": "online",
"employment_type": "full-time",
"workload_min": 100,
"workload_max": 100,
"contract_type": "permanent",
"starts_immediately": false,
"posted_at": "2026-10-21T00:00:00.000Z",
"expires_at": "2026-11-20T00:00:00.000Z",
"source_url": "https://www.job-room.ch/job-search/409c48a9-7faa-48d1-b61c-7cb66591158c",
"source_platform": "arbeit.swiss",
"search_query": "Logistik"
},
{
"id": "38dcda54-688f-4336-aaf9-3f78ed9731c9",
"title": "Teamleitung SAP Services / Business Analyst Order-to-Cash (OTC) 80-100% (m/w/d)",
"company": "Sanitas Troesch AG",
"location": "Bern, BE",
"postal_code": "3018",
"canton": "BE",
"employment_type": "full-time",
"workload_min": 100,
"contract_type": "permanent",
"posted_at": "2026-10-21T00:00:00.000Z",
"search_query": "Logistik"
},
{
"id": "7d3a3ce7-2a00-4f90-ac8d-17445bf115d9",
"title": "Fachspezialist/-in Administration",
"company": "Institut für Virologie und Immunologie IVI",
"location": "Mittelhäusern, BE",
"canton": "BE",
"employment_type": "full-time",
"workload_min": 100,
"contract_type": "permanent",
"posted_at": "2026-10-21T00:00:00.000Z",
"search_query": "Logistik"
}
]How many of the 30 jobs had each field filled:
- Always (30 of 30): title, employer, place, postal code, canton, workload, contract type, publication and expiry date, link, listing text (plain and Markdown).
- Application link: 29 of 30. It usually leads to the listing on another job board, for example jobs.ch or jobscout24.ch.
- Application email and contact person: 1 of 30.
- Never filled: salary, company website, start date, remote information, requirements.
titleFilter option (see below). Job titles are mostly in German, French or Italian, so search in the language of the canton.posted_at holds only the date; the time is always 00:00. All jobs in the selection above were posted on 20 or 21 October.Create an Apify account
- Open the Arbeit.Swiss Scraper page on Apify.
- Click Try for free and sign up with Google or email.
- You land in the Apify Console on the Actor's Input tab. The monthly free credit of the Free plan is enough for small runs.
Enter keyword and canton
In searchQueries, enter one or more keywords. Each keyword runs as its own search, and duplicate jobs are removed across all keywords. In cantonCodes, enter the canton as a code, for example ["BE"] or ["ZH", "SG"]. Empty means all of Switzerland.
sortBy:newestsorts by date, newest first (default).oldestreverses the order. The Job-Room has no relevance sorting.maxResultsPerQuery: cap per keyword (default 100, 0 means unlimited).maxResults: cap across all keywords together (0 means unlimited).includeJobDetails:truealso fetches the full listing text (default).
maxResults to 10 to 30. You see quickly whether the matches fit your keyword, and you pay only a few cents.postedWithinDays to choose a shorter period.Run the Actor and check the result
Click Save and Run at the bottom. On the run page, the Log tab shows progress and the Dataset tab shows the results as a table. Several keywords and cantons in one run look like this (“Pflege” is nursing care, “Lagerist” warehouse worker, “Buchhaltung” bookkeeping):
{
"searchQueries": ["Pflege", "Lagerist", "Buchhaltung"],
"cantonCodes": ["ZH", "BE"],
"maxResultsPerQuery": 50,
"includeJobDetails": false
}Export the data
- In the run, open the Dataset tab.
- Click Export.
- Choose the format: CSV, Excel, JSON and more. With the field selection you export only the columns you need, for example
title,company,location,workload_min,posted_atandsource_url.
Prompt for Claude to copy
In Claude, add the Apify MCP server as a custom connector with this URL (see Apify's MCP documentation). The URL limits Claude to this one Actor:
https://mcp.apify.com?tools=santamaria-automations/arbeit-swiss-scraperThen paste this prompt and replace keyword and canton with your own. Claude tells you the cost first and waits for your OK before the run starts:
Use the Apify MCP server. Run the Actor santamaria-automations/arbeit-swiss-scraper with the keyword
"Logistik", canton BE, sortBy newest and at most 30 results.
Before you start the run, tell me what it will cost and wait for my OK.
When it is done, give me a table with title, employer, place, workload and date, newest first.We tested the Actor and the inputs, not the prompts over MCP; Claude may word the cost statement differently.
Available filters
The Actor filters the search by these settings:
- Keyword (
searchQueries) and canton (cantonCodes, several allowed). - Workload (
workloadMinandworkloadMax, in percent, default 10 to 100). - Age of the listing (
postedWithinDays): 1 means 24 hours, 7 means one week. The filter runs at the Job-Room, so you pay only for the matches. The older settingonlineSinceDaysdefaults to 60. - Title (
titleFilter): a comma-separated list of terms, for exampleLaborant, Chemiker, QC. Only jobs with one of these terms in the title are kept. The filter applies before the details are fetched, so filtered-out jobs cost nothing. - Sorting (
sortBy): newest or oldest first. - Volume:
maxResultsPerQueryandmaxResults.
There is no filter for industry, salary or contract type. You do that afterwards in the table, for example with contract_type and employment_type.
Fetch by API and on a schedule
You can also call the Actor from your own scripts, n8n or Make. This call starts a run and returns the results directly (Apify endpoint run-sync-get-dataset-items):
curl -X POST "https://api.apify.com/v2/acts/santamaria-automations~arbeit-swiss-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchQueries": ["Logistik"], "cantonCodes": ["BE"], "sortBy": "newest", "maxResults": 50}'You find your API token in the Apify Console under Settings → API & Integrations. For recurring exports, create a schedule in the Console under Schedules. Set postedWithinDays to 1 for daily runs and compare the results with your last export (field id) so you only process new jobs.
What it costs
The Actor charges per result (prices from the Apify Store, Free plan, as of 21 Oct 2026):
- Start: $0.00005 per run.
- Job in the result: $0.003 per job.
Each job is charged once, when it is saved to the result. The full listing text (includeJobDetails) costs nothing extra. Worked example: 30 jobs = $0.00005 + 30 x $0.003 = $0.09005, about $0.09. All 345 matches of the example (logistics, canton of Bern, 60 days) would cost about $1.04. You can always find the current prices on the Actor's Apify page.
What people use the data for
Track the Swiss labour market by canton
Run the newest jobs for an occupation and a canton on a schedule and count how many appear per week, or which employers advertise most. The data comes from the official SECO platform.
Source roles for candidates and relocation clients
Recruiters and relocation firms can filter by canton and workload and open the original listing through source_url. Use expires_at and job_status to drop expired listings from your list.
Find employers that are hiring
The company column shows who is hiring in your region. Note that recruitment agencies can appear there too.
Analyse workload and fixed-term jobs
With workload_min, workload_max and contract_type you can see how many jobs are part-time or temporary.
Frequently asked questions
Do I need to code to scrape work.swiss?
No. In the Apify Console you fill in a form, click Save and Run and download the table. You only need code if you want to call the Actor from your own system through the API.
Is work.swiss the same as arbeit.swiss and the SECO Job-Room?
Yes. work.swiss (English), arbeit.swiss (German), travail.swiss (French) and lavoro.swiss (Italian) are the four language versions of the Job-Room run by SECO, the Swiss State Secretariat for Economic Affairs (job-room.ch). The Actor reads the shared data, so you get the same jobs whichever language the site uses.
Does the data include salaries?
Usually not. The fields salary_min, salary_max, salary_currency and salary_period exist in the schema, but the Job-Room does not publish salaries. In the example run, none of the 30 jobs had a salary.
How many jobs do I get per search?
By default at most 100 per keyword (maxResultsPerQuery). Set both maxResultsPerQuery and maxResults to 0 to get every match; the Actor then fetches 100 jobs per page until the list ends. For scale: in the example, the Job-Room reported 345 matches for logistics in the canton of Bern.
How do I get only new jobs?
Set postedWithinDays to 1 for the last 24 hours or 7 for the last week. The filter runs on the Job-Room side. Without it, the default is 60 days. For recurring runs, also compare the id field with your previous export.
How much does the work.swiss scraper cost?
$0.003 per job plus $0.00005 per run start. The detail page is included. 30 jobs with full text cost about $0.09.
Am I allowed to use this data?
That depends on your use case, especially for personal contact details. Some listings name a contact person with email or phone. Check data protection rules (the Swiss FADP, and the GDPR if EU residents are involved) before you store or reuse such data.
Related links
- Arbeit.Swiss Scraper, Actor page: input fields, output fields and pricing at a glance.
- Arbeit.Swiss Scraper on Apify: the Actor with documentation and all parameters.
- How to Scrape Every Job Online: job listings from 110+ job boards with one call.