
Global Sources Supplier Scraper
scrape.ly/store/cornerledger/globalsources-scraperLead generationE-commerce
2 monthly users

Export Swiss job listings from job-room.ch (arbeit.swiss / travail.swiss / lavoro.swiss / work.swiss), the job portal of the Swiss public employment service. Search by keyword, canton, city and radius, workload, contract type and posting date, or paste job links. Get employer, location, coordinates, workload, contract, start date, occupation, full description, contacts and apply links. No login needed.
Export Swiss job listings from job-room.ch, the job portal of the Swiss public employment service (also served as arbeit.swiss, travail.swiss, lavoro.swiss and work.swiss). Search by keyword, canton, city and radius, workload, contract type and posting date, and get clean rows with the employer, place of work, coordinates, workload, contract, start date, occupation, full description, contacts and apply links. No login needed: 10 jobs take about 5 seconds, 1,000 jobs with full descriptions about 25 seconds, and you pay $2.00 per 1,000 jobs.
Pflege, Informatiker, comptable), or * for all jobs that match your filters.| Field | What it does |
|---|---|
searchQueries | Search terms, one search each (* = all jobs matching the filters) |
startUrls | Job links or job ids to read in full |
maxResults | Total jobs to save (0 = no limit) |
cantons | Two-letter canton codes, e.g. ZH, VD, TI |
location / radiusKm | Swiss city or postcode and a 10–150 km radius |
postedWithinDays | Only jobs published in the last N days (1–60) |
workloadMin / workloadMax | Workload (Pensum) range in % |
contractType | any, permanent or temporary |
companyName | Employer name contains |
titleFilter | Comma-separated words the job title must contain |
sortBy | newest, oldest or relevance |
includeJobDetails | Full description and contacts for keyword searches (on by default) |
language | de, fr, it or en for descriptions, occupation names and salutations |
{
"searchQueries": ["Pflege"],
"cantons": ["ZH", "AG"],
"workloadMin": 80,
"contractType": "permanent",
"postedWithinDays": 7,
"maxResults": 100
}
One row per job.
| Field | Description |
|---|---|
title | Job title |
company | Employer or agency |
location, city, postal_code, canton, latitude, longitude | Place of work |
workload_min, workload_max | Workload (Pensum) in % |
employment_type | full-time or part-time (from the workload) |
contract_type | permanent or temporary |
start_date, starts_immediately, end_date | When the job starts and ends |
occupation, occupation_codes | Occupation name and code (Swiss AVAM classification) |
language_skills | Required languages and levels |
description_full, description_md, description_snippet | Full description as plain text and Markdown, plus a short excerpt |
posted_at, expires_at | Publication period |
job_status | online, expired, offline or unknown |
contact_*, apply_url, apply_email, apply_phone | Contact person and how to apply |
company_url, company_city, … | Employer details |
job_number, reporting_obligation | Federal job number and whether the job falls under the job-reporting obligation |
source_url, search_query, scraped_at | Job link, the search that found it and when it was saved |
{
"id": "d5eb9f09-0e3c-487b-bda5-bbbcb260535e",
"title": "Dipl. Pflegefachperson HF/FH & Teamleiter/in Pflegeabteilung 80-100% in Schlieren",
"company": "MediPersonal",
"location": "Schlieren, ZH",
"city": "Schlieren",
"postal_code": "8952",
"canton": "ZH",
"canton_name": "Zürich",
"latitude": 47.397,
"longitude": 8.446,
"job_status": "online",
"employment_type": "full-time",
"contract_type": "permanent",
"workload_min": 100,
"workload_max": 100,
"start_date": null,
"starts_immediately": true,
"number_of_jobs": 1,
"occupation": "Pflegefachmann/frau",
"occupation_codes": ["101224"],
"language_skills": [{"language": "de", "spoken": "basic", "written": "basic"}],
"description_snippet": "Dipl. Pflegefachperson HF/FH & Teamleiter/in Pflegeabteilung 80-100% in Schlieren – Ihre Führungsqualitäten sind gefragt! Schlieren liegt westlich von Zürich …",
"description_full": "Dipl. Pflegefachperson HF/FH & Teamleiter/in Pflegeabteilung 80-100% in Schlieren – Ihre Führungsqualitäten sind gefragt!\n\nSchlieren liegt westlich von Zürich …",
"posted_at": "2026-10-14",
"expires_at": "2026-11-12",
"job_number": "242821002",
"reporting_obligation": false,
"contact_salutation": "Frau",
"contact_name": "Anna Muster",
"contact_email": "anna.muster@example.ch",
"contact_phone": "+41440000000",
"apply_url": "https://www.example.ch/jobs/pflegefachperson-schlieren",
"apply_email": "jobs@example.ch",
"company_url": "https://www.example.ch",
"company_city": "Wallisellen",
"source_url": "https://www.job-room.ch/job-search/d5eb9f09-0e3c-487b-bda5-bbbcb260535e",
"source_platform": "job-room.ch",
"search_query": "Pflege",
"scraped_at": "2026-10-21T16:25:20Z"
}
The run's OUTPUT record lists every search with the number of jobs the site reports for it, plus job links that no longer exist.
You pay $2.00 per 1,000 jobs saved ($0.002 per job), full descriptions and contacts included. Platform usage (compute and Swiss residential proxy traffic) is billed on top and stays small: about $0.02–0.03 per 1,000 jobs in our test runs. Example: 1,000 jobs ≈ $2.00 + ~$0.03 usage ≈ $2.03.
Is it legal to scrape job-room.ch? The actor reads only public job ads that anyone can see without an account. You are responsible for how you use the data, especially personal data such as contact names (GDPR and the Swiss FADP).
Do I need a login or a proxy? No login. Swiss residential exits are the default because they reach the site fastest; datacenter exits work too (a little slower). If the chosen exits are refused, the run switches to the other group on its own.
How many jobs can I get? Up to 100,000 per run. The site lists jobs of the last 60 days and shows at most 10,000 per search; bigger searches are split by canton, and the run's status says if a search still hit the ceiling.
Why is a field empty? The site only has what the employer entered: many ads have no contact person, start date or company website. Salaries are not published on job-room.ch.
Can I schedule it or use the API? Yes. Schedule runs (for example daily with "Posted within" 1 day) and read the dataset through the API, webhooks or integrations.
Every field below can be set in the run form, passed through the API, or saved as a task. Unset fields fall back to the defaults shown.
searchQueriesarrayOptionalSearch terms
Job titles, skills or company names, one per line, e.g. 'Pflege', 'Informatiker', 'Koch', 'comptable'. Each term is its own search and duplicates across terms are removed. Use * to list all jobs that match the filters below.
startUrlsarrayOptionalJob links
Optional. Single job links from job-room.ch (or arbeit.swiss, travail.swiss, lavoro.swiss, work.swiss), e.g. https://www.job-room.ch/job-search/, or bare job ids. Each link is read in full; handy to re-check whether jobs are still online. Links that no longer exist are listed in the run's OUTPUT record.
maxResultsintegerOptionaldefault 20Maximum jobs
How many jobs to save in total across all search terms and locations (job links are always read in full). 0 = no limit (up to 100,000). One search on the site shows at most 10,000 jobs; bigger searches are split by canton automatically.
cantonsarrayOptionalCantons
Only jobs in these cantons. Leave empty for all of Switzerland.
locationstringOptionalLocation
Swiss city or postcode, e.g. 'Zürich', 'Lausanne', '3011'. Jobs within the radius below are returned. Separate several places with ';'. A canton name works too.
radiusKmintegerOptionaldefault 10Radius around the location (km)
Distance around the location (needs a location). The site accepts 10 to 150 km.
postedWithinDaysintegerOptionalPosted within (days)
Only jobs published in the last N days, e.g. 1, 7 or 30. 0 = all (the site lists jobs of the last 60 days).
workloadMinintegerOptionalMinimum workload (%)
Only jobs whose workload (Pensum) reaches at least this percentage, e.g. 80.
workloadMaxintegerOptionalMaximum workload (%)
Only jobs whose workload starts at or below this percentage, e.g. 60 for part-time jobs.
contractTypeenumOptionaldefault "any"Contract type
Permanent (unbefristet) or temporary (befristet) jobs only.
companyNamestringOptionalCompany
Only jobs from employers whose name matches, e.g. 'Spitex' or 'SBB'.
titleFilterstringOptionalJob title contains
Comma-separated words; only jobs whose title contains one of them are saved (case-insensitive, also matches inside longer words), e.g. 'Pflegefachfrau, Pflegefachmann, Pflegefachperson'.
sortByenumOptionaldefault "newest"Sort by
Newest first (the site's default), oldest first, or best match for the search term.
includeJobDetailsbooleanOptionaldefault trueInclude full descriptions
Keyword searches return only a short excerpt of each job; with this on, the full description (plain text and Markdown) and all contact fields are read from each job's page. Searches without a keyword (*) always include the full text. Turn off for faster runs.
languageenumOptionaldefault "de"Language
Preferred language for the description (when the job has several), occupation names and salutations.
maxResultsPerQueryintegerOptionalMaximum jobs per search
Optional cap for each search term and location, so many searches in one run each get their share. 0 = no cap per search (only Maximum jobs applies).
proxyConfigurationobjectOptionaldefault {"useScrapelyProxy":true,"scrapelyProxyGroups":["RESIDENTIA…Proxy configuration
Swiss residential exits are the default: they reach job-room.ch fastest. Datacenter proxies work too (a little slower). If the chosen exits are refused, the run switches to the other group automatically.
Every run writes its results to a dataset. Preview it in the dashboard, then export it or read it through the API.
| Field | Type | Description |
|---|---|---|
| id | string | null | |
| title | string | null | |
| company | string | null | |
| location | string | null | |
| city | string | null | |
| postal_code | string | null | |
| canton | string | null | |
| canton_name | string | null | |
| region_code | string | null | |
| country | string | null | |
| latitude | number | null | |
| longitude | number | null | |
| job_status | string | null | |
| employment_type | string | null | |
| contract_type | string | null | |
| workload_min | number | null | |
| workload_max | number | null | |
| start_date | string | null | |
| starts_immediately | boolean | null | |
| end_date | string | null | |
| short_employment | boolean | null | |
| work_forms | array | null | |
| number_of_jobs | number | null | |
| occupation | string | null | |
| occupation_codes | array | null | |
| language_skills | array | null | |
| description_language | string | null | |
| description_languages | array | null | |
| description_snippet | string | null | |
| description_full | string | null | |
| description_md | string | null | |
| posted_at | string | null | |
| expires_at | string | null | |
| created_at | string | null | |
| updated_at | string | null | |
| job_number | string | null | |
| reporting_obligation | boolean | null | |
| source_system | string | null | |
| contact_salutation | string | null | |
| contact_name | string | null | |
| contact_firstname | string | null | |
| contact_lastname | string | null | |
| contact_email | string | null | |
| contact_phone | string | null | |
| apply_url | string | null | |
| apply_email | string | null | |
| apply_phone | string | null | |
| apply_address | string | null | |
| apply_info | string | null | |
| external_url | string | null | |
| company_url | string | null | |
| company_street | string | null | |
| company_postal_code | string | null | |
| company_city | string | null | |
| company_country | string | null | |
| company_phone | string | null | |
| company_email | string | null | |
| source_url | string | null | |
| source_platform | string | null | |
| search_query | string | null | |
| scraped_at | string | null |
You pay for the events the actor reports, such as each result or page it produces. Platform usage is included in the event prices.
| Event | Charged when | Price |
|---|---|---|
| Job | One saved job-room.ch job listing (full description and contacts included). | $0.002 |
Run this actor from your own code. Swap in your API token and the examples work as-is.
import { ScrapelyClient } from 'scrapely-client'
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN })
// Start the actor and wait for the run to finish.
const run = await client.actor('openrole/job-room-scraper').call({
"searchQueries": [
"Pflege"
],
"maxResults": 20,
"proxyConfiguration": {
"useScrapelyProxy": true,
"scrapelyProxyGroups": [
"RESIDENTIAL"
],
"scrapelyProxyCountry": "CH"
}
})
// Read the dataset the run produced.
const { items } = await client.dataset(run.defaultDatasetId).listItems()
console.log(items)Tokens live in your account settings. Keep them server-side: a token carries the full permissions of your account.
Connect the Scrape.ly MCP server once and your agent can run this actor as a tool. Pick your tool:
Fetch scrape.ly/agents.md and run openrole/job-room-scraperPaste into Claude Code, Codex, Cursor or any AI agent. It signs you in once in the browser.
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp?tools=actors,runs,storage,docs&actors=openrole/job-room-scraper"
}
}
}No key in the file: your client opens the browser to sign you in the first time it connects.
Inputs the developer prepared for common jobs. Open one to see its input, then copy it to your account to run it as-is or adjust it.
Search term 'Informatiker' in canton Zürich, permanent contracts, 10 jobs with full descriptions.
Every job around Lausanne with a 20 km radius, descriptions and occupation names in French.
Search term 'cuoco' in canton Ticino with Italian occupation names.
'Verkauf' jobs posted in the last 7 days with a workload up to 60%, excerpts only for a faster run.
Every job from employers matching 'Spitex', oldest first.
Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.