jobs.ch Scraper πŸ‡¨πŸ‡­ Swiss Jobs (Search + Detail) avatar

jobs.ch Scraper πŸ‡¨πŸ‡­ Swiss Jobs (Search + Detail)

Pricing

from $2.00 / 1,000 results

Go to Apify Store
jobs.ch Scraper πŸ‡¨πŸ‡­ Swiss Jobs (Search + Detail)

jobs.ch Scraper πŸ‡¨πŸ‡­ Swiss Jobs (Search + Detail)

Scrape jobs.ch β€” Switzerland's #1 job board. Search + full job detail: title, company, location, workload % (80-100%), contract type, salary (CHF), full description, posted date. Fast JSON-API scraping on a Swiss residential proxy. Pay-per-result.

Pricing

from $2.00 / 1,000 results

Rating

0.0

(0)

Developer

Crow Lee

Crow Lee

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

jobs.ch Scraper πŸ‡¨πŸ‡­ β€” Scrape Swiss Jobs (no login, no API key)

Scrape job postings from jobs.ch, Switzerland's #1 job board, into clean structured data β€” title, company, company logo, location, canton, workload percentage (the Swiss 80-100% convention), contract type, salary in CHF when published, full job description, remote-work flag, and ISO posted date. A practical jobs.ch API alternative: no login and no API key required; export to JSON, CSV, Excel (XLSX), XML, or an HTML table, or pull results straight from the Apify API. Your $5 free Apify credit β‰ˆ 3,300 full-detail jobs β€” enough to test seriously before spending a cent.

πŸ” What does the jobs.ch Scraper do?

You give it a search (a keyword like software engineer plus a location like Zurich, or any jobs.ch search URL) and it returns every matching job posting as a structured record. Built-in filters narrow the search server-side: publication date (last 24h / 3 / 7 / 30 days), employment types (permanent, temporary, freelance, internship, supplementary income, apprenticeship), and workload range (e.g. only 80-100% roles). It runs in two layers:

  • Search cards β€” fast list of jobs from the results pages (title, company, location, workload %, contract type, snippet, posted date).
  • Full detail (default) β€” fetches each job's detail record for the complete description, published salary (CHF), and the direct application URL.

Under the hood it talks to jobs.ch's own public JSON API over plain HTTP through a Swiss residential proxy β€” no browser rendering, so runs are fast and cheap. It paginates page by page and stops cleanly at your item budget or the API's 2,000-results-per-search ceiling.

πŸ‘€ Who is it for?

  • Recruiters & staffing agencies β€” track open roles, hiring companies, and workloads across Swiss cities; build outreach lists by role, canton, and pensum.
  • Labour-market & HR analysts β€” measure demand by skill, contract type (permanent vs. temporary), and region; benchmark published CHF salaries.
  • Job boards & aggregators β€” supplement your own inventory with Swiss coverage from the market leader.
  • Founders & sales teams β€” find companies that are actively hiring (a strong buying/growth signal) in a target city or sector.

⭐ Why use this scraper?

  • Switzerland-focused β€” jobs.ch coverage with Swiss conventions built in: workload as 80-100%, salaries in CHF, locations across all cantons and language regions (searches work in English, German, French, or Italian).
  • API-grade data quality β€” records come from jobs.ch's own JSON API, not brittle HTML parsing: stable IDs, exact timestamps with timezone, structured salary ranges. Since jobs.ch offers no public developer API, this actor is the pragmatic jobs.ch API alternative for programmatic access.
  • Server-side filters β€” publication date (24h/3d/7d/30d), employment types, and workload (pensum) range are applied in the jobs.ch API query itself, so you only pay for jobs that match.
  • No login, no API key β€” just a search or a URL.
  • Full job descriptions β€” the complete job-ad text as clean plain text, not just the snippet.
  • Budget-safe β€” maxItems cap, dedup (you never pay twice for the same job), anti-runaway pagination caps.
  • All export formats β€” JSON, CSV, Excel, XML, HTML table, plus API and webhooks.

