# jobs.ch Advert Details, With the Salary Named as an Estimate (`gubidonius/jobsch-job-details`) Actor

The full text of a jobs.ch advert with its start date, workload, apply link and industry. jobs.ch puts its own salary model into the field schema.org reserves for the employer's pay, so this Actor publishes that number as an estimate and says so on every row.

- **URL**: https://apify.com/gubidonius/jobsch-job-details.md
- **Developed by:** [Gregory Bolshakov](https://apify.com/gubidonius) (community)
- **Categories:** Jobs, Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 1,000 advert returneds

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 advert details

The full text of a jobs.ch advert, with the start date, weekly hours, apply link, industry and
employer website.

Give it advert URLs or bare advert ids. On jobs.ch an advert opens on its uuid alone, so
`a6a10b48-c5ce-4392-93ba-0aefae34d436` works as well as the whole URL. Feed it the `jobId` or
`url` column from jobsch-jobs.

### Two numbers on this source mean something other than their name

This is why the Actor exists, and both were found by running it, not by reading the docs.

**The salary is not the employer's pay.** schema.org keeps a field called `baseSalary` for the
salary actually offered. jobs.ch puts its own estimate in it, and writes the identical numbers
a second time in the field meant for estimates. The site's own wording says the figure is
calculated for a 100 percent workload in the canton. Only 1 advert in 14 carries any figure at
all.

So it is published here as `salaryEstimateMin` and `salaryEstimateMax`, with
`salaryIsEmployerPublished` set to false on every row and a sentence saying where the number
came from. No row will ever tell you an employer offered that money.

**The opening count is the company's advert count.** schema.org defines `totalJobOpenings` as
the positions open for this advert. Two different Lonza Group adverts both report 15, and
Lonza's own jobs.ch page is titled "15 job offers on jobs.ch". ROOMZ SA reports 1 and its page
says "1 job vacancy".

So the column is called `companyAdvertsOnJobsCh`. There is also `openingsForThisAdvert`, and it
is null on every row, because jobs.ch publishes no such number anywhere. You get an honest null
instead of a wrong number.

### The advert text

The advert page carries the real text the employer wrote, and this Actor returns it in
`description` with the paragraph breaks kept, and in `descriptionHtml` with the markup.

Do not confuse it with what a jobs.ch search page carries. There the same field holds a
sentence built from the title, like "We are looking for a Equipment Engineer to join our
team." That is not an advert and it is never published by this Actor or by jobsch-jobs.

### The place of work

An advert page keeps the workplace in a different field from the search page, and it is the
same comma joined line with the same problem. "Bern, Fribourg, Neuchatel" is three places.
"Zurich, Zurich, Schweiz" is one place with its canton and country. "Neuwiesenstrasse 15, 8400
Winterthur" is a street address.

You get `placeOfWorkLabel` exactly as written, and the comma separated parts named as parts of
a label. Nothing here invents a town.

### Adverts that have gone

A well formed advert id that is no longer live answers 404. That is a fact about the advert,
not a failure. It goes into `advertsGone` in the run summary with the reason, it costs you
nothing, and the run still finishes.

Duplicates in your own list are dropped before anything is fetched, so the same advert listed
as a URL and as a bare id is one request and one charge.

### Cost

Both events cost 0.00001 USD. One request per advert, no second fetch for any field. You are
charged after rows are written.

Run jobsch-jobs first and send only the adverts worth the full text. The search already gives
you the title, company, place, workload, contract type and exact date.

All measurements here are from 13 September 2026.

# Actor input Schema

## `jobs` (type: `array`):

Advert URLs or bare advert ids. A jobs.ch advert opens on its uuid alone, so https://www.jobs.ch/en/vacancies/detail/a6a10b48-c5ce-4392-93ba-0aefae34d436/ and a6a10b48-c5ce-4392-93ba-0aefae34d436 both work. Feed this the jobId or url column from jobsch-jobs. An entry with no uuid in it is reported with the reason rather than guessed at.

## `maxResults` (type: `integer`):

How many adverts to return at most, and the most you will be charged for. Duplicates in your own list are dropped before anything is fetched, so the same advert never uses two slots.

## Actor input object example

```json
{
  "jobs": [
    "https://www.jobs.ch/en/vacancies/detail/a6a10b48-c5ce-4392-93ba-0aefae34d436/"
  ],
  "maxResults": 100
}
```

# Actor output Schema

## `results` (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 = {
    "jobs": [
        "https://www.jobs.ch/en/vacancies/detail/a6a10b48-c5ce-4392-93ba-0aefae34d436/"
    ],
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("gubidonius/jobsch-job-details").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 = {
    "jobs": ["https://www.jobs.ch/en/vacancies/detail/a6a10b48-c5ce-4392-93ba-0aefae34d436/"],
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("gubidonius/jobsch-job-details").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 '{
  "jobs": [
    "https://www.jobs.ch/en/vacancies/detail/a6a10b48-c5ce-4392-93ba-0aefae34d436/"
  ],
  "maxResults": 100
}' |
apify call gubidonius/jobsch-job-details --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gubidonius/jobsch-job-details"
        }
    }
}
```

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/PZR8ctLYxegnTTGO0/builds/zr1kaKyMRYiesygnX/openapi.json
