AutoScout24 [Only $1.25] Scraper · CH -> SWISS avatar

AutoScout24 [Only $1.25] Scraper · CH -> SWISS

Pricing

from $1.25 / 1,000 results

Go to Apify Store
AutoScout24 [Only $1.25] Scraper · CH -> SWISS

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

Muhamed Didovic

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

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:

EndpointMethodPurpose
POST /v1/listings/search?language={de|fr|it|en}POSTPaginated vehicle search (max page size 20)
GET /v1/listings/{id}?language={...}GETFull 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):

FilterField in request bodyNotes
Make / modelmakeModelVersions: [{ makeKey, modelKey }]Nested — not top-level makeKey
FuelfuelTypes: [string]Plural array; singular fuelType is silently ignored
BodybodyTypes: [string]Plural array
ConditionconditionTypes: [string]Plural array
Price (CHF)priceFrom, priceToInt
YearfirstRegistrationYearFrom, firstRegistrationYearToInt
Mileage (km)mileageFrom, mileageToInt
Power (HP)horsePowerFrom, horsePowerToInt — not powerFrom/powerTo
Vehicle categoryvehicleCategories: [string]Plural array
Sortsort: [{ 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

FieldTypeDescription
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.
filterLanguagede|fr|it|enResponse locale & detail-page URL prefix. Default de.
filterVehicleCategorycar|camper|truck|motorcycle|trailerWorks server-side. Default car.
filterMake / filterModelstringMake/model key (lowercase, hyphen-separated; e.g. bmw, mercedes-benz, x1). Applied client-side.
filterConditionTypenew|pre-registered|demonstration|usedClient-side.
filterFuelTypeelectric|petrol|diesel|hybrid|mhev-petrol|mhev-diesel|plugin-hybridClient-side.
filterBodyTypesuv|saloon|estate|coupe|cabriolet|small-car|pickup|minivan|busClient-side.
filterPriceFromCHF / filterPriceToCHFintCHF, inclusive. Client-side.
filterYearFrom / filterYearTointFirst-registration year, inclusive. Client-side.
filterMileageFrom / filterMileageTointkm, inclusive. Client-side.
filterPowerFromHP / filterPowerToHPintHP, inclusive. Client-side.
filterZipCode / filterRadiusKmstring + intSent to the API; not verified client-side (no geo lookup).
sortTypeRELEVANCE|PRICE|MILEAGE|YEAR|POWERWorks server-side. Default RELEVANCE.
sortOrderDESC|ASCDefault DESC.
enrichDetailsboolWhen true, fetch /v1/listings/{id} per result for extra fields. Doubles request count.
maxItemsintHard cap on output rows. Default 1000. Non-paying users are capped at 60.
maxConcurrency / minConcurrency / maxRequestRetriesintCrawlee tuning knobs.
proxyobjectApify 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_ITEMS respected.
  • src/routes.ts — two handlers:
    • LIST — POSTs to /v1/listings/search, applies matchesClientSideFilters, pushes rows, enqueues next page until maxItems or end.
    • DETAILS — GETs /v1/listings/{id}, merges with basicInfo from 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 package ch.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