πŸ“Š What data can you extract from jobs.ch?

Data pointExample
titleSoftware Engineer
companyAmmann Schweiz AG
companyUrlhttps://www.jobs.ch/en/companies/3812-ammann-schweiz-ag/
companyLogohttps://media.jobs.ch/images/44c3746c-…/320x320.png
locationLangenthal
canton (detail mode)BE
isRemotetrue when the title/description mentions remote / home office / Homeoffice
workloadPercent80-100%
contractTypePermanent position
salaryRawCHF 5200+ per month
salaryMin / salaryMax5200 / 6500
salaryCurrencyCHF
salaryPeriodmonth
descriptionSnippetAmmann ist ein weltweit fΓΌhrender Lieferant von Mischanlagen…
description (detail mode)Full job-ad text as clean plain text
applicationUrl (detail mode)https://ammann-schweiz-ag.contactrh.com/jobs/4473/…
postedDate2026-06-20T08:32:21.000Z
publishedRaw2026-06-20T10:32:21+02:00
jobKey0e233528-63b7-4b59-a477-0e02f3035ba3
urlhttps://www.jobs.ch/en/vacancies/detail/0e233528-…/

Note: salaryRaw/salaryMin/salaryMax appear only when the employer publishes pay β€” most Swiss postings don't (salary transparency is not mandatory in Switzerland). description and applicationUrl are only populated when Scrape full detail pages is on.

πŸ’° How much does it cost to scrape jobs.ch?

This actor uses Apify's pay-per-event pricing:

EventWhen it firesPrice (USD)Per 1,000
Actor startOnce per run$0.02β€”
Job (search card)Per unique job, when Scrape full detail pages = off$0.0008$0.80
Job (full detail)Per unique job, when Scrape full detail pages = on (full description + salary + application URL)$0.0015$1.50

Your first results are free: the $5 free credit on Apify's free plan covers roughly 3,300 full-detail jobs (or ~6,200 search cards) β€” no credit card needed to start. Duplicates are never charged. Real-world cost examples:

RunItemsModeApprox. cost
Quick scan100 jobssearch cards only$0.02 + 100 Γ— $0.0008 = $0.10
Standard100 jobsfull detail$0.02 + 100 Γ— $0.0015 = $0.17
Deep pull500 jobsfull detail$0.02 + 500 Γ— $0.0015 = $0.77
Max search2,000 jobsfull detail$0.02 + 2,000 Γ— $0.0015 = $3.02

With the $5/month free Apify plan you can scrape roughly 3,300 full-detail jobs or 6,200 search cards per month at no cost. (Proxy traffic is included in your Apify plan's usage; the API-based approach keeps it minimal.)

πŸš€ How to scrape jobs.ch

  1. Open the actor on Apify and click Try for free.
  2. Enter a Search query (e.g. software engineer) and a Location (e.g. Zurich) β€” or paste one or more jobs.ch search URLs into Search URLs.
  3. (Optional) Narrow with Posted within, Employment types, and Min/Max workload; set Max items and toggle Scrape full detail pages.
  4. Leave the proxy on RESIDENTIAL / Switzerland.
  5. Click Start, then Export results as JSON, CSV, Excel, XML, or HTML.

🧩 Input examples

Minimal β€” keyword + city:

{
"searchQuery": "software engineer",
"location": "Zurich",
"maxItems": 100,
"scrapeDetails": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "CH" }
}

Filtered β€” fresh permanent 80-100% roles only:

{
"searchQuery": "data engineer",
"location": "Zurich",
"publicationDateFilter": "7d",
"employmentTypes": ["5"],
"workloadMin": 80,
"workloadMax": 100,
"maxItems": 200,
"scrapeDetails": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "CH" }
}

Multiple filtered searches β€” paste jobs.ch URLs (any language; filters like employment type, region, or publication date are preserved):

