# carriera.ch Scraper: Ticino & Italian-Swiss Jobs (`santamaria-automations/carriera-ch-scraper`) Actor

Scrape carriera.ch — the leading jobs portal for Canton Ticino / Italian-speaking Switzerland. Returns title, company, city, workload %, employment type, CHF salary, education, experience, benefits, qualifications, and full Italian description. No browser required.

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

## Pricing

from $3.00 / 1,000 serp 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?

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

## carriera.ch Scraper: Ticino & Italian-Swiss Jobs

Collect job listings from [carriera.ch](https://www.carriera.ch), the primary jobs portal for **Canton Ticino and Italian-speaking Switzerland** (Lugano, Bellinzona, Locarno, Mendrisio, Chiasso, Balerna, Agno, Bioggio, and beyond). Returns structured data extracted from schema.org JobPosting JSON-LD on every detail page: title, company, city, posted date, expiry date, workload percentage, employment type, and the full Italian description in plain text, HTML, and Markdown.

### What you get

Each result row contains:

- **Job**: title (Italian), URL, posted date (ISO 8601), expiry date, workload percentage (100%, 80%, 50%, etc.)
- **Company**: name, website, logo URL (when the employer supplies them via JSON-LD hiringOrganization)
- **Location**: city, region ("Svizzera italiana"), postal code, street address, country code CH
- **Job details**: employment type (Full-time / Part-time / Contract / Internship / Temporary), workplace type (Remote / Hybrid inferred from description)
- **Apply URL**: external employer link when the detail page anchors out to a company careers page
- **Description**: snippet (300 chars), plain text, HTML, and Markdown (when `includeJobDetails=true`)
- **Contacts**: emails, phones, and external URLs from the job description

### A note on salary data

carriera.ch does not expose salary in its job listings. The site's JSON-LD template hardcodes `baseSalary.value = 80000` on every job as a CMS placeholder, not actual employer-supplied pay data. All salary fields (`salary_min`, `salary_max`, `salary_currency`, etc.) are returned as `null`. If you need CHF salary benchmarks, consider combining this actor with an LLM enrichment layer over the description text.

### Use cases

- Ticino labour market research: track hiring trends across the Italian-speaking Swiss region
- Competitive intelligence: monitor which companies are actively hiring in Ticino
- Cross-border recruiting between Northern Italy (Como, Varese, Milano) and Ticino
- Lead generation for HR / staffing agencies serving the Italian-Swiss market
- Academic research: employment patterns in the multi-lingual Swiss economy

### Pricing

This actor uses Pay-Per-Event (PPE) pricing. Every Apify account includes a **$5 free monthly credit**.

| Event | Cost |
|---|---|
| Actor start | $0.001 |
| SERP result (job card from the search page) | $0.003 |
| Full job detail (description + JSON-LD structured fields) | $0.005 |

carriera.ch's SERP shows only date / company / title / city / workload. All the structured JobPosting data (employment type, location detail, apply URL, description) lives on the detail page. Keep `includeJobDetails: true` (default) for the full field surface; set to `false` for lightweight bulk collection at the lower rate.

### Input

```json
{
  "searchQueries": [""],
  "location": "Lugano",
  "includeJobDetails": true,
  "sortBy": "newest",
  "maxResults": 100
}
```

| Field | Type | Description |
|---|---|---|
| `searchQueries` | string\[] | Italian job keywords. Leave `[""]` (empty) to scrape all active listings. Examples: `informatica`, `contabile`, `ingegnere`, `commerciale` |
| `searchUrls` | string\[] | Direct carriera.ch SERP URLs. Paste a `/cgi-bin/annunci_offerte_lavoro.cgi` URL and the scraper paginates through `job_page`. |
| `location` | string | Ticino city filter. Examples: `Lugano`, `Bellinzona`, `Locarno`, `Mendrisio`, `Chiasso`, `Balerna` |
| `category` | string | carriera.ch `job_category` code (leave empty for `ALL`). Reference: `190` = IT / Telecomunicazioni, `200` = Marketing, `270` = Vendita / Distribuzione |
| `sortBy` | enum | Sort order. `newest` (default; `sort_date=DESC`) or `oldest` (`sort_date=ASC`). Verified empirically 2026-09-03 |
| `includeJobDetails` | boolean | Fetch each detail page for the full JSON-LD JobPosting block (default: `true`) |
| `includeCompanyDetails` | boolean | Include `hiringOrganization.url` / `.logo` when present (default: `false`) |
| `maxResults` | integer | Total results cap (default: 100, max: 5000) |
| `maxResultsPerQuery` | integer | Cap per keyword (default: 100) |
| `maxConcurrency` | integer | Max concurrent requests 1-20 (default: 5; scraper is currently sequential) |

### Output sample

```json
{
  "_type": "job",
  "id": "291235",
  "title": "Mechanical maintenance technician",
  "job_url": "https://www.carriera.ch/cgi-bin/offerta.cgi?job_id=291235",
  "source_url": "https://www.carriera.ch/cgi-bin/offerta.cgi?job_id=291235",
  "source_platform": "carriera.ch",
  "company_name": "IBSA Farmaceutici Italia",
  "location": "Lodi, IT",
  "country": "IT",
  "region": null,
  "city": "Lodi",
  "posted_at_text": "2026-09-01",
  "posted_at_datetime": "2026-09-01T00:00:00Z",
  "expires_at": "2026-12-31T00:00:00Z",
  "employment_type": "Full-time",
  "description_snippet": "La posizione di Mechanical Maintenance Technician presso IBSA Farmaceutici Italia...",
  "description_full": "La posizione di Mechanical Maintenance Technician presso IBSA...",
  "apply_url": "https://www.ibsa.it/carriere/posizione-maintenance-technician",
  "scraped_at": "2026-09-05T10:00:00Z"
}
```

### Notes on data completeness

- **Fields with high fill rate (>80%)**: `title`, `company_name`, `city`, `location`, `posted_at_datetime`, `description_full`, `description_snippet`, `description_html`, `description_md` -- all sourced from JSON-LD JobPosting.
- **Fields with lower fill rate**: `company_website`, `company_logo_url`, `apply_url` -- depend on whether the employer supplies a `hiringOrganization.url`/`.logo` or an outbound "Dettagli dell'annuncio" link.
- **Fields always null**: `salary_min`, `salary_max`, `salary_currency`, `salary_period`, `salary_text` (hardcoded CMS placeholder on the site -- see salary note above), `company_size`, `company_profile_url`, `image_url`, `education_requirements`, `experience_requirements`, `qualifications`, `job_benefits`, `incentive_compensation`, `seniority` (all boilerplate template values identical across every job on the site).
- **Fields typically null**: `category` (JSON-LD occupationalCategory is usually empty), `company_industry` (JSON-LD industry is usually empty), `postal_code`, `street_address`.
- **Charset**: carriera.ch serves ISO-8859-1. The scraper transcodes to UTF-8 before parsing so Italian accented characters (a, e, i, o, u with accents) render cleanly.

### Related actors

#### Swiss job boards (same market)

- [jobs-ch-scraper](https://apify.com/santamaria-automations/jobs-ch-scraper) - jobs.ch, Switzerland's largest job board (JobCloud)
- [jobup-ch-scraper](https://apify.com/santamaria-automations/jobup-ch-scraper) - jobup.ch, French-speaking Switzerland (JobCloud)
- [arbeit-swiss-scraper](https://apify.com/santamaria-automations/arbeit-swiss-scraper) - job-room.ch, the official Swiss federal job portal (arbeit.swiss / travail.swiss / lavoro.swiss / work.swiss)
- [swissdevjobs-ch-scraper](https://apify.com/santamaria-automations/swissdevjobs-ch-scraper) - swissdevjobs.ch, developer-focused Swiss listings
- [ictjobs-ch-scraper](https://apify.com/santamaria-automations/ictjobs-ch-scraper) - ictjobs.ch, ICT and tech roles in Switzerland
- [zentraljob-ch-scraper](https://apify.com/santamaria-automations/zentraljob-ch-scraper) - zentraljob.ch, Central Switzerland regional board
- [ostjob-ch-scraper](https://apify.com/santamaria-automations/ostjob-ch-scraper) - ostjob.ch, Eastern Switzerland regional board
- [jobbasel-ch-scraper](https://apify.com/santamaria-automations/jobbasel-ch-scraper) - jobbasel.ch, Basel regional board
- [jobbern-ch-scraper](https://apify.com/santamaria-automations/jobbern-ch-scraper) - jobbern.ch, Bern regional board
- [jobmittelland-ch-scraper](https://apify.com/santamaria-automations/jobmittelland-ch-scraper) - jobmittelland.ch, Mittelland regional board
- [jobzueri-ch-scraper](https://apify.com/santamaria-automations/jobzueri-ch-scraper) - jobzueri.ch, Zurich regional board
- [myjob-ch-scraper](https://apify.com/santamaria-automations/myjob-ch-scraper) - myjob.ch, Swiss generalist board
- [schaffu-ch-scraper](https://apify.com/santamaria-automations/schaffu-ch-scraper) - schaffu.ch, Swiss generalist board
- [nicejob-de-scraper](https://apify.com/santamaria-automations/nicejob-de-scraper) - nicejob.de, German-language Swiss and German listings

#### Italian job boards (same-language market for IT-CH)

- [subito-it-jobs-scraper](https://apify.com/santamaria-automations/subito-it-jobs-scraper) - subito.it, Italy's largest classifieds platform with a large jobs section

***

### Support

Questions, bug reports, or field requests? Email **contact@nanoscrape.com** or open an issue on the [actor issues tab](https://console.apify.com/actors/T8dSZzZObL2mVTcv1/issues).

# Actor input Schema

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

Italian job keywords to search across carriera.ch. Leave empty and set no location to scrape all active listings. Examples: 'informatica', 'contabile', 'ingegnere', 'commerciale'.

## `searchUrls` (type: `array`):

Direct carriera.ch SERP URLs (e.g. filtered by city or category). Paste any /cgi-bin/annunci\_offerte\_lavoro.cgi URL and the scraper will paginate through job\_page.

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

Ticino city to filter by. Examples: 'Lugano', 'Bellinzona', 'Locarno', 'Mendrisio', 'Chiasso', 'Balerna'. Leave empty for all cities.

## `category` (type: `string`):

carriera.ch job\_category code. Leave empty (default 'ALL') for all categories. Category codes correspond to the site's own /offerte/annunci-offerte-lavoro\_{slug}\_{code}\_0.html pages (e.g. 190 = IT / Telecomunicazioni, 200 = Marketing, 270 = Vendita).

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

How to order results. carriera.ch's CGI SERP supports sort\_date=DESC (newest first, default) and sort\_date=ASC (oldest first). Verified empirically 2026-09-03.

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

Fetch each detail page for full description (HTML, plain text, Markdown) plus structured schema.org JobPosting fields (salary in CHF, education, experience, benefits, qualifications, responsibilities). Adds one HTTP request per job.

## `includeCompanyDetails` (type: `boolean`):

Include company website and logo URL when present in the JSON-LD hiringOrganization block.

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

Maximum total results to return across all queries.

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

Maximum results per search keyword or URL.

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

Maximum concurrent requests (1-20). Currently informational; scraper is sequential per-page.

## Actor input object example

```json
{
  "searchQueries": [
    ""
  ],
  "sortBy": "newest",
  "includeJobDetails": true,
  "includeCompanyDetails": false,
  "maxResults": 100,
  "maxResultsPerQuery": 100,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

Dataset containing scraped carriera.ch Ticino / Italian-Swiss job listings. Each row includes title, company\_name, city, country, posted\_at\_datetime, expires\_at, employment\_type, work\_hours, and description quartet (snippet/full/html/md). Salary and several structured fields are null because carriera.ch injects identical boilerplate placeholder values for those fields on every job.

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

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

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

```

## MCP server setup

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