# JobMittelland.ch Scraper - Mittelland Region Job Board (`santamaria-automations/jobmittelland-ch-scraper`) Actor

Scrapes job listings from JobMittelland.ch, the regional job portal for Swiss Mittelland (Solothurn, Olten, Aarau). Filter by location, workload, and company type. Optional LLM contact extraction.

- **URL**: https://apify.com/santamaria-automations/jobmittelland-ch-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 6 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

## Jobmittelland.ch Job Scraper

Scrapes job listings from [jobmittelland.ch](https://www.jobmittelland.ch), the leading job portal for Mittelland.

### Features

- **Multi-query support** - Run multiple search keywords in a single actor run, deduplicated across queries
- **Per-query limits** - Control how many results each keyword returns
- **API-based scraping** - Uses the official API for fast, reliable data extraction
- **Smart location filtering** - Enter any canton, district, or city name - auto-resolves via API
- **Sort by date** - Get newest jobs first for job monitoring use cases
- **Workload filter** - Filter by Pensum percentage (e.g., 40-60% for part-time)
- **HR company filtering** - Filter out recruitment agencies to get direct employer postings
- **Still alive checks** - Verify if specific job URLs are still active via Direct URL mode
- **Company details** - Returns company website, about text, address, logo, and social URLs from the CH-Media API at no extra HTTP cost
- **Standardized output** - Returns data in the `JobListing` schema format with `search_query` tracking

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client — Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

**Apify MCP server URL:**

```
https://mcp.apify.com?tools=santamaria-automations/jobmittelland-ch-scraper
```

**Example prompt once connected:**

> "Use `jobmittelland-ch-scraper` to scrape job listings from jobbasel ch. Return results as a table."

Clients that support dynamic tool discovery (Claude.ai, VS Code) will receive the full input schema automatically via `add-actor`.

### Input

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `searchQueries` | string\[] | One or more search keywords (multi-query). Each runs as a separate search, deduplicated. | `["Informatiker"]` |
| `searchQuery` | string | Legacy single search query. Use `searchQueries` instead. | `""` |
| `directUrls` | string\[] | Job URLs to scrape directly (for still alive checks) | `[]` |
| `location` | string | Canton, district, or city name. Auto-resolves via API. | `""` (all Basel) |
| `maxResultsPerQuery` | integer | Max results per search keyword | `100` |
| `maxResults` | integer | Total cap across all queries. 0 = unlimited. | `0` |
| `sortBy` | string | `newest` (date order) or `relevance` (best match). Maps to platform's `by_date` / `by_relevance`. | `newest` |
| `workloadMin` | integer | Minimum workload/Pensum percentage (0-100) | - |
| `workloadMax` | integer | Maximum workload/Pensum percentage (0-100) | - |
| `includeJobDetails` | boolean | Fetch full job descriptions | `true` |
| `companyFilter` | string | `all`, `exclude-hr`, `only-hr` | `all` |

### Multi-Query Example

```json
{
  "searchQueries": ["Informatiker", "Pflege", "Buchhaltung"],
  "location": "Basel",
  "maxResultsPerQuery": 50,
  "maxResults": 0,
  "sortBy": "newest"
}
```

This runs 3 searches, each returning up to 50 results. Jobs appearing in multiple searches are deduplicated. Each result includes a `search_query` field showing which keyword found it.

### Output

```json
{
  "id": "12345",
  "title": "Software Entwickler (m/w/d)",
  "company_name": "Tech Solutions AG",
  "location": "Basel, 4001, BS",
  "canton": "BS",
  "employment_type": "full-time",
  "workload_min": 80,
  "workload_max": 100,
  "job_url": "https://www.jobmittelland.ch/job/software-entwickler/12345",
  "source_platform": "jobmittelland.ch",
  "search_query": "Informatiker",
  "posted_at": "2026-01-15T00:00:00.000Z",
  "company_website": "https://www.techsolutions.ch",
  "company_about": "Tech Solutions AG ist ein innovatives Schweizer IT-Unternehmen...",
  "company_address": "Musterstrasse 1, 4001, Basel, CH",
  "company_logo_url": "https://api.jobmittelland.ch/public/image/logo456",
  "company_social_urls": ["https://www.linkedin.com/company/tech-solutions-ag"],
  "scraped_at": "2026-03-17T12:00:00.000Z"
}
```

#### Output fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Job ID on jobmittelland.ch |
| `title` | string | Job title |
| `company_name` | string | Employer name |
| `location` | string | City, ZIP, canton |
| `canton` | string | Swiss canton code (BS, BL, etc.) |
| `job_url` | string | Direct URL to job listing |
| `apply_url` | string | Application URL |
| `posted_at` | string | ISO 8601 post date |
| `expires_at` | string | ISO 8601 expiry date |
| `description_snippet` | string | Short job description excerpt |
| `description_full` | string | Full job description |
| `employment_type` | string | full-time / part-time |
| `workload_min` / `workload_max` | number | Pensum % range |
| `remote_option` | string | hybrid / onsite |
| `contact_email` / `contact_phone` | string | Contact details |
| `company_website` | string | Employer own website |
| `company_about` | string | Company description from API |
| `company_address` | string | Company address (street, zip, city, country) |
| `company_logo_url` | string | Company logo URL |
| `company_social_urls` | string\[] | Social media profile URLs |
| `company_benefits` | string\[] | Company benefits from API |
| `search_query` | string | Search keyword that found this job |

#### Deprecation notes

The following field names are deprecated and will be removed after **2027-09-16** (one-year backward-compatibility window):

- `company` - use `company_name` (canonical since 2026-09-16)
- `source_url` - use `job_url` (canonical since 2026-09-16)
- `company_url` - use `company_website` (canonical since 2026-09-16)
- `company_description` - use `company_about` (canonical since 2026-09-16)

Both the deprecated and canonical fields are emitted in every dataset row during the transition window. Please migrate downstream consumers to the canonical names before the removal date.

### Direct URL Mode (Still Alive Checks)

```json
{
  "directUrls": [
    "https://www.jobmittelland.ch/job/software-entwickler/12345",
    "https://www.jobmittelland.ch/job/projekt-manager/67890"
  ]
}
```

Each job will have `job_status`: `"online"` or `"offline"`.

### Performance

- **Speed**: ~100-200 jobs/minute (4-second rate limit between requests)
- **Cost**: ~0.01-0.03 CU per 500 jobs
- **Memory**: 256-512 MB

### Data Source

- **Website**: [jobmittelland.ch](https://www.jobmittelland.ch)
- **API**: Public vacancy search API (CH-Media Group)
- **Coverage**: Mittelland (BE,SO,AG,LU)

### Related Actors

Looking for more job data? Check out our other scrapers:

**Switzerland**

- [Jobs.ch Scraper](https://apify.com/santamaria-automations/jobs-ch-scraper)
- [JobScout24 Scraper](https://apify.com/santamaria-automations/jobscout24-ch-scraper)
- [ICTjobs.ch Scraper](https://apify.com/santamaria-automations/ictjobs-ch-scraper)
- [SwissDevJobs Scraper](https://apify.com/santamaria-automations/swissdevjobs-ch-scraper)

**Germany**

- [StepStone.de Scraper](https://apify.com/santamaria-automations/stepstone-de-scraper)
- [Stellenanzeigen.de Scraper](https://apify.com/santamaria-automations/stellenanzeigen-de-scraper)

**Global**

- [LinkedIn Jobs Scraper](https://apify.com/santamaria-automations/linkedin-scraper)
- [Indeed Scraper](https://apify.com/santamaria-automations/indeed-scraper)

**Enrich your job data**

- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor) -- Extract jobs directly from company career pages
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor) -- Get emails and phone numbers from company websites
- [Website Email & Phone Scraper](https://apify.com/santamaria-automations/website-email-scraper) -- Fast email and phone extraction (no AI needed)

***

**Part of the Santamaria Job Scrapers Suite** - Professional-grade job data for the DACH region.

# Actor input Schema

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

List of job detail page URLs to scrape directly (skips search). Use this for 'still alive' checks or re-scraping specific jobs. Example: \['https://www.jobmittelland.ch/job/software-entwickler/12345']

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

One or more search keywords. Each keyword runs as a separate search. Results are deduplicated across queries.

## `searchQuery` (type: `string`):

Legacy single search query. Use 'searchQueries' instead for multiple keywords.

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

Canton, district, or city name (e.g., 'Solothurn', 'Olten', 'Aarau'). The scraper auto-resolves the location type. Leave empty for all of Mittelland region.

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

Per-keyword cap. Total possible results = maxResultsPerQuery × number of searchQueries (deduplicated). Example: 100 × 8 queries = up to 800 results. Set to 0 for unlimited per query (only maxResults caps the total).

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

Total cap across all queries. Set to 0 for unlimited (each query limited by maxResultsPerQuery).

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

Sort order for results. 'newest' returns jobs sorted by publication date (recommended for monitoring). 'relevance' returns best keyword matches first. Maps to the platform's native by_date / by_relevance order parameter.

## `sortOrder` (type: `string`):

DEPRECATED — use sortBy. Removed 2027-09-19. How to sort job results. Use 'by_date' to get newest jobs first (recommended for monitoring), 'by_relevance' for best matches to search query.

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

Minimum workload/Pensum percentage (e.g., 60 for 60%). Leave empty for no minimum.

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

Maximum workload/Pensum percentage (e.g., 100 for 100%). Leave empty for no maximum.

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

Fetch full job descriptions from detail pages (slower but more data)

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

Filter jobs by company type: 'all' includes all companies, 'exclude-hr' removes HR/recruitment agencies, 'only-hr' shows only HR/recruitment agencies

## Actor input object example

```json
{
  "directUrls": [],
  "searchQueries": [
    "Informatiker"
  ],
  "searchQuery": "",
  "location": "",
  "maxResultsPerQuery": 100,
  "maxResults": 0,
  "sortBy": "newest",
  "sortOrder": "",
  "includeJobDetails": true,
  "companyFilter": ""
}
```

# Actor output Schema

## `jobListings` (type: `string`):

Dataset containing scraped job listings

# 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 = {
    "directUrls": [],
    "searchQueries": [
        "Informatiker"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/jobmittelland-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 = {
    "directUrls": [],
    "searchQueries": ["Informatiker"],
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/jobmittelland-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 '{
  "directUrls": [],
  "searchQueries": [
    "Informatiker"
  ]
}' |
apify call santamaria-automations/jobmittelland-ch-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/jobmittelland-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/2fobhFgKdhD24lQk8/builds/4frnvxGwW2SnqElmz/openapi.json
