# carmarket.ch Scraper — Swiss Cars, EV Battery & Dealers (`memo23/carmarket-scraper`) Actor

Scrape carmarket.ch, the Swiss dealer car marketplace: every listing with VIN, type approval, mileage, first registration, battery kWh and range, all photos, the dealer's address, phones, email, website and map coordinates. Paste any search URL; the whole result set is delivered.

- **URL**: https://apify.com/memo23/carmarket-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** E-commerce, Lead generation, AI
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.10 / 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.
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?

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

## carmarket.ch Scraper — Swiss Cars, EV Battery & Dealers

Scrape **carmarket.ch**, the Swiss dealer car marketplace, into one row per car: VIN, type approval, first registration, mileage, battery capacity and range, every technical-table field, the full photo gallery, the dealer's address and map coordinates, and on request the dealer's phones, email and website. Paste any carmarket.ch search URL and the **whole result set** is delivered, not only the 33 pages the site shows.

![How the carmarket.ch Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-carmarket.png)

### Why use this scraper

- **Complete result sets.** carmarket.ch stops at 33 pages of 30 (1,000 cars) per search. The actor splits larger searches by price on its own and checks the result against the site's own count, so a 3,482-car search delivers 3,482 cars.
- **Your filters, exactly.** Set the filters on carmarket.ch, copy the address, paste it. Every filter in the URL is applied the way the site applies it, and a filter the actor cannot apply stops the run with a clear message instead of being ignored.
- **Everything the listing page shows.** All technical-table fields, the page's schema.org data (`jsonLd`), all gallery images in order and the dealer block.
- **Dealer location on every row.** `sellerCoordinates` carries the point on the dealer's carmarket.ch profile map.
- **Dealer contact details when you need them.** Switch on *Include dealer contact details* to add the phones, email and website; they are charged once per dealer per run, not per car.
- **A short run says so.** The completeness check compares every search with the count carmarket.ch reports and can fail a run that comes up short.
- **Fast.** The 3,482 used electric cars on 07.10.2026: 62 requests, about 16 seconds.

### What you can scrape

| Start URL | Example | What you get |
|---|---|---|
| Search page | `https://carmarket.ch/de/suche?fuelType=g%7C4&vehicleCondition=2` | Every car matching the search (here: used electric cars) |
| Listing page | `https://carmarket.ch/de/fahrzeug/hyundai-ioniq-5-77-4-kwh-origo-4507362` | That car |
| Dealer page | `https://carmarket.ch/de/haendler/auto-regli-gmbh-4363` | Every car that dealer lists |

German, French and Italian URLs all work (`/fr/recherche`, `/it/cerca`, `/fr/vehicule/…`, `/it/concessionaria/…`). The URL's language sets the language of the values (`Elektro` / `Electrique`).

Search filters supported: make and model, fuel type, body type, condition, price (buy or monthly rate), mileage, first registration, power (PS or kW), transmission, drive, vehicle class and type, doors, seats, engine size, cylinders, weights, battery capacity and range, colours, upholstery, energy-efficiency class, equipment, other filters (e.g. "Ab MFK"), promotions, free text and location radius. Sorting and paging parameters are ignored, since every matching car is delivered.

### Input

| Field | Description |
|---|---|
| `startUrls` | carmarket.ch search, listing or dealer URLs. |
| `maxItems` | Most listings to deliver across the run; 0 = no limit. Default 1000. Non-paying users are capped at 100. |
| `includeContactDetails` | Adds the dealer's phones, email and website to `seller` and `jsonLd`. Charged once per dealer per run. Default off. |
| `includeRawData` | Adds the vehicle record exactly as carmarket.ch's API returns it, under `raw`. Default off. |
| `failOnIncomplete` | End the run as FAILED when a search's shortfall exceeds the threshold. Default on. |
| `completenessTolerancePercent` / `completenessToleranceAbsolute` | The threshold: the larger of this percentage of the reported count and this many listings. Defaults 1 and 25. |
| `proxyConfiguration` | Optional. The data comes from two public JSON services that need no proxy. |

```json
{
    "startUrls": [{ "url": "https://carmarket.ch/de/suche?fuelType=g%7C4&vehicleCondition=2" }],
    "maxItems": 0,
    "includeContactDetails": true
}
```

### Output

One row per car. Selected fields from a real row, with *Include dealer contact details* on:

```json
{
    "id": 4507362,
    "url": "https://carmarket.ch/de/fahrzeug/hyundai-ioniq-5-77-4-kwh-origo-4507362",
    "title": "HYUNDAI Ioniq 5 77,4 kWh Origo",
    "make": "HYUNDAI", "model": "Ioniq", "version": "Ioniq 5 77,4 kWh Origo",
    "price": 28890, "priceCurrency": "CHF", "priceInitial": 57099,
    "conditionType": "Occasion",
    "firstRegistrationDate": "2022-12-28", "mileage": 40100,
    "powerHp": 227, "powerKw": 167,
    "batteryCapacityKwh": 77.4, "batteryRangeKm": 507,
    "fuelType": "Elektro", "transmissionType": "Automatik-Getriebe", "drive": "Hinterradantrieb",
    "vin": "KMHKM81EFPU124243",
    "typeApproval": "1HC553",
    "commissionNumber": "GA24243",
    "directImport": true,
    "warranty": { "typeId": 2, "months": 96, "maxKm": 160000 },
    "imageCount": 20,
    "images": ["https://vehicle.imgix.net/4507362/2c4934ea-ea00-4d75-8982-fb699f91ddfb.jpg", "…"],
    "seller": {
        "id": 5031, "name": "Auto Welt von Rotz AG",
        "profileUrl": "https://carmarket.ch/de/haendler/auto-welt-von-rotz-ag-5031",
        "street": "Wilerstrasse 72", "zip": "9542", "city": "Münchwilen",
        "telephone": "+41 71 516 11 27", "phone": "+41 71 913 33 66", "calltrackingPhone": "+41 71 516 11 27",
        "email": "…", "website": null
    },
    "sellerContactIncluded": true,
    "sellerCoordinates": { "latitude": 47.4722981, "longitude": 9.0109541, "source": "seller_location" },
    "jsonLd": { "@type": ["Product", "Car"], "vehicleIdentificationNumber": "KMHKM81EFPU124243", "offers": { "offeredBy": { "@type": "AutoDealer" } } }
}
```

#### Key output fields

| Field | Meaning |
|---|---|
| `vin` | Vehicle identification number, unchanged. |
| `typeApproval` | Swiss type approval number ("Typengenehmigung"). |
| `commissionNumber` | "Wagennummer" as the page shows it: the dealer's own reference, else carmarket.ch's internal number (both also in `vehicleExternalId` and `internalCommissionNumber`). |
| `batteryCapacityKwh`, `batteryRangeKm` | Battery capacity and range; null when the listing gives none. |
| `seller.telephone` | The number the listing shows: a call-tracking number when the dealer has one, otherwise the dealer's own. `seller.phone` is always the dealer's own number. All contact fields (`telephone`, `phone`, `calltrackingPhone`, `email`, `website`, and `offeredBy.telephone`/`url` in `jsonLd`) are null unless *Include dealer contact details* is on. |
| `sellerContactIncluded` | True when the row carries the dealer's contact details. |
| `sellerCoordinates` | The dealer's location on its carmarket.ch profile map; `source` is `seller_location`. |
| `jsonLd` | The listing page's schema.org Product/Car object, built the way the page builds it (`weightTotal.maxValue` is filled in where the page leaves it empty). |
| `warranty` | Warranty as carmarket.ch records it (type, months, kilometres, text per language). |

#### Completeness

Each search's count is compared with the listings delivered for it. The comparison is logged, written to the `COMPLETENESS` record in the run's key-value store and shown in the status message, for example `Done — delivered 3482 of 3482 reported (difference 0, threshold 35)`. With `failOnIncomplete` on, a shortfall above the threshold ends the run as FAILED. A search cut short by `maxItems` is not judged. A car that appears in two of your searches is delivered and charged once.

### Pricing

Pay per event:

| Event | When it is charged |
|---|---|
| `result` | Once per car delivered. A car that several of your URLs return is delivered and charged once per run. |
| `contact-details` | Once per dealer per run, only with *Include dealer contact details* on, however many of that dealer's cars you get. A dealer with no phone, email or website on carmarket.ch costs nothing. |

The amounts for your Apify plan are on the actor's Pricing tab. A run stops cleanly at your spending limit: the rows you get are the rows you paid for.

### FAQ