{
"startUrls": [
{ "url": "https://www.jobs.ch/en/vacancies/?term=data%20engineer&location=Zurich&employment-types=5" },
{ "url": "https://www.jobs.ch/de/stellenangebote/?term=pflegefachfrau&region=2" }
],
"maxItems": 300,
"scrapeDetails": true,
"maxConcurrency": 5,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "CH" }
}

βš™οΈ Input parameters

ParameterTypeDefaultDescription
startUrlsarray–jobs.ch search URLs (website or API form, any language). Overrides the query/location fields. All URL filters are preserved.
searchQuerystring–Job keyword (the jobs.ch term), e.g. software engineer. Empty with no startUrls = browse all jobs.
locationstring–City, canton, or region, e.g. Zurich, Geneva. Empty = all of Switzerland.
publicationDateFilterstringanyOnly jobs posted within: 1d, 3d, 7d, 30d, or any. Applied server-side in the API query and re-checked on each record's postedDate.
employmentTypesarray–Contract-type filter: "5" Permanent, "1" Temporary, "2" Freelance, "3" Internship, "4" Supplementary income, "6" Apprenticeship. Empty = all.
workloadMin / workloadMaxinteger–Workload (pensum) range 0-100, e.g. 80/100 for 80-100% roles. Maps to the jobs.ch employment-grade filter.
maxItemsinteger100Stop after this many jobs (0 = unlimited, capped at 2,000 per search by the jobs.ch API).
scrapeDetailsbooleantrueFetch each job's detail record for full description, salary, and application URL.
maxConcurrencyinteger5Parallel requests (capped at 10 internally to stay polite).
proxyConfigurationobjectRESIDENTIAL / CHRequired. Apify residential proxy, country Switzerland.

πŸ“€ Output example

A real record from query=nurse (full-detail mode):

{
"url": "https://www.jobs.ch/en/vacancies/detail/d9f74cbb-ff2b-4f58-be48-a6c2eb704651/",
"jobKey": "d9f74cbb-ff2b-4f58-be48-a6c2eb704651",
"title": "Pflegeexpertin / Pflegeexperte / Nurse Practitioner (w/m/d) Tumorpfad 80-100%",
"company": "UniversitΓ€tsspital ZΓΌrich",
"companyUrl": "https://www.jobs.ch/en/companies/11393-universitaetsspital-zuerich/",
"companyLogo": "https://media.jobs.ch/images/2c1f45b0-9c94-4bbf-a2a1-c19c04c34f9d/320x320.png",
"location": "ZΓΌrich",
"canton": "ZH",
"isRemote": false,
"workloadPercent": "80-100%",
"contractType": "Permanent position",
"salaryRaw": null,
"salaryMin": null,
"salaryMax": null,
"salaryCurrency": null,
"salaryPeriod": null,
"descriptionSnippet": "Am UniversitΓ€tsspital ZΓΌrich begleitest du Menschen mit onkologischen Erkrankungen in einem hochspezialisierten medizinischen Umfeld - im ...",
"description": "Am UniversitΓ€tsspital ZΓΌrich begleitest du Menschen mit onkologischen Erkrankungen in einem hochspezialisierten medizinischen Umfeld - im durchgΓ€ngigen Patientenpfad, ΓΌber Fachgrenzen hinweg und mit spΓΌrbarer Wirkung fΓΌr Patientinnen und Patienten.…",
"applicationUrl": "https://ohws.prospective.ch/public/v1/jobs/01d77c02-b241-4cd1-885f-440f56a08b83/",
"postedDate": "2026-06-16T13:32:41.000Z",
"publishedRaw": "2026-06-16T15:32:41+02:00",
"scrapedAt": "2026-07-10T17:11:58.241Z",
"source": "detail"
}

And a record with a published salary (detail mode):

