# Jobup.ch Scraper - Swiss Job Board (`parsebird/jobup-ch-scraper`) Actor

Scrape jobs from jobup.ch: search by keyword, location, workload, and employment type, or paste a filtered search URL. Full descriptions, apply links, company data, and incremental change tracking. Export JSON, CSV, Excel.

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

## Pricing

from $0.79 / 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/actors/running/actors-in-store.md#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

### Jobup.ch Scraper

Scrape job listings from **[jobup.ch](https://www.jobup.ch/)**, the leading job board for French‑speaking Switzerland. The **Jobup.ch Scraper** turns any keyword, location, or filtered search URL into a clean, structured dataset — full descriptions, apply links, workload percentages, employment type, company data, and publication dates — ready for analysis, monitoring, or integration.

<table><tr>
<td style="border-left:4px solid #0A6CFF;padding:12px 16px;font-weight:600">
Search jobup.ch by keyword and location, filter by workload, employment type, and staffing agency, fetch full job descriptions and apply URLs, and track new, updated, and expired postings across scheduled runs.
</td>
</tr></table>

##### Copy to your AI assistant

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

```
Actor: parsebird/jobup-ch-scraper (Apify) — scrapes job listings from jobup.ch (Swiss job board).
Call it with the Apify API / ApifyClient. Example input:
{
  "query": "software engineer",      // keywords, max 128 chars, all must match the same job
  "queries": ["comptable", "controlleur de gestion"], // OR: one title per entry, searched separately + merged
  "location": "Genève",              // city, canton, region, or postal code
  "language": "en",                  // "en" or "fr" (job descriptions stay in their original language)
  "sortBy": "date",                  // "relevance" | "date" | "random"
  "employmentType": "permanent",     // "" | permanent | temporary | freelance | internship | apprenticeship | side-job
  "workloadMin": 80, "workloadMax": 100, // keep only jobs offering >=80% workload
  "companyFilter": "exclude-agencies",   // all | exclude-agencies | only-agencies
  "publishedSinceDays": 7,
  "maxResults": 100,
  "includeDetails": true,            // fetch full description, apply URL, address, end date
  "compact": false,                  // true = core fields only, for LLM/MCP pipelines
  "incrementalMode": false, "stateKey": "sw-eng-geneva" // change feed across runs
}
Also accepts "startUrls": ["https://www.jobup.ch/en/jobs/?term=nurse&location=Vaud&sort=date"] or individual job-detail URLs.
Output: one record per job — id, title, company, companyId, place, zipcode, canton, employmentGrades [min,max],
employmentTypes, categories, description, descriptionHtml, applyUrl, applicationMethod, isPaid,
initialPublicationDate, publicationDate, publicationEndDate, url, source. Incremental mode adds
changeType (NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED), isRepost, repostOfId.
Pricing: pay-per-result, from $0.79 to $0.99 per 1,000 jobs. API docs: https://docs.apify.com/api/v2
```

### What does the Jobup.ch Scraper do?

The **Jobup.ch Scraper** extracts structured data from jobup.ch without touching an official API. Use it to:

- 🔍 **Search by keyword** — every keyword in one search must match the same job, so use the *Several job titles* input to search a list of alternative titles and merge the results.
- 📍 **Filter by location** — city, canton, region, or postal code (e.g. Genève, Vaud, Lausanne, 1200).
- 🧰 **Filter by workload and employment type** — keep only full‑time‑friendly roles (≥80%), only part‑time roles (≤60%), or a specific contract type: permanent, temporary, freelance, internship, apprenticeship, side job.
- 🏢 **Skip staffing agencies** — one toggle removes reposts from Adecco, Manpower, Randstad, Hays, and similar recruiters, so you see only direct employers.
- 📄 **Fetch full job details** — complete description (plain text and HTML), apply URL, application method, street address, and publication end date.
- 🔗 **Paste search URLs** — copy a filtered jobup.ch results URL straight from your browser, or drop in individual job‑detail URLs.
- 🔁 **Track changes over time** — incremental mode annotates every record with a `changeType` (NEW, UPDATED, UNCHANGED, REAPPEARED, EXPIRED) and flags reposted listings, turning a scheduled run into a job‑change feed.
- 🤖 **Feed AI agents** — compact output mode returns core fields only, ideal for LLM and MCP pipelines without token overhead.

It is a practical **jobup.ch API alternative** for recruiters, job aggregators, labour‑market researchers, and relocation services that need Swiss job data at scale.

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `query` | string | No | — | Job search keywords (max 128 characters). Every keyword must match the same job. |
| `queries` | array | No | `[]` | One job title per entry — each searched separately, results merged and de‑duplicated. Ignored when `startUrls` is set. |
| `startUrls` | array | No | `[]` | jobup.ch search‑result URLs (filters in the URL are respected) or individual job‑detail URLs. |
| `country` | string | No | `CH` | Market to search. jobup.ch lists Swiss jobs only. |
| `location` | string | No | — | City, canton, region, or postal code. |
| `language` | string | No | `en` | `en` or `fr`. Controls the job URL locale and platform‑rendered text; descriptions stay in their original language. |
| `sortBy` | string | No | `relevance` | `relevance`, `date` (newest first), or `random`. |
| `employmentType` | string | No | `""` | `permanent`, `temporary`, `freelance`, `internship`, `apprenticeship`, or `side-job`. |
| `workloadMin` | integer | No | `0` | Drop jobs whose maximum offered workload is below this percentage. |
| `workloadMax` | integer | No | `100` | Drop jobs whose minimum required workload is above this percentage. |
| `companyFilter` | string | No | `all` | `all`, `exclude-agencies`, or `only-agencies`. |
| `publishedSinceDays` | integer | No | `0` | Only jobs first published within this many days. `0` = no limit. |
| `maxResults` | integer | No | `25` | Maximum total results. `0` = unlimited (required for reliable expired‑job detection). |
| `maxResultsPerQuery` | integer | No | `0` | Per‑keyword / per‑URL cap. The public API returns at most 2,000 results per search. |
| `includeDetails` | boolean | No | `true` | Fetch each job's detail page for the full description, apply URL, address, and end date. |
| `descriptionFormat` | string | No | `both` | `text`, `html`, or `both`. |
| `compact` | boolean | No | `false` | Emit core fields only. |
| `excludeEmptyFields` | boolean | No | `false` | Remove null / empty values from each record. |
| `incrementalMode` | boolean | No | `false` | Compare against the previous run stored under `stateKey`. |
| `stateKey` | string | No | — | Identifier for the tracked search state. Required when `incrementalMode` is on. |
| `emitUnchanged` | boolean | No | `false` | Also output records that did not change. |
| `emitExpired` | boolean | No | `false` | Also output a minimal record for jobs no longer found (requires `maxResults` = 0). |
| `skipReposts` | boolean | No | `false` | Drop new listings whose content matches a previously expired job. |
| `maxConcurrency` | integer | No | `8` | Maximum parallel detail‑page requests. |
| `proxyConfiguration` | object | No | Apify Proxy | Proxy settings. Datacenter proxy is sufficient for jobup.ch. |

#### Input examples

**Basic search** — keyword‑driven search with a result cap:

```json
{
  "query": "software engineer",
  "maxResults": 50
}
```

**Several job titles + location** — each title searched separately, results merged:

```json
{
  "queries": ["comptable", "aide-comptable", "responsable comptabilité"],
  "location": "Genève",
  "companyFilter": "exclude-agencies",
  "maxResults": 200
}
```

**Incremental tracking** — only emit jobs that changed since the previous run:

```json
{
  "query": "infirmier",
  "location": "Vaud",
  "maxResults": 0,
  "incrementalMode": true,
  "stateKey": "infirmier-vaud-tracker"
}
```

**Compact output for AI agents** — core fields only:

```json
{
  "query": "data scientist",
  "employmentType": "permanent",
  "maxResults": 50,
  "compact": true
}
```

### Output example

```json
{
  "jobId": "109b5e98b40dac8b25d80e8d7763d1a147ab0d6419ac6e3524ee3c9ae4c11c1c",
  "id": "a9ed2520-06af-48b9-9316-63c17e389cb2",
  "title": "Développeur C# / Vue.js Full Stack Senior (H/F)",
  "synonym": "C Developer",
  "company": "Data Consulting S.A.",
  "companyId": "5e39cc7f-8f78-4065-be5d-b5005f23fca7",
  "companyLogo": "https://media.jobs.ch/media/921a0699-4751-4a33-92a9-c01a879cda67",
  "place": "Lausanne",
  "street": "Chemin d'Entre-Bois 25",
  "zipcode": "1018",
  "canton": "VD",
  "country": "CH",
  "coordinates": { "lat": 46.53884, "lon": 6.63165 },
  "employmentGrades": [100, 100],
  "employmentTypes": ["Permanent position"],
  "employmentTypeIds": ["5"],
  "categories": ["/702/707"],
  "regions": ["/52/55"],
  "description": "Éditeur et distributeur de solution ERP pour les administrations communales, Data Consulting recherche : Développeur C# / Vue.js Full Stack Senior (H/F)...",
  "descriptionHtml": "<p>Éditeur et distributeur de solution ERP pour les administrations communales, <strong>Data Consulting</strong> recherche :</p> ...",
  "skills": ["C#", "Vue.js"],
  "contacts": [{ "firstName": "Michael", "lastName": "Magnin" }],
  "applyUrl": "https://www.jobup.ch/en/jobs/detail/a9ed2520-06af-48b9-9316-63c17e389cb2/",
  "applicationMethod": "APPLICATION_METHOD.FORMULAR",
  "isNew": false,
  "isPaid": true,
  "isActive": true,
  "initialPublicationDate": "2026-08-04T16:41:19+00:00",
  "publicationDate": "2026-08-04T18:41:19+02:00",
  "publicationEndDate": "2026-09-18",
  "url": "https://www.jobup.ch/en/jobs/detail/a9ed2520-06af-48b9-9316-63c17e389cb2/",
  "portalUrl": "https://www.jobup.ch/en/jobs/detail/a9ed2520-06af-48b9-9316-63c17e389cb2/",
  "scrapedAt": "2026-09-07T14:19:16.462Z",
  "source": "jobup.ch"
}
```

In incremental mode each record also carries `changeType` (`NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, or `EXPIRED`), plus `isRepost`, `repostOfId`, and `repostDetectedAt` when a new listing matches the tracked content of a previously expired one.

Download the dataset as **JSON, CSV, Excel, HTML, or RSS** from the Console or via the [Apify API](https://docs.apify.com/api/v2).

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

| Field | Description |
|-------|-------------|
| `title` | Job title as published |
| `synonym` | Normalised job‑title synonym jobup.ch maps the posting to |
| `company` / `companyId` | Employer name and jobup.ch company ID |
| `place` / `street` / `zipcode` / `canton` | Work location |
| `coordinates` | Latitude / longitude of the workplace |
| `employmentGrades` | `[min, max]` workload percentage offered |
| `employmentTypes` / `employmentTypeIds` | Permanent, temporary, freelance, internship, apprenticeship, side job |
| `categories` / `regions` | jobup.ch taxonomy paths |
| `description` / `descriptionHtml` | Full job description, plain text and original HTML |
| `applyUrl` / `applicationMethod` | Where and how to apply |
| `isPaid` / `isNew` / `isActive` | Listing flags |
| `initialPublicationDate` / `publicationDate` / `publicationEndDate` | Posting timeline |
| `url` / `portalUrl` | Canonical jobup.ch job page |

### How to scrape jobup.ch

1. Open the **Jobup.ch Scraper** and click **Try for free**.
2. Enter a keyword in **Search keywords**, or add several alternative titles under **Several job titles**.
3. Optionally set a **Location**, choose an **Employment type**, or set a **workload** range.
4. To reuse a search you already built on the site, copy its URL from your browser and paste it into **Start URLs**.
5. Set **Max results** (start low — 25 or 50 — to preview output cheaply).
6. Click **Start**. When the run finishes, open the **Output** tab and export as JSON, CSV, or Excel.
7. To monitor a search, enable **Incremental change tracking**, set a **State key**, and schedule the actor to run daily or hourly.

### Pricing

This actor uses the **pay‑per‑result** pricing model.

| Event | Price per 1,000 jobs |
|-------|----------------------|
| `job-scraped` (Free tier) | **$0.99** |
| `job-scraped` (Bronze / Silver) | **$0.89** |
| `job-scraped` (Gold) | **$0.79** |

You are charged once per job record written to the dataset. Scraping 1,000 jobs with full details costs about **$0.79–$0.99** depending on your Apify plan. Incremental runs are far cheaper because only changed records are emitted after the first baseline run. Apify's free monthly usage credits apply.

### How it works

1. The actor queries the public jobup.ch search endpoint, paginating through results (up to 2,000 per search).
2. Client‑side filters (workload, staffing agency, publication date) are applied to each result.
3. When **Fetch full job details** is on, each job's detail page is fetched and parsed for the description, apply URL, application method, address, and end date.
4. In incremental mode, each record's tracked content is hashed and compared with the state stored under your **State key** to assign a `changeType`.
5. Records are pushed to the dataset and are immediately available via the Apify API, integrations, and webhooks.

### FAQ

**Is it legal to scrape jobup.ch?**
Scraping publicly available information is legal in most jurisdictions, including the EU and Switzerland. This actor collects only public job postings and does not access private accounts or personal candidate data. You are responsible for how you use the data — in particular, comply with the GDPR / Swiss FADP and jobup.ch's terms. See Apify's guide on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

**Why does my keyword search return nothing?**
jobup.ch requires every keyword in a single search term to match the same job. `Lagerist Maschinenführer` matches no job, while `Lagerist` and `Maschinenführer` each return hundreds. Put alternative titles in the **Several job titles** input instead.

**How many results can I get per search?**
The public jobup.ch API returns at most 2,000 results per search. Split a broad search by location or employment type to go beyond that.

**Does language affect the job descriptions?**
No. `language` controls the job‑page URL locale and platform text only. Employers post descriptions in one language (usually German or French) and that is what you receive.

**Can I get only jobs from direct employers?**
Yes. Set **Company type** to `exclude-agencies` to drop reposts from staffing agencies such as Adecco, Manpower, Randstad, and Hays.

**Can I schedule recurring runs?**
Yes. Use the [Apify Scheduler](https://docs.apify.com/platform/schedules) with **Incremental change tracking** enabled to build a feed of new, updated, and expired jobs.

**How do I call this actor from my code?**
Use the [Apify API](https://docs.apify.com/api/v2) or a client library:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("parsebird/jobup-ch-scraper").call(run_input={
    "query": "software engineer",
    "location": "Genève",
    "maxResults": 100,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["company"], job["url"])
```

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('parsebird/jobup-ch-scraper').call({
    query: 'software engineer',
    location: 'Genève',
    maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((job) => console.log(job.title, job.company, job.url));
```

**Something looks wrong or missing.**
Open an issue on the **Issues** tab. Include your input and the run ID.

### Related Swiss job scrapers

- [Jobs.ch Scraper](https://apify.com/parsebird/jobs-ch-scraper) — the German‑speaking sister board of jobup.ch
- [JobScout24.ch Jobs Scraper](https://apify.com/parsebird/jobscout24-ch-jobs-scraper) — the third JobCloud portal
- [Job-Room.ch Jobs Scraper](https://apify.com/parsebird/job-room-ch-jobs-scraper) — the official Swiss public employment service board
- [Indeed Jobs Scraper](https://apify.com/parsebird/indeed-jobs-scraper) — global job listings including Switzerland

### Legal and compliance

The **Jobup.ch Scraper** collects only publicly accessible job‑posting data from jobup.ch. It does not log in, bypass access controls, or collect personal data about job seekers. You are responsible for ensuring your use of the scraped data complies with applicable laws (including the GDPR and the Swiss Federal Act on Data Protection) and with jobup.ch's terms of use. This actor is not affiliated with, endorsed by, or connected to jobup.ch or JobCloud AG.

# Actor input Schema

## `query` (type: `string`):

Job search keywords (maximum 128 characters). Every keyword in one search must match the same job, so a list of alternative job titles finds nothing — use "Several job titles" below to search for more than one.

## `queries` (type: `array`):

One job title per entry — each is searched separately and the results are merged and de-duplicated. Use this instead of putting synonyms in one search term. Each entry is limited to 128 characters. Ignored when Start URLs are set.

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

Paste jobup.ch search-result URLs (filters in the URL are respected) or individual job-detail URLs. When set, 'query' / 'queries' / 'location' are ignored.

## `country` (type: `string`):

Which market to search. jobup.ch only lists Swiss jobs.

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

City, canton, region, or postal code to search in (e.g. Genève, Vaud, Zurich, 1200). Ignored when Start URLs are set.

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

Sets the jobup.ch content language for platform-rendered text (job titles list, dates) and the job URL locale. Job descriptions are always returned in the language the employer posted them in.

## `sortBy` (type: `string`):

Result ordering. Relevance = best match to the query (default); Date = newest first; Random = randomized order.

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

Filter by employment type.

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

Drops jobs whose maximum offered workload is below this. E.g. 80 keeps only jobs offering at least 80% (full-time-friendly). 0 = no minimum.

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

Drops jobs whose minimum required workload is above this. E.g. 60 keeps only part-time jobs (≤60%). 100 = no maximum.

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

Filter by company type. 'Exclude staffing agencies' skips reposts from Adecco, Manpower, Hays, Randstad, and similar recruiters.

## `publishedSinceDays` (type: `integer`):

Only include jobs first published within this many days. 0 = no limit.

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

Maximum total results across all searches. 0 = unlimited (needed for reliable expired-job detection in incremental mode).

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

Cap results for each individual keyword / Start URL. 0 = use 'Max results'. The public API returns at most 2000 results per search.

## `includeDetails` (type: `boolean`):

Fetch each job's detail page for the full description, apply URL, application method, address, and end date. Disable for a faster listing-only run.

## `descriptionFormat` (type: `string`):

Which description fields to include: plain text, HTML, or both.

## `compact` (type: `boolean`):

Emit core fields only — ideal for piping into an LLM, MCP data source, or downstream tool without token overhead.

## `excludeEmptyFields` (type: `boolean`):

Remove null / empty values from each record.

## `incrementalMode` (type: `boolean`):

Compare this run against the previous run stored under the same State key and annotate each record with a changeType (NEW, UPDATED, UNCHANGED, REAPPEARED, EXPIRED).

## `stateKey` (type: `string`):

Identifier for the tracked search state. Reuse the same value across runs to build a change feed. Required when incremental tracking is on.

## `emitUnchanged` (type: `boolean`):

Also output records whose tracked content did not change since the previous run.

## `emitExpired` (type: `boolean`):

Also output a minimal record for jobs that were tracked before but are no longer found (requires Max results = 0).

## `skipReposts` (type: `boolean`):

Drop new listings whose content matches a previously expired job (a re-published duplicate).

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

Maximum parallel detail-page requests.

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

Apify Proxy settings. Datacenter proxy is sufficient for jobup.ch.

## Actor input object example

```json
{
  "query": "software engineer",
  "country": "CH",
  "language": "en",
  "sortBy": "relevance",
  "employmentType": "",
  "workloadMin": 0,
  "workloadMax": 100,
  "companyFilter": "all",
  "publishedSinceDays": 0,
  "maxResults": 25,
  "maxResultsPerQuery": 0,
  "includeDetails": true,
  "descriptionFormat": "both",
  "compact": false,
  "excludeEmptyFields": false,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "skipReposts": false,
  "maxConcurrency": 8,
  "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 = {
    "query": "software engineer",
    "maxResults": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/jobup-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 = {
    "query": "software engineer",
    "maxResults": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/jobup-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 '{
  "query": "software engineer",
  "maxResults": 25
}' |
apify call parsebird/jobup-ch-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/jobup-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/1J68ulz26LU11avfR/builds/3OKGbOCgYhyxWHa6g/openapi.json