**Why not just 33 pages?** That is the site's display limit, not the number of cars. The actor reads the same search index the site uses and splits large searches by price, so nothing is cut off.

**What if my URL has a filter the actor doesn't know?** The run stops before scraping and names the filter. Send the URL to the developer and support will be added.

**Are private sellers included?** carmarket.ch lists dealers only.

**Why are the dealer's phone and email empty?** *Include dealer contact details* is off. The dealer's name, address and map coordinates are always included.

**What happens if the run is moved to another server mid-way?** The actor reads back what it already delivered and continues; no car is delivered or charged twice.

### Support

Found a bug or need a field added? Open an issue on the actor's Issues tab or write to muhameddidovic@gmail.com.

### ⚠️ Disclaimer

This actor collects publicly available listing data from carmarket.ch. You are responsible for using the data in line with carmarket.ch's terms, the Swiss Federal Act on Data Protection (FADP), the GDPR where it applies, and any other law that applies to you. Dealer contact details are business information published by the dealers; do not use them for unsolicited marketing where the law forbids it.

### SEO Keywords

carmarket.ch scraper, carmarket scraper, Swiss car listings scraper, Switzerland used cars data, electric car listings Switzerland, EV battery capacity data, used EV market data Switzerland, car dealer data Switzerland, Occasion Elektroauto Schweiz, Auto Händler Daten Schweiz, VIN data scraper, car marketplace API, Emil Frey carmarket data

# Actor input Schema

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

Set your filters on carmarket.ch and paste the address of the results page: every filter in it is applied, and the whole result set is scraped, not just the 33 pages the site shows. Listing pages (`/de/fahrzeug/{name}-{id}`) and dealer pages (`/de/haendler/{name}-{id}`, all of that dealer's cars) work too, in German, French or Italian (`/fr/recherche`, `/it/cerca`). The language of the URL sets the language of the values. Example: \["https://carmarket.ch/de/suche?fuelType=g%7C4\&vehicleCondition=2"] (used electric cars).

## `maxItems` (type: `integer`):

Most listings to deliver across the whole run; 0 means no limit. A search the limit cuts short is not judged by the completeness check. Non-paying users are capped at 100. Default: 1000.

## `includeContactDetails` (type: `boolean`):

Adds the dealer's phones (the number the listing shows, usually a call-tracking number, and the dealer's own), email and website to `seller` and to `jsonLd`. Charged once per dealer per run (event `contact-details`), however many cars the dealer lists. Off: `seller` keeps the dealer's id, name, address and map coordinates. Default: off.

## `includeRawData` (type: `boolean`):

Adds the vehicle record exactly as carmarket.ch's API returns it, under `raw`. Every field is already in the row; turn this on only to see the source. Default: off.

## `failOnIncomplete` (type: `boolean`):

End the run as FAILED when a search's delivered listings fall short of its reported count by more than the threshold below. Searches stopped by Max results are not judged. Delivering more than reported never fails: listings are published while a run is in flight. Default: on.

## `completenessTolerancePercent` (type: `integer`):

Relative half of the threshold. Listings are withdrawn while a run is in flight, so a strict match would fail runs over ordinary churn. Default: 1.

## `completenessToleranceAbsolute` (type: `integer`):

Absolute floor of the threshold; the larger of the two wins. Default: 25.

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

Leave empty. carmarket.ch's data comes from two public JSON services that need no proxy. Set this only if your requests must leave through a proxy. Default: no proxy.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://carmarket.ch/de/suche?fuelType=g%7C4&vehicleCondition=2"
    }
  ],
  "maxItems": 100,
  "includeContactDetails": false,
  "includeRawData": false,
  "failOnIncomplete": true,
  "completenessTolerancePercent": 1,
  "completenessToleranceAbsolute": 25
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `completeness` (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": [
        {
            "url": "https://carmarket.ch/de/suche?fuelType=g%7C4&vehicleCondition=2"
        }
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/carmarket-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": [{ "url": "https://carmarket.ch/de/suche?fuelType=g%7C4&vehicleCondition=2" }],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/carmarket-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": [
    {
      "url": "https://carmarket.ch/de/suche?fuelType=g%7C4&vehicleCondition=2"
    }
  ],
  "maxItems": 100
}' |
apify call memo23/carmarket-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/carmarket-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/KUkI8oesCxvXgEZBN/builds/KkmPh6S8VlyIEayPB/openapi.json
