AutoScout24 [Only $1.25] Scraper · CH -> SWISS
Pricing
from $1.25 / 1,000 results
AutoScout24 [Only $1.25] Scraper · CH -> SWISS
[Only $1.25] Scrape vehicle listings from AutoScout24.ch (Switzerland) via the public REST API. Supports filter-based search and direct detail page URLs. ℹ️ For custom solutions or support, contact : muhameddidovic@gmail.com
Pricing
from $1.25 / 1,000 results
Rating
0.0
(0)
Developer
Muhamed Didovic
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
AutoScout24 Scraper · CH
Overview
This scraper extracts vehicle listings from AutoScout24 Switzerland
(autoscout24.ch) — a separate product operated by Auto Scout 24 Schweiz AG (part of
Swiss Marketplace Group). It is not the same backend as .de / .com and other
AutoScout24 EU markets — those are operated by a different company and need a different
scraper.
Looking for listings from any other AutoScout24 market (
.de/.com/.it/.es/.fr/.be/.nl/.at/.lu)? Use the sibling actor: AutoScout24 Scraper · DE · AT · IT · ES · FR · BE · NL · LU · .com.
The scraper talks to the public api.autoscout24.ch REST API:
| Endpoint | Method | Purpose |
|---|---|---|
POST /v1/listings/search?language={de|fr|it|en} | POST | Paginated vehicle search (max page size 20) |
GET /v1/listings/{id}?language={...} | GET | Full structured detail JSON for one listing |
No authentication needed. The API host is not behind Cloudflare (unlike the public
www.autoscout24.ch HTML pages), so a proxy is not strictly required.
Features
- Filter mode — paginate through the entire car catalog and pull matching listings.
- Detail-URL mode — paste one or more
https://www.autoscout24.ch/{lang}/d/{id}URLs. - Optional detail enrichment — fetches the JSON detail endpoint for each match (extra fields like cylinders, doors, drive type, full consumption breakdown).
- All four UI languages:
de,fr,it,en. - Five vehicle categories:
car,camper,truck,motorcycle,trailer.
Server-side filtering
The POST /v1/listings/search endpoint honours all the major filters server-side, using
the same shape the website's own SSR uses (extracted from initialSearchState in a
Wayback Machine snapshot):
| Filter | Field in request body | Notes |
|---|---|---|
| Make / model | makeModelVersions: [{ makeKey, modelKey }] | Nested — not top-level makeKey |
| Fuel | fuelTypes: [string] | Plural array; singular fuelType is silently ignored |
| Body | bodyTypes: [string] | Plural array |
| Condition | conditionTypes: [string] | Plural array |
| Price (CHF) | priceFrom, priceTo | Int |
| Year | firstRegistrationYearFrom, firstRegistrationYearTo | Int |
| Mileage (km) | mileageFrom, mileageTo | Int |
| Power (HP) | horsePowerFrom, horsePowerTo | Int — not powerFrom/powerTo |
| Vehicle category | vehicleCategories: [string] | Plural array |
| Sort | sort: [{ type, order, variant: 'v1' }] | Server-side |
Result: a query that matches 341 listings on the website also returns 341 from
the API (no over-fetching). A matchesClientSideFilters pass still runs as a
defense-in-depth safety net but is normally a no-op.
Still client-side only (server-side shape not yet confirmed)
- ZIP code + radius (
zipCode/radiusKm) — sent but silently ignored - Warranty / accident (
hasWarranty/hasAccidentHistory) — sent but ignored
If you set these, the actor pages through results and applies them client-side. Send an example URL that uses one of these filters and we can extend support.
Input
Provide either startUrls (detail URLs) or filter fields. URLs always win when
both are set.
Filter-mode example
{"filterLanguage": "de","filterVehicleCategory": "car","filterMake": "bmw","filterModel": "x1","filterPriceFromCHF": 20000,"filterPriceToCHF": 50000,"filterYearFrom": 2020,"filterFuelType": "hybrid","sortType": "RELEVANCE","sortOrder": "DESC","enrichDetails": false,"maxItems": 100,"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }}
Detail-URL example
You can paste full URLs or bare numeric ids — both are accepted in the same startUrls array.
{"filterLanguage": "de","startUrls": [{ "url": "https://www.autoscout24.ch/de/d/20458677" },{ "url": "https://www.autoscout24.ch/fr/d/20462882" },{ "url": "20464837" }],"maxItems": 100}
For bare ids the language defaults to filterLanguage (which itself defaults to de).
Input field reference
| Field | Type | Description |
|---|---|---|
startUrls | [{ url }] | Detail-page URLs (/de/d/{id}, /fr/d/{id}, …) or bare numeric ids ("12345678"). Search/list URLs are not parsed — use filters instead. |
filterLanguage | de|fr|it|en | Response locale & detail-page URL prefix. Default de. |
filterVehicleCategory | car|camper|truck|motorcycle|trailer | Works server-side. Default car. |
filterMake / filterModel | string | Make/model key (lowercase, hyphen-separated; e.g. bmw, mercedes-benz, x1). Applied client-side. |
filterConditionType | new|pre-registered|demonstration|used | Client-side. |
filterFuelType | electric|petrol|diesel|hybrid|mhev-petrol|mhev-diesel|plugin-hybrid | Client-side. |
filterBodyType | suv|saloon|estate|coupe|cabriolet|small-car|pickup|minivan|bus | Client-side. |
filterPriceFromCHF / filterPriceToCHF | int | CHF, inclusive. Client-side. |
filterYearFrom / filterYearTo | int | First-registration year, inclusive. Client-side. |
filterMileageFrom / filterMileageTo | int | km, inclusive. Client-side. |
filterPowerFromHP / filterPowerToHP | int | HP, inclusive. Client-side. |
filterZipCode / filterRadiusKm | string + int | Sent to the API; not verified client-side (no geo lookup). |
sortType | RELEVANCE|PRICE|MILEAGE|YEAR|POWER | Works server-side. Default RELEVANCE. |
sortOrder | DESC|ASC | Default DESC. |
enrichDetails | bool | When true, fetch /v1/listings/{id} per result for extra fields. Doubles request count. |
maxItems | int | Hard cap on output rows. Default 1000. Non-paying users are capped at 60. |
maxConcurrency / minConcurrency / maxRequestRetries | int | Crawlee tuning knobs. |
proxy | object | Apify proxy config. Residential recommended only for very heavy runs. |
Output
Each pushed dataset row has this shape (selected fields shown):
{"id": 20458677,"url": "https://www.autoscout24.ch/de/d/20458677","language": "de","title": "M2 Coupé","price": 63890,"priceCurrency": "CHF","make": "BMW", "makeKey": "bmw", "makeId": 9,"model": "M2", "modelKey": "m2", "modelId": 999,"firstRegistrationDate": "2024-…","firstRegistrationYear": 2024,"mileage": 28900,"fuelType": "petrol","transmissionType": "automatic","bodyType": "coupe","conditionType": "used","powerHp": 460,"powerKw": 338,"consumptionCombined": 9.6,"drive": "rear","hadAccident": false,"hasWarranty": true,"warrantyType": "from-delivery","sellerId": 123456, "sellerName": "…", "sellerType": "professional","sellerCity": "Zürich", "sellerZipCode": "8001","imageCount": 17,"images": ["https://listing-images.autoscout24.ch/listing/…", "…"],"source": "list", // or "detail" when enrichDetails=true"raw": { "...": "full listing object as returned by the API" }}
Architecture
src/main.ts— input validation, dual-mode resolution, crawler setup. Free-user clamp +ACTOR_MAX_PAID_DATASET_ITEMSrespected.src/routes.ts— two handlers:LIST— POSTs to/v1/listings/search, appliesmatchesClientSideFilters, pushes rows, enqueues next page untilmaxItemsor end.DETAILS— GETs/v1/listings/{id}, merges withbasicInfofrom the list pass.
src/lib/buildSearchQuery.ts— payload builder + client-side filter predicate.src/lib/utils.ts— URL classification (isDetailPageUrl,extractListingId,extractLanguageFromUrl, …).
Tests
npm test # 61 unit tests, fully offline (sub-second)npm run test:live # 2 integration tests against the real CDN (~1 s, requires internet)
The offline suite covers URL classification, language extraction, filter matching, payload construction, start-URL/bare-id normalisation, and image-URL construction.
The live suite checks that the image-CDN host we construct (listing-images.autoscout24.ch)
still resolves to real images. Run it after any AutoScout24-side change to catch
silent breakage early. Not invoked by default so flaky networks don't break local dev.
Out of scope
- Pasting search/list URLs (
/de/s/...) is not supported — the URL → API mapping isn't published and parsing the query-string syntax (mk-bmw,mo-320, …) is fragile. Use the filter fields instead. - The Swiss site has a separate iOS app (App Store ID
295835058, Android packagech.autoscout24.autoscout24). The actor does not currently use any iOS-app-specific endpoints — those would need a mitmproxy capture to discover.
Support
For custom solutions, schema changes, or to report a broken endpoint: muhameddidovic@gmail.com