jobs.ch Swiss Jobs Scraper avatar

jobs.ch Swiss Jobs Scraper

Pricing

from $1.70 / 1,000 job founds

Go to Apify Store
jobs.ch Swiss Jobs Scraper

jobs.ch Swiss Jobs Scraper

Search jobs.ch (Switzerland) by keyword and get public job listings: title, company, location, employment type, posted date, URL. Unofficial, independent tool — not affiliated with, endorsed by, or sponsored by jobs.ch.

Pricing

from $1.70 / 1,000 job founds

Rating

0.0

(0)

Developer

Tim Zinin

Tim Zinin

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 hours ago

Last modified

Share

jobs.ch is Switzerland's largest job board. This Actor searches it by keyword and returns one row per open role — title, company, location, employment type, posted date and a direct link — straight from the public, server-rendered search results. No login, no browser, no proxies.

What you get

  • Live job listings, not a stale export. The same job cards jobs.ch's own search page shows, for as many keywords as you give it in one run.
  • Optional full description. Turn on one setting and this Actor also visits each job's own page for the real description text and a more precise location — off by default so a run stays fast.
  • Multiple keywords, one run. Up to 10 search terms per call, each paginated and deduplicated independently.
  • Honest "no results." A search that genuinely has nothing pushes a found: false row with no error — a search that failed to load pushes found: false with a real error message. The two never look the same.
  • Runs on Apify: schedule it, monitor it, call it from the API or the MCP server, export to JSON, CSV or Excel, or push results straight into your own pipeline.

How to run it

  1. Click Try for free — no card needed on the free plan.
  2. Paste your search terms into Search keywords, one per line — e.g. marketing, software engineer.
  3. Press Start. Results appear in the dataset — read them in the UI, pull them from the API, or have a webhook push them onward.

Pricing

Pay-per-event: $0.005 per run start + $0.002 per job found. No monthly seat, no minimum. 100 jobs cost about $0.21; 1,000 jobs about $2.01.

A keyword with no matches, or a page that failed to load, is still logged with found: false and the reason — and it is not charged for. You pay for jobs actually delivered, not for attempts.

Input

FieldRequiredWhat it does
keywordsyesSearch terms, e.g. marketing, software engineer. Up to 10 per run.
locationnoOptional jobs.ch location filter (city or postal code), applied to every keyword. Leave empty to search all of Switzerland.
max_itemsnoJob rows to collect per keyword, at most (default 30, max 200).
max_pagesnoResult pages to walk per keyword, at most (default 3, max 20; ~20 jobs/page).
fetch_full_descriptionnoVisit each job's own page for the real description and a more precise location. Slower — one extra request per job. Off by default.
{
"keywords": ["marketing"],
"max_items": 30,
"max_pages": 3
}

Output

One dataset row per job found. This is a real row from a real run (VDjmy13MxbdsowQM9, 2026-07-30, default settings, fetch_full_description off):

{
"found": true,
"url": "https://www.jobs.ch/en/vacancies/detail/4c2c1609-3e60-4cf8-abdd-c9d21b694f75/",
"job_id": "4c2c1609-3e60-4cf8-abdd-c9d21b694f75",
"title": "Marketing Manager 80-100%",
"company": "Wilhelm AG",
"company_url": "https://www.jobs.ch/en/companies/142381-142381-wilhelm-ag/",
"location": "CH",
"country": "CH",
"employment_type": "Permanent position",
"posted_date": "2026-07-24T05:32:38.000Z",
"salary_raw": null,
"description": "We are looking for a Marketing Manager 80-100% to join our team.",
"description_is_teaser": true,
"source_board": "jobs-ch",
"scraped_at": "2026-07-30T14:26:04.916Z",
"matched_keyword": "marketing"
}