{
"url": "https://www.jobs.ch/en/vacancies/detail/bba01a3d-0710-4865-96f5-5fe0090aadcf/",
"jobKey": "bba01a3d-0710-4865-96f5-5fe0090aadcf",
"title": "Reinigungsmitarbeiter/in (80–100%) – BΓΌroreinigung",
"company": "Efe's Reinigung",
"location": "Urdorf",
"workloadPercent": "80-100%",
"contractType": "Permanent position",
"salaryRaw": "CHF 5200+ per month",
"salaryMin": 5200,
"salaryMax": null,
"salaryCurrency": "CHF",
"salaryPeriod": "month",
"postedDate": "2026-07-09T12:46:12.000Z",
"source": "detail"
}

In search-card mode (scrapeDetails: false), description and applicationUrl are null and source is "search-card".

πŸ’‘ Tips for best results

  • Start small. Run with maxItems: 20 first to validate your query, then scale up.
  • Use startUrls for precise filters. Build the exact search you want on jobs.ch (employment type, region, publication date, category…), then paste the URL β€” every filter is respected.
  • Beat the 2,000-result ceiling. The API caps one search at 2,000 results. Split broad queries into several startUrls (per canton, per employment type) to cover more.
  • Schedule it. Run daily with publicationDateFilter: "1d" to capture only postings from the last 24 hours β€” perfect for a fresh-jobs feed.
  • Search cards are half the requests. If you don't need full descriptions, turn scrapeDetails off: same jobs at almost half the cost and double the speed.

⚠️ Error items

When a request permanently fails after all retries, the actor pushes an error item (no charge) so a run is never silently lossy:

{ "error": "BLOCKED_OR_FAILED", "errorDescription": "Non-JSON response from https://www.jobs.ch/api/…", "url": "https://www.jobs.ch/api/v1/public/search?query=…", "scrapedAt": "2026-07-10T17:12:00.000Z" }
Error codeMeaning
BLOCKED_OR_FAILEDThe request failed after 5 retries (network error, rate limit, or an HTML error page instead of JSON). Re-run later or lower concurrency.
RUN_ABORTEDThe whole run hit an unrecoverable error (e.g. proxy pool exhaustion). Results scraped before the abort are kept.

πŸ”Œ Integrations

Push results anywhere Apify connects: Google Sheets, Slack, Discord, Make, Zapier, BigQuery, Snowflake, Airbyte, plain webhooks, and the scheduler. Configure these from the actor's Integrations tab.

πŸ› οΈ API usage

Run the actor and fetch the dataset via the Apify API.

