# Jobs.ch Scraper - Swiss Job Board (`parsebird/jobs-ch-scraper`) Actor

Scrape job listings from Jobs.ch: search by keyword, location, or canton, paste a pre-filtered search URL, or check specific job URLs. Full descriptions, contacts, and company data. Export JSON, CSV, Excel.

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

## Pricing

from $2.20 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Jobs.ch Scraper - Swiss Job Board

Jobs.ch Scraper extracts job listings from [Jobs.ch](https://www.jobs.ch), Switzerland's largest job board: full descriptions, requirements, contacts, salary ranges, and company profile data — filtered by keyword, canton, or location.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">Paste a jobs.ch search URL, search by keyword and canton, or re-check specific job URLs for still-alive status — with strict canton filtering and full contact/company enrichment on every listing.</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
parsebird/jobs-ch-scraper on Apify. Call: ApifyClient("TOKEN").actor("parsebird/jobs-ch-scraper").call(run_input={"searchQueries":["Software Engineer"],"locations":["Zurich"],"maxResultsPerQuery":50}), then client.dataset(run["defaultDatasetId"]).list_items().items for results. Three modes: startUrls (array of pasted jobs.ch search URLs — filters extracted automatically), directUrls (array of job detail URLs — still-alive checks, returns job_status), or searchQueries + locations/cantons (array combinations, deduplicated by job ID). Key inputs: language (de|fr|en), maxResultsPerQuery, maxResults (0=unlimited), employmentType (permanent|temporary|freelance), workloadMin/workloadMax (0-100, strictly bounds the job's own posted range), publicationDate (1|3|7|30 days), companyFilter (all|exclude-hr|only-hr), includeJobDetails (boolean, full description/contacts/company data vs a fast title-only pass), maxConcurrency (1-50). Output rows include title, company, location, canton, employment_type, workload_min/max, description_full, requirements, contact_firstname/lastname/email/phone, apply_url/apply_email, company_website/rating/review_count/benefits, posted_at, source_url. Full actor spec: GET https://api.apify.com/v2/acts/parsebird~jobs-ch-scraper (Bearer TOKEN). Get token: https://console.apify.com/account/integrations
```

### What is Jobs.ch Scraper?

Jobs.ch Scraper is an [Apify Actor](https://apify.com/actors) for extracting structured listing data from [Jobs.ch](https://www.jobs.ch), the largest job board in Switzerland, covering German-, French-, and English-language postings across all 26 cantons. Point it at a search URL, a set of keywords and cantons, or a list of specific job URLs, and it returns clean structured rows — title, company, location, full description, contacts, and company profile data.

Use it as a **Jobs.ch API alternative**, a **Swiss job market research tool**, or a repeatable pipeline for recruiting, lead generation, or labor-market analysis. Results download as JSON, CSV, Excel, XML, or HTML, or you can fetch them programmatically through the [Apify API](https://docs.apify.com/api/v2).

### What can Jobs.ch Scraper do?

- 🔗 **Start URL mode** — paste any jobs.ch search URL and every filter in it (keywords, locations, categories, employment type, workload) is extracted automatically
- 🔎 **Search mode** — combine keywords × locations × cantons; every combination runs as its own search, deduplicated by job ID
- ♻️ **Direct URL mode** — re-check specific job URLs and get back `online`, `offline`, or `expired` status, ideal for periodic "still alive" checks
- 🗺️ **Strict canton filtering** — each selected canton gets its own result quota, and every job is confirmed to actually be in that canton before it's returned
- 📋 **Full detail enrichment** — description, requirements, contact person, application links, salary text, and company profile (website, employee count, rating, reviews, benefits)
- 🏢 **HR agency filter** — include or exclude recruitment-agency postings to focus on direct employers
- ⏱️ **Publication-date filter** — pull only jobs posted in the last 1/3/7/30 days for daily scheduled monitoring
- ⚙️ **Fast mode** — turn off full details for a cheap, quick title/company/location-only pass
- 🔌 Run on demand, schedule recurring runs, or connect results to [Apify integrations](https://apify.com/integrations) like Google Sheets, Zapier, Make, and webhooks

### What data can you extract from Jobs.ch?

| Field | Description |
|-------|-------------|
| `title`, `company`, `location`, `canton` | Core listing identity, with canton resolved and verified |
| `employment_type`, `workload_min`, `workload_max` | Contract type and Pensum (workload) percentage range |
| `description_full`, `requirements` | Full job description and an extracted requirements list |
| `contact_firstname`, `contact_lastname`, `contact_email`, `contact_phone` | Hiring contact, when published |
| `apply_url`, `apply_email` | Where the application actually goes |
| `company_website`, `company_employee_count`, `company_rating`, `company_benefits` | Company profile enrichment |
| `posted_at`, `expires_at` | Publication and expiry dates |
| `job_status` | `online` / `offline` / `expired` — Direct URL mode only |

### Input parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `startUrls` | array of strings | `[]` | Pre-filtered jobs.ch search URLs — filters extracted from the URL |
| `directUrls` | array of strings | `[]` | Direct job URLs to check (still-alive mode) |
| `companyNames` | array of strings | `[]` | Company names to search for |
| `searchQueries` | array of strings | `["Software Engineer"]` | Keywords to search |
| `locations` | array of strings | `[]` (all Switzerland) | City/region names, e.g. `Zurich`, `Basel` |
| `cantons` | array of strings | `[]` (all cantons) | Canton codes, e.g. `ZH`, `BE`, `AG` |
| `language` | string | `de` | `de`, `fr`, or `en` |
| `maxResultsPerQuery` | integer | `100` | Cap per keyword/location/canton combination |
| `maxResults` | integer | `0` | Total cap across all queries. `0` = unlimited |
| `employmentType` | string | `""` (all) | `permanent`, `temporary`, or `freelance` |
| `workloadMin` / `workloadMax` | integer | — | Workload / Pensum percentage (0-100) |
| `publicationDate` | string | `""` (any time) | `1`, `3`, `7`, or `30` days |
| `searchMode` | string | `semantic` | `semantic` (AI-powered) or `classic` (keyword matching) |
| `includeJobDetails` | boolean | `true` | Fetch full descriptions, contacts, and company data |
| `maxConcurrency` | integer | `10` | Parallel detail-page workers (1-50) |
| `companyFilter` | string | `all` | `all`, `exclude-hr`, or `only-hr` |
| `proxyConfiguration` | object | Datacenter | Apify proxy settings — datacenter is sufficient |

#### Mode 1: Start URL (easiest)

Configure your search on jobs.ch with every filter you want, copy the URL from your browser, and paste it here:

```json
{
  "startUrls": [
    "https://www.jobs.ch/de/stellenangebote/?term=javascript&location=st.%20gallen&location=z%C3%BCrich&category=171&category=174&employment-type=5&employment-grade-min=50&employment-grade-max=100"
  ],
  "maxResults": 100
}
```

Combine multiple search URLs to scrape different filter combinations in one run:

```json
{
  "startUrls": [
    "https://www.jobs.ch/de/stellenangebote/?term=Software+Engineer&location=z%C3%BCrich",
    "https://www.jobs.ch/fr/offres-emplois/?term=Developpeur&location=gen%C3%A8ve"
  ],
  "maxResults": 200
}
```

#### Mode 2: Search (multi-query)

Search multiple keywords, locations, and cantons at once — every combination runs as its own search, and results are deduplicated:

```json
{
  "searchQueries": ["Software Engineer", "Softwareentwickler", "Backend Developer"],
  "locations": ["Zurich", "Basel"],
  "maxResultsPerQuery": 100,
  "maxResults": 0
}
```

With `includeJobDetails: true` (default), full descriptions, requirements, and contact details are fetched:

```json
{
  "searchQueries": ["Data Scientist", "Machine Learning"],
  "cantons": ["ZH", "BE", "BS"],
  "maxResultsPerQuery": 100,
  "includeJobDetails": true
}
```

Every selected canton gets its own quota — with `maxResultsPerQuery: 20` and 3 cantons, you get up to 20 jobs per canton (60 total), each one confirmed to actually be in that canton.

#### Mode 3: Direct URLs (still-alive checks)

When `directUrls` is set, the actor skips search entirely, visits each URL directly, and returns `job_status` (`online`, `offline`, or `expired`) plus full data if the job is still available — ideal for periodic re-checks after deduplication:

```json
{
  "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/"
  ]
}
```

#### More examples

**Part-time jobs in Basel (40-60% workload):**

```json
{
  "searchQueries": ["Buchhaltung"],
  "locations": ["Basel"],
  "workloadMin": 40,
  "workloadMax": 60,
  "maxResultsPerQuery": 50
}
```

**French-speaking region search:**

```json
{
  "searchQueries": ["Infirmier", "Aide-soignant"],
  "cantons": ["VD"],
  "language": "fr",
  "maxResultsPerQuery": 100
}
```

**Direct employer postings only (no HR agencies):**

```json
{
  "searchQueries": ["Marketing Manager"],
  "locations": ["Zurich"],
  "companyFilter": "exclude-hr",
  "maxResultsPerQuery": 100
}
```

**Daily scrape — only new listings from the last 24 hours:**

```json
{
  "searchQueries": ["Software Engineer"],
  "locations": ["Zurich"],
  "publicationDate": "1",
  "maxResultsPerQuery": 100
}
```

The date filter also works in Start URL mode — just include `publication-date=N` in the pasted URL.

### Output example

```json
{
  "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",
  "employment_type": "full-time",
  "workload_min": 80,
  "workload_max": 90,
  "description_snippet": "Fuer unseren Bereich in der Kinder- und Jugendpsychiatrie...",
  "requirements": ["Erfahrung im Bereich der Kinder- und Jugendpsychiatrie", "Offene, kommunikative Persoenlichkeit"],
  "posted_at": "2025-12-10T15:36:17.000Z",
  "source_url": "https://www.jobs.ch/de/stellenangebote/detail/b475b944-eab5-4d69-b251-a325bd272d62/",
  "source_platform": "jobs.ch",
  "contact_firstname": "Irene",
  "contact_lastname": "Walczewski",
  "contact_phone": "+41 44 929 83 73",
  "company_url": "https://www.jobs.ch/de/firmen/23141-clienia-schlossli-ag/",
  "company_website": "https://www.clienia.ch/de/",
  "company_employee_count": "501 - 1000 employees",
  "company_job_count": 21,
  "company_rating": 2.5,
  "company_review_count": 8,
  "company_benefits": ["5 Wochen Ferien", "Attraktive Arbeitszeitformen", "Foerderung von Fort- und Weiterbildungen"],
  "search_query": "Pflegefachperson",
  "scraped_at": "2026-08-17T14:16:53.609Z"
}
```

`job_status` is only populated in Direct URL mode — search-mode results are assumed online since they just came from live search results.

Download in JSON, HTML, CSV, or Excel from the dataset page, or fetch rows programmatically through the API.

### How to scrape Jobs.ch listings

1. Open Jobs.ch Scraper on Apify and click **Try for free**.
2. Pick a mode: paste a search URL, enter keywords/locations/cantons, or paste direct job URLs.
3. Set `maxResultsPerQuery` and `maxResults` to control run size and cost.
4. Start the run and wait for the dataset to populate.
5. Download results as JSON, CSV, Excel, HTML, XML, or RSS.
6. Automate it with [Apify scheduling](https://docs.apify.com/platform/schedules), [integrations](https://apify.com/integrations), or the [Apify API](https://docs.apify.com/api/v2).

### How to use the Jobs.ch API in Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("parsebird/jobs-ch-scraper").call(run_input={
    "searchQueries": ["Data Scientist", "Machine Learning"],
    "cantons": ["ZH", "BE", "BS"],
    "maxResultsPerQuery": 100,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items[:2])
```

### How to use the Jobs.ch API in JavaScript

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('parsebird/jobs-ch-scraper').call({
    searchQueries: ['Software Engineer'],
    locations: ['Zurich', 'Basel'],
    maxResultsPerQuery: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use cases

- **Recruiting & sourcing** — Pull direct-employer listings (excluding HR agencies) for a specific role and region
- **Labor market research** — Compare workload, salary, and remote-work patterns across cantons
- **Lead generation** — Extract company websites, industries, and hiring contacts from active job postings
- **Competitive monitoring** — Track which roles a specific company is hiring for, canton by canton
- **Daily job alerts** — Schedule a run with `publicationDate: "1"` to catch only new listings each day
- **Link health monitoring** — Use Direct URL mode to periodically re-check whether saved job links are still live

### How it works

1. Resolves your input into one of three modes: pasted search URLs, keyword/location/canton combinations, or direct job URLs
2. Calls jobs.ch's public search API and paginates through results
3. Applies canton, location, workload, publication-date, and HR-agency filters locally — since jobs.ch's own PLZ/canton and workload data is richer than what the search API filters strictly enforce
4. Deduplicates by job ID across every query combination in the run
5. Optionally fetches each job's detail page and parses its full description, requirements, contacts, and company profile
6. Pushes normalized rows to the dataset and stops once your spending limit is reached

### How much does it cost to scrape Jobs.ch?

Jobs.ch Scraper uses pay-per-event pricing, with two events depending on how much data you request per job.

| Event | What it covers | Price per 1,000 |
|-------|-----------------|-----------------|
| `job-search` | A search-result row (title, company, location, dates) — used when `includeJobDetails` is off | **$2.50 / $2.40 / $2.30 / $2.20** (Free / Bronze / Silver / Gold) |
| `job-detail` | A complete listing with full description, contacts, and company data — used when `includeJobDetails` is on (default) | **$4.50 / $4.40 / $4.30 / $4.20** (Free / Bronze / Silver / Gold) |

Scraping 100 fully-enriched jobs costs about $0.45 on the Free plan; the same 100 jobs without details costs about $0.25. Apify's free trial credits cover typical test runs.

### Is it legal to scrape Jobs.ch?

Jobs.ch Scraper extracts publicly available job listing data from the same public search endpoint jobs.ch's own website uses to render search results and job pages. Scraping publicly accessible data is generally lawful, but you're responsible for how you use the results — always review [jobs.ch's Terms of Use](https://www.jobcloud.ch/c/de-ch/agb/#use-of-services) and Apify's guide on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) before running large or automated workloads.

### Related job board scrapers

| Actor | Best for |
|-------|----------|
| [Arbeitsagentur Scraper](https://apify.com/parsebird/arbeitsagentur-scraper) | Germany's federal job board, useful alongside German-speaking Swiss searches |
| [HelloWork Jobs Scraper](https://apify.com/parsebird/hellowork-jobs-scraper) | French job listings, useful alongside French-speaking Swiss (Romandie) searches |
| [Greenhouse Jobs Scraper](https://apify.com/parsebird/greenhouse-jobs-scraper) | Company career pages running on the Greenhouse ATS |

### FAQ

**How does canton filtering actually work?**
Each selected canton in `cantons` gets its own result quota (`maxResultsPerQuery` per canton). The actor resolves each job's canton from jobs.ch's own location data and only returns jobs confirmed to be in a selected canton — no guessing from city names alone.

**What's the difference between `locations` and `cantons`?**
`locations` matches a job's city/place name (e.g. "Zurich" matches both "Zürich" and "Zurich"). `cantons` matches the canton code directly (e.g. "ZH"). Use whichever fits your search — both can be combined with keywords.

**Why does `workloadMax` sometimes exclude a job with a wide workload range?**
If a job is posted as "50-100%", it genuinely doesn't fit a `workloadMax: 60` (up to 60%) request — the actor strictly bounds the job's own posted range to your requested window, rather than returning any job that merely overlaps it.

**What happens if a company doesn't publish a direct contact or email?**
Those fields come back `null`. Not every jobs.ch listing publishes a named contact, phone number, or email — the actor never fabricates one.

**Can I re-check jobs I've already scraped without re-running search?**
Yes — that's exactly what Direct URL mode is for. Pass the job URLs you already have in `directUrls` and get back `job_status` (`online`, `offline`, `expired`) for each.

**Can I schedule recurring runs?**
Yes. Use [Apify scheduling](https://docs.apify.com/platform/schedules) to run daily or weekly — pair it with `publicationDate: "1"` for a clean "what's new today" feed.

**How do I report a problem or request a field?**
Open an issue from the Actor page in Apify Console and include the run ID, input, and the job URL that needs review.

# Actor input Schema

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

Pre-filtered jobs.ch search URLs, copied straight from your browser. All filters in the URL (keywords, locations, categories, employment type, workload) are extracted automatically.

## `directUrls` (type: `array`):

Specific jobs.ch job detail URLs to check. Skips search entirely and returns each job's status (online, offline, expired) plus full data if still available. Useful for periodic "still alive" checks.

## `searchQueries` (type: `array`):

One or more keywords to search. Used when Start URLs and Direct URLs are both empty. Leave empty (single blank entry) to browse by location/canton only.

## `companyNames` (type: `array`):

Company names to search for, in addition to (or instead of) keyword search. Each name is searched and results are confirmed to actually mention that company.

## `locations` (type: `array`):

City or region names, e.g. Zurich, Basel. Leave empty to search all of Switzerland.

## `cantons` (type: `array`):

Swiss canton codes. Each selected canton gets its own result quota (Max results per query applies per canton). Results are strictly filtered to jobs confirmed to be in a selected canton.

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

Search UI language. Sets which language-specific jobs.ch URLs are returned; jobs in all languages still match your search.

## `maxResultsPerQuery` (type: `integer`):

Maximum results per keyword/location/canton combination.

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

Hard cap across all queries combined. 0 = unlimited (bounded only by maxResultsPerQuery per combination).

## `employmentType` (type: `string`):

Filter by contract type.

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

Minimum workload / Pensum percentage.

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

Maximum workload / Pensum percentage.

## `publicationDate` (type: `string`):

Only return jobs posted within this window. Ideal for daily scheduled runs that only want new listings.

## `searchMode` (type: `string`):

semantic uses jobs.ch's AI-powered relevance ranking; classic uses plain keyword matching.

## `companyFilter` (type: `string`):

Filter results by whether the poster looks like an HR/recruitment agency (matched by company name).

## `includeJobDetails` (type: `boolean`):

Fetch each job's detail page for the full description, requirements, contacts, and company data. Turn off for a fast, cheap title/company/location-only pass.

## `maxConcurrency` (type: `integer`):

Parallel detail-page workers.

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

Datacenter proxy is sufficient for jobs.ch.

## Actor input object example

```json
{
  "startUrls": [],
  "directUrls": [],
  "searchQueries": [
    "Software Engineer"
  ],
  "companyNames": [],
  "locations": [],
  "cantons": [],
  "language": "de",
  "maxResultsPerQuery": 20,
  "maxResults": 20,
  "employmentType": "",
  "publicationDate": "",
  "searchMode": "semantic",
  "companyFilter": "all",
  "includeJobDetails": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "startUrls": [],
    "directUrls": [],
    "searchQueries": [
        "Software Engineer"
    ],
    "companyNames": [],
    "locations": [],
    "cantons": [],
    "language": "de",
    "maxResultsPerQuery": 20,
    "maxResults": 20,
    "searchMode": "semantic",
    "includeJobDetails": true,
    "maxConcurrency": 5,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/jobs-ch-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 = {
    "startUrls": [],
    "directUrls": [],
    "searchQueries": ["Software Engineer"],
    "companyNames": [],
    "locations": [],
    "cantons": [],
    "language": "de",
    "maxResultsPerQuery": 20,
    "maxResults": 20,
    "searchMode": "semantic",
    "includeJobDetails": True,
    "maxConcurrency": 5,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/jobs-ch-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 '{
  "startUrls": [],
  "directUrls": [],
  "searchQueries": [
    "Software Engineer"
  ],
  "companyNames": [],
  "locations": [],
  "cantons": [],
  "language": "de",
  "maxResultsPerQuery": 20,
  "maxResults": 20,
  "searchMode": "semantic",
  "includeJobDetails": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call parsebird/jobs-ch-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/jobs-ch-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/pfSdWns7zBIiXy1yh/builds/f5qEUiLkRYxhzVHaW/openapi.json