With fetch_full_description: true, the same job's description becomes the real posting text (not the short teaser), description_is_teaser becomes false, and location/company_url upgrade to more precise values when the job's own page has them (e.g. location: "Roggwil, 9325" instead of "CH", company_url pointing at the employer's real site instead of its jobs.ch profile page).

FieldWhat it means
foundWhether this row is a real job (true) or a notice/error row (false)
urlDirect link to the job posting — the unique key for this row
job_idjobs.ch's own job identifier
titleJob title
companyHiring company name
company_urlLink to the company (its own site when available, otherwise its jobs.ch profile)
locationLocation as jobs.ch shows it — just the country unless fetch_full_description is on
countryCountry code (always CH on this Actor)
employment_typejobs.ch's own label, e.g. "Permanent position"
posted_dateISO 8601 timestamp, or null if unparseable
salary_rawSalary as published, or null — Swiss job ads essentially never publish one; this Actor never estimates or invents a figure
descriptionJob description, up to 600 characters; teaser text unless fetch_full_description is on
description_is_teasertrue when description is the short list-page snippet rather than the real posting text
source_boardAlways "jobs-ch" — which board this Actor's row came from
scraped_atWhen this Actor fetched the row
matched_keywordWhich of your search keywords produced this row
partial / partial_reasonOnly present when fetch_full_description is on and that one job's own page failed to load — the row is still delivered and billed with the list-page data, just flagged as incomplete

A keyword with no matches (only reliably reproducible via the location filter — a plain keyword search on jobs.ch is designed to always suggest something) pushes:

{ "found": false, "error": "", "source_board": "jobs-ch", "scraped_at": "..." }

A keyword jobs.ch failed to answer pushes an error row with a non-empty error (e.g. "http 403") — never the same shape as "no matches".

API

Start a run with a bearer token and explicit JSON input:

curl -sS -X POST 'https://api.apify.com/v2/acts/zinin~jobs-ch-swiss/runs?waitForFinish=60' \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"keywords":["marketing"],"max_items":30,"max_pages":3}'

Read Dataset rows using the returned defaultDatasetId:

curl -sS "https://api.apify.com/v2/datasets/$DEFAULT_DATASET_ID/items?clean=true&format=json" \
-H "Authorization: Bearer $APIFY_TOKEN"

MCP

For an Apify MCP client exposing the standard call-actor tool, send this exact payload:

{
"name": "call-actor",
"arguments": {
"actor": "zinin/jobs-ch-swiss",
"input": {
"keywords": [
"marketing"
],
"max_items": 30,
"max_pages": 3
}
}
}

Tools that cover the same Swiss/DACH hiring picture from a different angle — a company not on Greenhouse/Lever/Ashby, or a wider region than jobs.ch alone.

ActorUse it when
XING Jobs (DACH) ScraperWidening the same search to Germany and Austria, sourced straight from each job's own page rather than jobs.ch's keyword search.
Job Postings AggregatorThe Swiss company you're checking does run a Greenhouse, Lever or Ashby board — pull its feed directly instead of searching jobs.ch.
Company Hiring RadarYou have one specific company in mind and want a scored hiring signal, not a keyword search across the whole market.

FAQ

Does it need an API key / login? No — it reads jobs.ch's public, server-rendered search results.

Why is salary_raw almost always null? Because jobs.ch almost never publishes one. This Actor never estimates or guesses a number — null means the source said nothing, not that the Actor failed to find it.

Why does a nonsense search term still return jobs? jobs.ch's own search is designed to never show an empty results page — an unmatched term falls back to unrelated "recommended" jobs rather than showing nothing. That is jobs.ch's behavior, not a bug in this Actor. To reliably get zero results (e.g. for testing), use the location filter with a place that doesn't exist.

How fresh is the data? Live at run time — every call fetches jobs.ch's current search results.

Can I call it from an AI agent? Yes — standard Apify Actor, callable from the Apify API, the SDK, or the Apify MCP server.

What this is NOT. It does not apply to jobs on your behalf, does not cover job boards outside jobs.ch, and does not invent a salary figure when the source has none.

Found a wrong result, or need a check we don't run? Open an issue on this Actor's page.

Machine use

The Actor is callable through the Apify API, SDK, and Apify MCP server. The input and Dataset row are the machine-facing contract; salary_raw is null whenever jobs.ch itself publishes none — this Actor never estimates or invents a figure to fill the gap.


Built by zinin. Questions? Telegram @timzinin.