Node.js (apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('crowley/jobs-ch-scraper').call({
searchQuery: 'software engineer',
location: 'Zurich',
maxItems: 100,
scrapeDetails: true,
proxyConfiguration: { useApifyProxy: true, apifyProxyGroups: ['RESIDENTIAL'], apifyProxyCountry: 'CH' },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python (apify-client):

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("crowley/jobs-ch-scraper").call(run_input={
"searchQuery": "software engineer",
"location": "Zurich",
"maxItems": 100,
"scrapeDetails": True,
"proxyConfiguration": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "CH"},
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)

cURL:

curl -X POST "https://api.apify.com/v2/acts/crowley~jobs-ch-scraper/runs?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchQuery":"software engineer","location":"Zurich","maxItems":100,"scrapeDetails":true,"proxyConfiguration":{"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"],"apifyProxyCountry":"CH"}}'

πŸ€– Use with AI agents via MCP

This actor is callable from AI agents through the Apify MCP server. Example setup for Claude Desktop / Claude Code / Cursor:

{
"mcpServers": {
"apify": {
"command": "npx",
"args": ["-y", "@apify/actors-mcp-server", "--actors", "crowley/jobs-ch-scraper"],
"env": { "APIFY_TOKEN": "YOUR_APIFY_TOKEN" }
}
}
}

Example prompts: "Find software engineering jobs in Zurich with at least an 80% workload" or "List nursing jobs in Bern posted this week, with company and application link."

❓ FAQ

Do I need a jobs.ch login or API key? No. Just a search or URL and an Apify residential proxy.

Where does the data come from? From jobs.ch's own public JSON API β€” the same one the jobs.ch website itself uses. That means stable job IDs, exact timestamps, and structured fields instead of fragile HTML scraping.

What does workloadPercent mean? Swiss job ads state the pensum β€” the employment percentage. 100% is full-time, 80-100% means the employer accepts anything from 4 days a week to full-time. The scraper collapses the API's grade list (e.g. [80, 85, 90, 95, 100]) into that familiar range.

Why are most salaries empty? Swiss employers rarely publish pay β€” there is no salary-transparency mandate in Switzerland. When a posting does include it, you get salaryRaw, salaryMin/salaryMax, salaryCurrency (CHF), and salaryPeriod.

Can I search in German or French? Yes. The search index covers all of jobs.ch, and queries work in any of the site's languages (pflegefachfrau, comptable, software engineer…). You can also paste /de/stellenangebote/ or /fr/offres-emplois/ URLs as startUrls.

How many results can I get per search? The jobs.ch API caps a single search at 2,000 results. Use more specific queries/locations or several startUrls to cover more.

Can I get only new jobs? Yes β€” set publicationDateFilter to 1d (last 24 hours), 3d, 7d, or 30d and schedule the actor. Website URLs with publication-date=N pasted as startUrls are translated to the equivalent API filter too.

Can I find remote jobs? jobs.ch has no structured remote field, so the actor sets an isRemote heuristic flag when the title or description mentions remote, home office, or Homeoffice. Filter your export on isRemote = true.

Can I use this for salary benchmarking? Yes, with the caveat that only a minority of Swiss postings publish pay. Aggregate salaryMin/salaryMax/salaryPeriod (already normalized to CHF) across a role and region for directional benchmarks.

Is it legal? See the Legality section below.

βš–οΈ Legality

This scraper collects publicly available job-posting data only. It does not log in, bypass paywalls, or collect personal data of job applicants. You are responsible for using it in compliance with jobs.ch's Terms of Service and robots.txt, the EU GDPR, and the Swiss Federal Act on Data Protection (FADP/nDSG). Scrape responsibly: keep concurrency modest, do not overload the site, and use the data lawfully (e.g. recruiting and market research, not spam). Job postings may contain a contact name β€” treat any personal data per the FADP and GDPR (lawful basis, minimisation, retention limits). When in doubt, consult a lawyer. Background reading: Is web scraping legal?

πŸ’¬ Your feedback

Found a bug or want a new field? Open an issue on the actor's Issues tab β€” we actively maintain it.

Other Switzerland-focused scrapers from the same author:

πŸ“ Changelog

1.1 β€” 2026-07-10

  • New publicationDateFilter input (1d/3d/7d/30d) β€” server-side publication-date window (mapped to the API's publication-date-from/-to range), plus a client-side postedDate double-check so re-published old ads never slip through.
  • New employmentTypes input β€” filter by contract type (Permanent, Temporary, Freelance, Internship, Supplementary income, Apprenticeship) via the API's employment-type-ids[] filter.
  • New workloadMin/workloadMax inputs β€” pensum range 0-100% via the API's employment-grade filter.
  • New output fields: companyLogo (structured logo image URL), canton (e.g. ZH, BE β€” from the detail location block), isRemote (heuristic keyword flag: remote / home office / Homeoffice).
  • Website startUrls with publication-date=N or employment-types=N are now translated to the equivalent API filters (the raw website params are silently ignored by the API).

1.0 β€” 2026-07-10

  • Initial release: jobs.ch search + full job-detail scraping via the public JSON API (no browser β€” fast, cheap HTTP).
  • Swiss workload parsing (80-100%), contract-type mapping, CHF salary ranges (min/max/period), ISO posted dates, clean plain-text descriptions, direct application URLs.
  • startUrls support for any jobs.ch search URL (en/de/fr/it) with all filters preserved.
  • Pay-per-event pricing with dedup and error items; maxItems budget cap and anti-runaway pagination caps (2,000-result API ceiling, matchless-streak guard).