Jobs.ch Scraper - Swiss Job Board Data Extraction
Pricing
from $4.00 / 1,000 job search results
Jobs.ch Scraper - Swiss Job Board Data Extraction
Scrapes job listings from jobs.ch, Switzerland's largest job board powered by JobCloud.
Pricing
from $4.00 / 1,000 job search results
Rating
0.0
(0)
Developer

Alessandro Santamaria
Actor stats
0
Bookmarked
22
Total users
4
Monthly active users
2 days ago
Last modified
Categories
Share
Jobs.ch Job Scraper
Scrapes job listings from jobs.ch, Switzerland's largest job board powered by JobCloud.
Three Scraping Modes
This scraper supports three distinct modes for different use cases:
| Mode | Input | Output | Use Case |
|---|---|---|---|
| SEARCH MODE | Search queries + filters | Basic or full job data | New job discovery, market analysis |
| SEARCH + DETAILS MODE | includeJobDetails: true (default) | Full job data with descriptions | Complete data collection in one run |
| DIRECT URLS MODE | directUrls: [...] | Full job data + job_status | Still-alive checks, re-scraping specific jobs |
Features
- Multi-query search - Run multiple search keywords in a single run with deduplication
- API-based scraping - Uses the official Jobs.ch search API for fast, reliable data extraction
- Multi-language support - Search in German, French, or English
- Location filtering - Filter by city, canton, or region across all of Switzerland
- Canton-specific search - Target specific Swiss cantons (ZH, BE, AG, etc.)
- Employment type filter - Filter by permanent, temporary, or freelance positions
- Workload filter - Filter by Pensum percentage (e.g., 40-60% for part-time)
- Nationwide coverage - Access jobs from all Swiss cantons and regions
- Comprehensive job data - Extracts title, company, location, salary, workload, contact details, and more
- LLM-powered contact extraction - Optional AI-powered extraction of contact person details using Groq or OpenRouter
- HR company filtering - Filter out recruitment agencies to get direct employer postings, or filter to only show HR agencies
- Standardized output - Returns data in the
JobListingschema format withsearch_querytracking - Rate-limited - Respectful 2-second delays between API requests
- Proxy support - Built-in proxy rotation for reliability
Input
| Field | Type | Description | Default |
|---|---|---|---|
directUrls | array | Direct job URLs to scrape (skips search mode) | [] |
companyNames | array | Company names to search for | [] |
searchQueries | string[] | One or more search keywords (deduplicated across queries) | ["Software Engineer"] |
searchQuery | string | Single search keyword (legacy, backward compatible) | "" |
location | string | City, canton, or region name (e.g., "Zurich", "Bern", "Basel") | "" (all Switzerland) |
canton | string | Filter by specific canton (e.g., "ZH", "BE", "AG") | "" (all cantons) |
language | string | Search language: de, fr, or en | de |
maxResultsPerQuery | integer | Maximum results per search keyword | 100 |
maxResults | integer | Total cap across all queries (0 = unlimited) | 0 |
employmentType | string | Filter by type: permanent, temporary, freelance | "" (all) |
workloadMin | integer | Minimum workload/Pensum percentage (0-100) | - |
workloadMax | integer | Maximum workload/Pensum percentage (0-100) | - |
searchMode | string | semantic (AI-powered) or classic (keyword matching) | semantic |
includeJobDetails | boolean | Fetch full job descriptions | true |
companyFilter | string | Filter by company type: all, exclude-hr, only-hr | all |
llmApiKey | string | API key for LLM contact extraction (optional, secret) | - |
llmModel | string | LLM model for contact extraction | none |
proxyConfiguration | object | Apify proxy settings | Residential |
Mode 1: SEARCH MODE (Multi-Query)
Search for jobs using multiple keywords and filters. Each keyword runs as a separate search, results are deduplicated across queries:
{"searchQueries": ["Software Engineer", "Softwareentwickler", "Backend Developer"],"location": "Zurich","maxResultsPerQuery": 100,"maxResults": 0}
Single query (backward compatible):
{"searchQuery": "Software Engineer","location": "Zurich","maxResultsPerQuery": 200}
Mode 2: SEARCH + DETAILS MODE (Complete Data)
Default mode with includeJobDetails: true:
- Use case: Complete data collection in one run
- Speed: Moderate - visits detail pages for each job
- Output: Full descriptions, requirements, contact details
{"searchQueries": ["Data Scientist", "Machine Learning"],"canton": "ZH","maxResultsPerQuery": 100,"includeJobDetails": true}
Mode 3: DIRECT URLS MODE (Still Alive Checks)
When directUrls is provided, the scraper operates in direct mode:
- Skips search phase - Goes directly to provided job URLs
- Job status detection - Returns
online,offline,expired, orunknown - Full data extraction - Same as detail page scraping
- Use case: Periodic "still alive" checks, re-scraping specific jobs after deduplication
{"directUrls": ["https://www.jobs.ch/de/stellenangebote/detail/b475b944-eab5-4d69-b251-a325bd272d62/","https://www.jobs.ch/fr/offres-emplois/detail/a123b456-cd78-9012-efab-345678901234/","https://www.jobs.ch/en/vacancies/detail/c789d012-ef34-5678-90ab-cdef12345678/"]}
Direct URLs mode workflow:
- Provide array of Jobs.ch job detail URLs
- Scraper visits each URL directly
- Detects if job is still online or has been removed
- Extracts full job data if available
- Returns
job_statusfield indicating availability
Language Support
Jobs.ch is a multilingual platform. Choose your preferred search language:
| Language | Code | Description |
|---|---|---|
| German | de | Default - most listings in German-speaking regions |
| French | fr | Listings in French-speaking regions (Romandie) |
| English | en | International positions and English-language listings |
Note: The language parameter sets the UI language but jobs are shown in all languages based on your search criteria.
Canton Filter
Target specific Swiss cantons for regional job searches:
| Canton | Code | Major Cities |
|---|---|---|
| Zurich | ZH | Zurich, Winterthur |
| Bern | BE | Bern, Biel/Bienne |
| Aargau | AG | Aarau, Baden |
| Geneva | GE | Geneva |
| Vaud | VD | Lausanne, Montreux |
| Basel-Stadt | BS | Basel |
| St. Gallen | SG | St. Gallen |
| Ticino | TI | Lugano, Bellinzona |
See full list of 26 cantons in the input schema.
Employment Type
Filter jobs by contract type:
| Type | Description |
|---|---|
permanent | Permanent/unlimited contracts (Festanstellung) |
temporary | Temporary/fixed-term contracts (Temporar) |
freelance | Freelance/contract work (Freiberuflich) |
Workload Filter (Pensum)
Filter jobs by workload percentage:
| Example | Description |
|---|---|
workloadMin: 80 | Jobs with at least 80% workload (typically full-time) |
workloadMax: 60 | Part-time jobs up to 60% |
workloadMin: 40, workloadMax: 60 | Part-time jobs between 40-60% |
This is useful for finding specific part-time or full-time positions.
HR Company Filtering
Filter jobs by company type:
| Option | Description |
|---|---|
all | Include all companies (default) |
exclude-hr | Remove HR/recruitment agencies (e.g., Adecco, Randstad, Manpower) |
only-hr | Show only HR/recruitment agency postings |
The filter detects HR companies by matching company names against common patterns.
LLM Data Extraction (Optional)
The scraper can optionally use an LLM to extract structured data from job postings, including requirements, benefits, and contact details.
Supported LLM Providers:
- Groq - Use API keys starting with
gsk_(recommended: fast and free tier available) - OpenRouter - Use API keys starting with
sk-or-
Available Models:
| Model ID | Provider | Description |
|---|---|---|
llama-3.1-8b-instant | Groq | Fast, lightweight (default) |
mistral-small-3.1-24b-instruct | OpenRouter | More capable, higher quality |
The LLM extracts:
requirements- Array of job requirements/qualificationscompany_benefits- Array of company benefits/perkscontact_phone- Contact phone numbercontact_email- Contact email addresscontact_salutation- "Herr" or "Frau"contact_firstname- First name of contact personcontact_lastname- Last name of contact person
Example Input
Multi-Query Search (IT Jobs in Zurich)
{"searchQueries": ["Software Engineer", "Softwareentwickler", "DevOps"],"location": "Zurich","maxResultsPerQuery": 100,"maxResults": 0}
Canton-Specific Search (All Jobs in Canton Bern)
{"searchQueries": [""],"canton": "BE","maxResultsPerQuery": 500}
Part-Time Jobs in Basel (40-60%)
{"searchQueries": ["Buchhaltung"],"location": "Basel","workloadMin": 40,"workloadMax": 60,"maxResultsPerQuery": 50}
French-Speaking Region Search
{"searchQueries": ["Infirmier", "Aide-soignant"],"canton": "VD","language": "fr","maxResultsPerQuery": 100}
Direct Employer Postings Only (No HR Agencies)
{"searchQueries": ["Marketing Manager"],"location": "Zurich","companyFilter": "exclude-hr","maxResultsPerQuery": 100}
With LLM Contact Extraction
{"searchQueries": ["Elektriker", "Elektroinstallateur"],"canton": "AG","maxResultsPerQuery": 100,"llmApiKey": "gsk_your_groq_api_key_here","llmModel": "llama-3.1-8b-instant"}
Direct URLs - Still Alive Check
{"directUrls": ["https://www.jobs.ch/de/stellenangebote/detail/b475b944-eab5-4d69-b251-a325bd272d62/","https://www.jobs.ch/de/stellenangebote/detail/a123b456-cd78-9012-efab-345678901234/"]}
Output
Each job listing follows the standardized JobListing schema:
{"id": "b475b944-eab5-4d69-b251-a325bd272d62","title": "Diplomierte Pflegefachperson","company": "Clienia Schloessli AG","location": "Oetwil am See","work_address": "Schloesslistrasse 8, 8618 Oetwil am See","canton": "ZH","job_status": "online","top_listing": null,"employment_type": "full-time","workload_min": 80,"workload_max": 90,"remote_option": null,"salary_text": null,"description_snippet": "Fuer unseren Bereich in der Kinder- und Jugendpsychiatrie...","description_full": "Full job description text...","requirements": ["Erfahrung im Bereich der Kinder- und Jugendpsychiatrie", "Offene, kommunikative Persoenlichkeit"],"posted_at": "2025-12-10T15:36:17.000Z","expires_at": null,"source_url": "https://www.jobs.ch/de/stellenangebote/detail/b475b944-eab5-4d69-b251-a325bd272d62/","source_platform": "jobs.ch","contact_salutation": "Frau","contact_firstname": "Irene","contact_lastname": "Walczewski","contact_email": null,"contact_phone": "+41 44 929 83 73","contact_raw": "Irene Walczewski","apply_url": null,"apply_email": null,"company_url": "https://www.jobs.ch/de/firmen/23141-clienia-schlossli-ag/","company_website": "https://www.clienia.ch/de/","company_industry": "Health care / Social services","company_employee_count": "501 - 1000 employees","company_job_count": 21,"company_jobs_url": "https://www.jobs.ch/de/firmen/23141-clienia-schlossli-ag/stellenangebote/","company_description": null,"company_rating": 2.5,"company_review_count": 8,"company_reviews_url": "https://www.jobs.ch/de/firmen/23141-clienia-schlossli-ag/bewertungen/","company_social_urls": null,"company_benefits": ["5 Wochen Ferien", "Attraktive Arbeitszeitformen", "Foerderung von Fort- und Weiterbildungen"],"search_query": "Pflegefachperson","scraped_at": "2025-12-11T14:16:53.609Z"}
Output Fields
| Field | Description |
|---|---|
id | Unique job posting ID |
title | Job title |
company | Company name |
location | City/location name |
work_address | Full work address (street, postal code, city) |
canton | Swiss canton code (ZH, BE, AG, etc.) |
job_status | Job availability: online, offline, expired, unknown (Direct URLs mode only) |
top_listing | Boolean - if job is a paid promotion (Direct URLs: always null) |
employment_type | permanent, temporary, freelance, full-time, part-time |
workload_min | Minimum workload percentage (Pensum) |
workload_max | Maximum workload percentage (Pensum) |
remote_option | remote, hybrid, onsite, or null |
salary_text | Salary as displayed (if available) |
description_snippet | First 500 characters of description |
description_full | Complete job description |
requirements | Array of job requirements (LLM-extracted if enabled) |
posted_at | Publication date |
expires_at | Expiration date (if available) |
source_url | Link to job posting (language-specific URL) |
source_platform | Always "jobs.ch" |
contact_salutation | "Herr" or "Frau" |
contact_firstname | Contact person first name |
contact_lastname | Contact person last name |
contact_email | Contact email address |
contact_phone | Contact phone number |
contact_raw | Raw contact text |
apply_url | External application URL |
apply_email | Application email address |
company_url | Company profile URL on jobs.ch |
company_website | Company's external website |
company_industry | Company industry/sector |
company_employee_count | Employee count range (e.g., "501 - 1000 employees") |
company_job_count | Number of open positions at company |
company_jobs_url | URL to company's job listings |
company_rating | Company rating (0-5 stars) |
company_review_count | Number of company reviews |
company_reviews_url | URL to company reviews page |
company_benefits | Array of company benefits (LLM-extracted if enabled) |
search_query | The search keyword that found this job (null for direct URLs) |
scraped_at | Timestamp when the job was scraped |
Notes on job_status field:
- Only populated in Direct URLs mode (Mode 3)
- In Search modes (Mode 1 & 2), this field is
nullsince jobs from search results are assumed to be online - Values:
online- Job is currently availableoffline- Job page returns 404 or "not found"expired- Job explicitly marked as expiredunknown- Unable to determine status
Usage
Via Apify Console
- Go to the actor page
- Configure input parameters
- Click "Start"
- Download results from the Dataset tab (JSON, CSV, Excel)
Via API
curl -X POST "https://api.apify.com/v2/acts/santamaria~jobs-ch-scraper/runs" \-H "Authorization: Bearer YOUR_API_TOKEN" \-H "Content-Type: application/json" \-d '{"searchQueries": ["Data Scientist", "Machine Learning Engineer"],"canton": "ZH","maxResultsPerQuery": 100}'
Via Apify SDK (Node.js)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });const run = await client.actor('santamaria/jobs-ch-scraper').call({searchQueries: ['Marketing Manager', 'Product Manager'],location: 'Zurich',employmentType: 'permanent',maxResultsPerQuery: 150,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(`Found ${items.length} jobs`);
Coverage
Jobs.ch is Switzerland's largest job board, covering all 26 cantons:
German-Speaking Regions
- Zurich (ZH), Bern (BE), Luzern (LU), Aargau (AG)
- St. Gallen (SG), Basel (BS/BL), Thurgau (TG)
- Solothurn (SO), Schaffhausen (SH), Graubunden (GR)
French-Speaking Regions (Romandie)
- Geneva (GE), Vaud (VD), Fribourg (FR)
- Neuchatel (NE), Valais (VS), Jura (JU)
Italian-Speaking Region
- Ticino (TI)
Performance
- Speed: ~100-300 jobs/minute (limited by respectful rate limiting)
- Cost: ~0.01-0.03 CU per 500 jobs
- Reliability: Built-in retry logic and error handling
Data Source
This actor scrapes data from Switzerland's largest job board:
- Website: jobs.ch
- API: JobCloud job search API
- Coverage: All of Switzerland (26 cantons)
- Platform: Powered by JobCloud
Common Use Cases
- Job market analysis: Track hiring trends by region/category
- Competitive intelligence: Monitor competitors' hiring
- Job aggregation: Build job search platforms
- Still-alive monitoring: Check if previously scraped jobs are still active (Direct URLs mode)
- Post-deduplication enrichment: Scrape basic data first, then fetch details for new jobs only
- Career research: Analyze salary ranges and requirements
- Recruitment sourcing: Find candidates via company postings
Legal Notice
This actor accesses publicly available job listings through the API. Please ensure your use case complies with jobs.ch terms of service.
Part of the Santamaria Job Scrapers Suite - Professional-grade job data for the DACH region and beyond.
Need help with integration, aggregation, or custom scraping solutions? Contact us at contact@alessandrosantamaria.com