# simap.ch Scraper — Swiss Public Procurement Tenders (`studio-amba/simap-scraper`) Actor

Search and extract Swiss public procurement tenders from simap.ch, Switzerland's national tender platform. Filter by canton, CPV code, publication type or date range. Returns buyer, deadline, CPV codes, lots and (for awards) the winning vendor and price. No cookies, no login required.

- **URL**: https://apify.com/studio-amba/simap-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

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

## Swiss Public Procurement Scraper — simap.ch Tenders & Awards

Search and extract Swiss public procurement tenders from simap.ch, the official national platform where every Swiss federal, cantonal and communal authority publishes its tenders. Filter by keyword, canton, CPV code, publication type or date range. Returns the buyer, submission deadline, CPV classification, lots and — for contract awards — the winning vendor, awarded price and number of bids received. No cookies, no login required.

### How to scrape simap.ch data

This actor queries the official simap.ch publication API directly. simap.ch is the single national platform Swiss public authorities are legally required to use for procurement above the WTO/cantonal thresholds — federal offices, cantonal administrations, municipalities, hospitals, public transport operators and universities all publish here. That makes this actor a complete feed of Swiss public-sector buying activity across construction, IT, supplies and services.

The actor fetches the public project-search endpoint for the list of matching tenders, then — when "Fetch full details" is enabled — makes one extra call per tender to pull the submission deadline, CPV classification codes, buyer contact details and, for award publications, the winning vendor and contract value. None of this requires an account: simap.ch's `/api/publications/...` endpoints are open, unauthenticated JSON, confirmed against the site's own `robots.txt` (only admin/account/vendor-profile paths are disallowed — the API is not).

#### Who benefits from this data?

- **Construction and engineering firms** — Monitor new public works tenders by canton and CPV code, and see what competitors are winning and at what price.
- **IT and software vendors** — Track federal and cantonal IT procurement (CPV 72xxxxxx / 48xxxxxx) before an RFP deadline closes.
- **Consultancies and advisory firms** — Build market intelligence on which authorities are buying what, and how often direct awards bypass open competition.
- **B2B sales and business development teams** — Turn every open tender in your sector into a prospect list with a buyer name, email and phone number.
- **Market researchers and journalists** — Analyze award prices, submission counts and canton-level procurement volumes.

#### Search by keyword

Enter any keyword to search tender titles, descriptions and buyer names server-side via the simap.ch API itself (unlike some tender platforms, this is a real search, not a client-side filter). Use German, French or Italian for the best results — simap.ch publications are written in the buyer's own language, and English titles only exist where a buyer chose to add one. Examples: "Bau" (construction), "informatique" (IT), "nettoyage" (cleaning), "Tiefbau" (civil engineering).

#### Filter by publication type, canton and CPV code

- **Publication type**: open tenders (calls for bids), contract awards, direct awards, design competitions, abandoned procedures, or all
- **Canton**: narrow to any of the 26 Swiss cantons by the buyer's or place-of-performance's address
- **CPV code**: filter by the EU/Swiss Common Procurement Vocabulary code, e.g. `45000000` for construction or `72000000` for IT services

#### Date range filtering

Set publication date filters to monitor new tenders on a schedule, or search historically for market research. `publishedAfter` and `publishedBefore` accept `YYYY-MM-DD` and map to the API's own `newestPublicationFrom` / `newestPublicationUntil` parameters.

### Input parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQuery` | String | — | Keywords to search in tender titles, descriptions and buyer names (server-side search) |
| `pubType` | Enum | `tender` | Filter: `tender`, `award`, `direct_award`, `competition`, `abandonment`, or `all` |
| `canton` | Enum | — (all) | 2-letter Swiss canton code, e.g. `ZH`, `GE`, `VD` |
| `cpvCode` | String | — | CPV classification code to filter by |
| `publishedAfter` | String | — | Only publications on or after this date (`YYYY-MM-DD`) |
| `publishedBefore` | String | — | Only publications on or before this date (`YYYY-MM-DD`) |
| `language` | Enum | `en` | Search/output language: `de`, `fr`, `it`, or `en` |
| `fetchDetails` | Boolean | `true` | Fetch deadline, CPV codes, lots and award vendor per tender (one extra API call each) |
| `maxResults` | Integer | `100` | Maximum number of tenders to return (1–10,000) |
| `proxyConfiguration` | Object | Automatic | Apify proxy settings — simap.ch has no anti-bot, so the default is enough |

