# Jobs.ch Jobs Scraper (`piotrv1001/jobs-ch-jobs-scraper`) Actor

The Jobs.ch Jobs Scraper extracts Swiss job vacancies from Jobs.ch by keyword, location and workload, capturing original advert text kept separate from translations, source language, every workplace, published salaries, companies and hours — ideal for Swiss recruiting and labour-market research.

- **URL**: https://apify.com/piotrv1001/jobs-ch-jobs-scraper.md
- **Developed by:** [FalconScrape](https://apify.com/piotrv1001) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 job listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### 🚀 Jobs.ch Jobs Scraper

Extract Swiss job vacancies from [jobs.ch](https://www.jobs.ch) by keyword, location and workload (Pensum). The **Jobs.ch Jobs Scraper** keeps each advert's **original text exactly as the employer wrote it**, separate from jobs.ch's own translation. It also reports the source language and saves **every workplace** of multi-location jobs. Use it for Swiss recruiting, sourcing and labour-market research.

### ✨ Features

- 🇨🇭 **Swiss job search**: search in German, French, Italian or English, anywhere in Switzerland or in a town, canton or region (`Zürich`, `Genève`, `Ticino`).
- 📝 **Original and translated text, never mixed**: `title` and `description` hold the advertiser's original advert. `titleLocalized` and `descriptionLocalized` hold jobs.ch's translation into English, German or French, when it provides one.
- 🌐 **Advert language with a sanity check**: `sourceOriginalLanguage` is the language jobs.ch reports. `detectedLanguage` is our own guess from the text. `languageMetadataConflict` flags jobs where the two disagree, such as an Italian advert that jobs.ch labels as French.
- ⚖️ **Workload (Pensum) filter with two modes**: by default you get jobs.ch's own matching, where a 60–100% job counts for a 40–60% search. Turn on **Whole workload range must fit** to keep only jobs whose entire offered range lies inside your range. Dropped jobs are not charged.
- 📍 **All workplaces**: a job advertised in St. Gallen, Zürich, Bern and Basel-Land keeps all four addresses with postcode, canton and coordinates.
- 💰 **Only real salaries**: salary fields are filled only when the advertiser publishes a figure (for example CHF 90,000–138,000 per year). Jobs without one get `null`, never a zero or an estimate.
- ✅ **Verified job pages**: an expired or redirected job URL is reported in the run summary. It is never replaced with another job's data and never charged.
- 🔗 **Flexible input**: use a keyword search, search or category pages copied from your browser, or single job URLs.
- 📋 **Run summary**: for every search you get the number of jobs jobs.ch reports, the pages scanned, the number of jobs excluded by the workload filter and why the search stopped.

### 🛠️ How It Works

1. **Enter a keyword and location**: for example `software` in `Zürich`. You can also paste jobs.ch search, category or job URLs.
2. **Optionally set a workload range**: for example 40–60% for part-time roles.
3. **Choose listings or full details**: listings come straight from the search results. **Scrape full job details** adds the full advert, the translation, salary, employment type, weekly hours and more.
4. **Run the scraper**: download the results as JSON, CSV or Excel, or connect them to your tools through the Apify API.

### 💵 Pricing

You pay per job saved. No monthly fee.

| Event       | Price                    | What you get                                                                                                                                                                            |
| ----------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Job listing | **$0.80 per 1,000 jobs** | Original title, company, workload range, place and all workplaces, required languages, publication dates                                                                                |
| Job detail  | **$1.50 per 1,000 jobs** | Everything in a listing plus the original advert text, the jobs.ch translation, source language, published salary, employment type, weekly hours, category, skills and application link |

Duplicates, jobs dropped by the workload filter and expired job URLs are free.

### 📊 Sample Output Data

A job with full details. The description is shortened here, and two of the four workplaces are shown:

```json
{
    "jobId": "58361213-0012-480c-9b23-856f6c756380",
    "url": "https://www.jobs.ch/en/vacancies/detail/58361213-0012-480c-9b23-856f6c756380/",
    "title": "Abacus Consultant (Fokus Wertschöpfung) im Key Customer Team (a) 80% - 100%",
    "titleLocalized": "Abacus Consultant (Focus on Value Creation) in the Key Customer Team (a) 80% - 100%",
    "companyName": "Axept Business Software AG",
    "companyUrl": "https://www.jobs.ch/en/companies/5d162b71-16f4-40b5-b4bf-8c101926559b-axept-business-software-ag/",
    "workloadMin": 80,
    "workloadMax": 100,
    "place": "St. Gallen",
    "locations": [
        {
            "street": "Heiligkreuzstrasse 5",
            "postalCode": "9008",
            "city": "St. Gallen",
            "cantonCode": "SG",
            "countryCode": "CH",
            "latitude": 47.43609,
            "longitude": 9.39575
        },
        {
            "street": "Kemptpark 12",
            "postalCode": "8310",
            "city": "Kemptthal",
            "cantonCode": "ZH",
            "countryCode": "CH",
            "latitude": 47.45155,
            "longitude": 8.70436
        }
    ],
    "requiredLanguages": [{ "language": "de", "level": 4 }],
    "listingTags": ["quickApply"],
    "publicationDate": "2026-09-22T10:21:54+02:00",
    "publicationEndDate": "2026-10-23",
    "description": "Du kennst Abacus aus der Praxis und möchtest dein Fachwissen künftig in spannenden Kundenprojekten einsetzen? …",
    "descriptionLocalized": "You know Abacus from practical experience and want to apply your expertise in exciting customer projects in the future? …",
    "uiLanguage": "en",
    "sourceOriginalLanguage": "de",
    "detectedLanguage": "de",
    "languageMetadataConflict": false,
    "employmentType": "Permanent position",
    "workHours": "33.6 - 42 hours/week",
    "salaryMin": null,
    "salaryMax": null,
    "salaryCurrency": null,
    "salaryPeriod": null,
    "hiringOrganization": "Axept Business Software AG",
    "category": "Technical / Information Technology / Telecom. / Consultancy / Business Informatics",
    "applicationMethod": "formular",
    "externalApplyUrl": null,
    "detailStatus": "ok",
    "scrapedAt": "2026-09-23T09:27:27.673Z"
}
```

Jobs found by a search also include `searchKeywords`, `searchLocation`, `searchUrl` and `searchMode`. `searchMode` shows how jobs.ch matched the query: `semantic` or `full_text`.

### 📝 Good to Know

- `workHours` is jobs.ch's conversion of the workload percentage to hours, based on a 42-hour week. It is not a contractual figure.
- `companyName` is the advertiser. For recruitment agencies, this may not be the final employer.
- jobs.ch sometimes switches how it matches a search partway through. When that happens, the scraper stops that search instead of mixing two different result lists, and records the reason in the run summary.
- Salary figures are kept exactly as published, per year, month or hour. They are not annualised or adjusted for workload.

Find your next hire or map the Swiss job market with the **Jobs.ch Jobs Scraper** today! 🚀

# Actor input Schema

## `keywords` (type: `string`):

What to search for, in any Swiss language, e.g. `software`, `comptable`, `Pflegefachfrau`, `contabile`.

## `location` (type: `string`):

A Swiss town, canton or region, e.g. `Zürich`, `Genève`, `Ticino`. Leave empty to search all of Switzerland. Jobs with several workplaces appear if any of them matches, and every workplace is kept in `locations`.

## `workloadMin` (type: `integer`):

Pensum filter, e.g. 40 for part-time jobs from 40%. jobs.ch matches any job whose offered range overlaps your range (a 60–100% job matches 40–60%).

## `workloadMax` (type: `integer`):

Pensum filter, e.g. 60 for jobs up to 60%.

## `workloadFullyInRange` (type: `boolean`):

Keep only jobs whose entire offered range lies inside your minimum and maximum (a 60–100% job is dropped for 40–60%). Dropped jobs are not charged and are counted in the run summary.

## `language` (type: `string`):

The original advert text is always saved as written. With full details on, adverts written in another language also get jobs.ch's own translation into this language in `titleLocalized` / `descriptionLocalized`.

## `startUrls` (type: `array`):

Search pages copied from your browser (with any filters applied on the site), category pages such as `https://www.jobs.ch/en/vacancies/information-technology-telecom/`, or single job pages like `https://www.jobs.ch/en/vacancies/detail/58361213-0012-480c-9b23-856f6c756380/`. The workload inputs above apply only to the keyword search.

## `scrapeDetails` (type: `boolean`):

Open every job and add the full original advert text, jobs.ch's translation with the source language, published salary (only when the advertiser states one), employment type, weekly hours, industry, category, skills, application method and link, and closing date. Charged as a job detail instead of a job listing. Job page URLs always include full details.

## `maxItems` (type: `integer`):

Maximum number of jobs to save.

## `proxyConfiguration` (type: `object`):

Proxy used to reach jobs.ch. The default works for most runs.

## Actor input object example

```json
{
  "keywords": "software",
  "location": "Zürich",
  "workloadFullyInRange": false,
  "language": "en",
  "scrapeDetails": false,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": "software",
    "location": "Zürich",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("piotrv1001/jobs-ch-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": "software",
    "location": "Zürich",
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("piotrv1001/jobs-ch-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": "software",
  "location": "Zürich",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call piotrv1001/jobs-ch-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,piotrv1001/jobs-ch-jobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ztIKO1o6c1lev3jT1/builds/f4ia5b27mIALSfaPI/openapi.json