Leaving every field empty (`{}`) still returns data: the actor defaults to `pubType: "tender"`, i.e. all currently open Swiss tenders.

### What data does this scraper extract?

| Field | Type | Description |
|-------|------|-------------|
| `projectId` | String | simap.ch project ID (stable across all publications of the same tender) |
| `publicationId` | String | ID of this specific publication |
| `projectNumber` | String | Public simap.ch project number |
| `publicationNumber` | String | Public publication number, e.g. `43403-01` |
| `tenderTitle` | String | Tender title in the requested/best-available language |
| `titleTranslations` | Object | Title in each published language (`de`/`fr`/`it`/`en`), `null` where untranslated |
| `projectType` | String | Always `tender` for procurement projects |
| `projectSubType` | String | `construction`, `supply`, or `service` |
| `processType` | String | Procedure type: `open`, `selective`, `invitation`, etc. |
| `pubType` | String | `tender`, `award`, `abandonment`, `direct_award`, or `competition` |
| `corrected` | Boolean | True when a later correction publication exists for this project |
| `publicationDate` | String | Date this publication went live (`YYYY-MM-DD`) |
| `deadline` | String | Bid submission deadline, ISO timestamp (open tenders only) |
| `procOfficeName` | String | Contracting authority / buyer name |
| `procOfficeEmail` | String | Buyer contact email |
| `procOfficePhone` | String | Buyer contact phone |
| `procOfficeUrl` | String | Buyer website |
| `canton` | String | 2-letter Swiss canton code |
| `city` | String | City of the buyer / place of performance |
| `postalCode` | String | Postal code |
| `country` | String | ISO country code, almost always `CH` |
| `cpvCode` | String | Primary CPV classification code |
| `cpvLabel` | String | Human-readable CPV category |
| `additionalCpvCodes` | Array | Secondary CPV codes with labels |
| `lots` | Array | Per-lot breakdown: lot number, title, canton, city |
| `description` | String | Full tender description, HTML stripped |
| `awardedVendorName` | String | Winning vendor name (award publications only) |
| `awardedPrice` | Number | Contract value awarded (award publications only) |
| `awardedCurrency` | String | Currency of `awardedPrice`, almost always `CHF` |
| `numberOfSubmissions` | Number | Number of bids received (award publications only) |
| `url` | String | Direct link to the project on simap.ch |
| `scrapedAt` | String | ISO timestamp of when the data was scraped |

### Example output

```json
{
    "projectId": "0afabb3b-cba8-41f6-b77e-9665d941174d",
    "publicationId": "8ccfc1c3-a7a5-4d44-aa72-0444e352c92a",
    "projectNumber": "43403",
    "publicationNumber": "43403-01",
    "tenderTitle": "BKP 358 Kücheneinrichtungen",
    "pubType": "tender",
    "publicationDate": "2026-09-03",
    "deadline": "2026-10-13T13:58:00+02:00",
    "procOfficeName": "Politische Gemeinde Balgach",
    "procOfficeEmail": "neubau-verahus@balgach.ch",
    "canton": "SG",
    "city": "Balgach",
    "cpvCode": "45215212",
    "cpvLabel": "Retirement home construction work",
    "lots": [
        { "lotNumber": 1, "title": "BKP 358 Kücheneinrichtungen", "canton": "SG", "city": "Balgach" }
    ],
    "url": "https://www.simap.ch/en/project-detail/0afabb3b-cba8-41f6-b77e-9665d941174d",
    "scrapedAt": "2026-09-04T19:46:14.193Z"
}
```

### Tips for best results

- **Daily monitoring**: Run on a schedule with `publishedAfter` set to today for fresh open tenders only — set an alert before a bid deadline passes.
- **CPV code targeting**: Note the CPV codes relevant to your business from an initial run, then filter by them directly. `45000000` = construction, `72000000` = IT services, `71000000` = architectural/engineering services.
- **Award intelligence**: Set `pubType: "award"` to see who won recent contracts and at what price — useful for competitor and pricing intelligence. This filter runs client-side (see Limitations), so pair it with a canton or CPV code for a fast scrape.
- **Canton-by-canton sweep**: Run once per canton to build a complete national dataset without hitting `maxResults` on a single broad query.
- **Multilingual titles**: `titleTranslations` carries every language the buyer published in — useful if you need the original German/French/Italian text alongside the display title.

### How much does it cost to run?

The simap.ch API is free and public. Your only cost is Apify compute time — there is no proxy or anti-bot cost since simap.ch requires no residential proxy.

| Search size | Estimated time | Estimated cost per result |
|-------------|---------------|----------------------------|
| 20 tenders | ~15 seconds | ~$0.002/result |
| 100 tenders | ~1 minute | ~$0.002/result |
| 500 tenders | ~4 minutes | ~$0.002/result |
| 1,000 tenders | ~8 minutes | ~$0.002/result |

Each tender requires one extra API call when "Fetch full details" is enabled (default), for the deadline, CPV codes and award data that the list endpoint doesn't expose. Disable it for a faster list-only scrape if you only need title, buyer and canton.

Usage cost only settles once a run reports **SUCCEEDED** — reading the dataset mid-run (before the run finishes) will undercount the final cost, since Apify's per-event billing is reconciled at run completion.

### Use as an API

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("studio-amba/simap-scraper").call(run_input={
    "searchQuery": "Bau",
    "pubType": "tender",
    "canton": "ZH",
    "maxResults": 50,
})

for tender in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{tender['tenderTitle']} | {tender['procOfficeName']} | Deadline: {tender['deadline']}")
```

### Limitations

- **`award` and `correction` publication types aren't filterable server-side**: the simap.ch API rejects `newestPubTypes=award` with HTTP 400. The actor works around this for `pubType: "award"` by fetching unfiltered pages and filtering client-side, which scans more pages for a given result count — narrow with `canton`, `cpvCode` or a date range to keep it fast. `correction` publications are rare enough on simap.ch that they aren't offered as a dedicated filter; they still surface in `pubType` output when present.
- **Deadline is empty on non-tender publications**: awards, abandonments and corrections don't carry a submission deadline.
- **Titles are often single-language**: a buyer publishing only in German will have `null` for `fr`/`it`/`en` in `titleTranslations` — this is how simap.ch itself publishes the data, not a scraping gap.
- **Detail fetching adds time**: each tender gets an individual API call for CPV codes, deadline and award data when `fetchDetails` is enabled. Set `maxResults` accordingly for large sweeps.

### Other European procurement scrapers

- Check the [Studio AMBA actor catalog](https://apify.com/studio-amba) for TenderNed (Netherlands), Belgian procurement, and other European tender scrapers.

### Your feedback

Found a bug or want a feature? Open an issue on the [Issues tab](https://console.apify.com/actors/studio-amba~simap-scraper/issues).

# Actor input Schema

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

Search tenders by keyword (matched against title, description and buyer name by the simap.ch API). Use German, French or Italian for best results. Leave empty to browse by canton, publication type or date range instead. Examples: 'construction', 'informatique', 'nettoyage', 'Bau'.

## `pubType` (type: `string`):

Filter by the type of the latest publication on each project. 'Contract awards' is filtered client-side (the simap.ch API does not accept 'award' as a server-side filter value), so it scans more pages internally — narrow with a canton, CPV code or date range for a fast scrape.

## `canton` (type: `string`):

Only return tenders where the place of performance (order address) is in this Swiss canton.

## `cpvCode` (type: `string`):

Filter by a CPV (Common Procurement Vocabulary) classification code, e.g. '45000000' for construction work or '72000000' for IT services. Leave empty for all categories.

## `publishedAfter` (type: `string`):

Only tenders with a publication on or after this date. Format: YYYY-MM-DD.

## `publishedBefore` (type: `string`):

Only tenders with a publication on or before this date. Format: YYYY-MM-DD.

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

Language used for the simap.ch search and preferred for the returned title/CPV label. simap.ch publications are often only available in the buyer's own language (de/fr/it) regardless of this setting.

## `fetchDetails` (type: `boolean`):

When enabled, each tender gets one extra API call to fetch its deadline, CPV codes, lots and (for awards) the winning vendor. Disable for a faster list-only scrape.

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

Maximum number of tenders to return.

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

Apify proxy configuration. simap.ch's publication API is a clean public JSON endpoint with no anti-bot protection, so the default (automatic) proxy is enough.

## Actor input object example

```json
{
  "pubType": "tender",
  "canton": "",
  "language": "en",
  "fetchDetails": true,
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/simap-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 = {
    "maxResults": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/simap-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 '{
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call studio-amba/simap-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/simap-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/42DDcJ6Ucgy5PRNGi/builds/hYnQw6X9eJYchHU4K/openapi.json
