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

39

Total users

5

Monthly active users

8 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).
  • Seller profile and coordinates on every row — street, zip, city, typed phones, website and Google place id from the seller profile, plus the seller's latitude and longitude with their source.
  • Dealers-only filter — sellerTypes: ["professional"] sent to the search, so private listings never come back.
  • Completeness check — every search's reported count is compared with what was delivered; a short run ends as FAILED instead of passing for a small market.
  • 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. The API rejects hybrid and plugin-hybrid (HTTP 400), so the form's Hybrid and Plug-in Hybrid options send hev-petrol + hev-diesel and phev-petrol + phev-diesel
BodybodyTypes: [string]Plural array
ConditionconditionTypes: [string]Plural array: new, pre-registered, demonstration, used, oldtimer
Seller typesellerTypes: [string]professional (dealers) or private
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. Types: RELEVANCE, PRICE, MILEAGE, CREATED_DATE, FIRST_REGISTRATION_DATE, HORSE_POWER. Any sort but RELEVANCE and CREATED_DATE gets CREATED_DATE DESC as a second key (see below)

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.

Stable paging

Listings that share a sort value (the same price, the same mileage) have no fixed order among themselves, so between two page requests they can swap places: one comes twice, another never. Measured 06.10.2026 on 980 used electric dealer cars at 25,000–29,999 CHF: sorted by price alone, the 49 pages held 904 distinct ids. The actor adds CREATED_DATE DESC as a second key to every sort but Relevance and Newest; with it, every sort returned all 976 dealer and all 105 private listings in that band.

Relevance has a different problem: on some result sets the server pages it with an offset error. The 105 private listings above came back as 120 rows with 99 distinct ids, on every pass, with page 3's last 10 listings repeated at the top of page 4 and again from page 4 to 5. A second sort key does not help. So when a Relevance search shows repeated listings and comes up short of its count, the actor reads it once more sorted newest first and adds only the listings the first pass missed (105 of 105 in that case). An id already delivered for the same search is never pushed twice.

Completeness check

The first page of every search reports totalElements. At the end of the run the actor compares it with the distinct listings it delivered for that search, logs the comparison, writes it to the COMPLETENESS record in the run's key-value store, and puts the summary in the status message. When the shortfall exceeds the larger of 1% and 25 listings (completenessTolerancePercent, completenessToleranceAbsolute), the run ends as FAILED. A search stopped by maxItems is not judged, a search whose first page never loaded fails outright, and delivering more than reported (listings published mid-run) never fails. Turn the gate off with failOnIncomplete: false.

When Apify migrates a run to another server mid-run, the actor starts again on the new one. It reads back the rows already in its dataset (each row's searchSegment names its search), so no listing is pushed twice and every search keeps its delivered count. Each search's reported count is kept in the COMPLETENESS_STATE record, so the restarted run is judged against the same numbers.

Seller profile and coordinates

With includeSellerDetails (on by default) every row gets a seller object from GET api.autoscout24.ch/v1/sellers/{id}, with the API's own field names and values, and a sellerCoordinates object. Each seller is fetched once per run. The coordinates follow the pin next to the address on the seller page:

sellerCoordinates.sourceWhere the coordinates come from
seller_locationThe dealer entered them on AutoScout24 (location in the profile; the pin links to ?query=lat,lng).
google_placeThe pin searches the dealer's Google place. A ChIJ… place id encodes Google's feature id; the actor asks Google for that place and keeps the answer only when the feature id matches.
address_swisstopoNo usable link: the street, zip and city from the profile, geocoded by swisstopo's federal address search.
address_googleThe same address, geocoded by Google, when swisstopo has no match in that zip code.
nullNothing to geocode (private sellers publish no street) or no match.

Sample of 511 dealer profiles on 06.10.2026: 15 had their own location, 401 were placed through their Google place, 94 by address, 1 not at all (two branches typed into one address field). Google-place coordinates sat a median 19 m from swisstopo's point for the same street address.

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

Paste full detail URLs. The platform's input check refuses anything that is not a URL, so a bare listing id is rejected before the run starts; put it in a URL instead (https://www.autoscout24.ch/de/d/20464837).

{
"filterLanguage": "de",
"startUrls": [
{ "url": "https://www.autoscout24.ch/de/d/20703068" },
{ "url": "https://www.autoscout24.ch/fr/d/20462882" },
{ "url": "https://www.autoscout24.ch/it/d/20464837" }
],
"maxItems": 100
}

The language comes from the URL (/de/, /fr/, /it/, /en/).

Input field reference

FieldTypeDescription
startUrls[{ url }]Detail-page URLs (/de/d/{id}, /fr/d/{id}, …) or a search URL copied from the site. From a search URL the actor reads make/model, price, year, mileage, power, sort, seller type, and every ticked fuel type, body type and condition.
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|used|oldtimerSent to the API as a search filter.
filterFuelTypeelectric|petrol|diesel|hybrid|mhev-petrol|mhev-diesel|plugin-hybridSent to the API as a search filter. hybrid covers petrol and diesel full hybrids, plugin-hybrid petrol and diesel plug-in hybrids.
filterBodyTypesuv|saloon|estate|coupe|cabriolet|small-car|pickup|minivan|busClient-side.
filterSellerTypeprofessional|privateSent to the API as sellerTypes. professional = dealers only. Empty = any seller.
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|CREATED_DATE|YEAR|POWERWorks server-side. Default RELEVANCE. YEAR and POWER are sent as FIRST_REGISTRATION_DATE and HORSE_POWER (the API rejects the short names).
sortOrderDESC|ASCDefault DESC.
enrichDetailsboolWhen true, fetch /v1/listings/{id} per result for extra fields. Doubles request count.
includeSellerDetailsboolSeller profile and seller coordinates on every row. Default true.
failOnIncompleteboolEnd the run as FAILED when a search's shortfall exceeds the threshold. Default true.
completenessTolerancePercent / completenessToleranceAbsoluteintThe threshold: the larger of this percentage of the reported count and this many listings. Defaults 1 and 25.
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,
"accidentFree": true,
"currentlyDamaged": null, // AutoScout24.ch does not publish this
"roadworthy": null, // AutoScout24.ch does not publish this
"hasWarranty": true,
"warrantyType": "from-delivery",
"sellerId": 123456, "sellerName": "…", "sellerType": "professional",
"sellerCity": "Zürich", "sellerZipCode": "8001",
"seller": {
"id": 64129, "name": "ADRAGNA AUTOMOBILE", "type": "professional",
"address": "Bernstrasse 64", "zipCode": "8952", "city": "Schlieren",
"phones": [{ "number": "+41764379004", "type": "sales" }, { "number": "+41763341416", "type": "business" }],
"website": null,
"googlePlaceId": "ChIJDbMwRQANkEcRgHKo2z6xmng"
},
"sellerDetailsFetched": true, // false when the profile request failed; `seller` then holds the search data
"sellerCoordinates": { "latitude": 47.402593, "longitude": 8.4385758, "source": "google_place" },
"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" }
}

accidentFree, currentlyDamaged and roadworthy use the same names and meaning as our mobile.de and AutoScout24 (DE, IT, ...) scrapers: true / false, or null when the listing does not say. AutoScout24.ch publishes accident history only, so accidentFree is hadAccident inverted and the other two are always null.

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, drops ids already delivered for the same search, applies matchesClientSideFilters, looks up each row's seller, 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/sellers.ts — seller profiles and seller coordinates, cached per seller per run.
  • src/lib/completeness.ts — the per-search completeness check.
  • 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

🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the Apify MCP server or the Apify API (actor: memo23/autoscout24-ch-scraper).

Purpose: Extract vehicle listings from AutoScout24 Switzerland (autoscout24.ch) via its public REST API — by search filters or by detail URL/id. Swiss market only (.de / .com use the sibling actor).

Minimal input:

{
"filterLanguage": "de",
"filterVehicleCategory": "car",
"maxItems": 50
}

To scrape specific listings instead, pass startUrls with detail URLs (https://www.autoscout24.ch/de/d/20703068) or search URLs — URLs win when both are set.

Output: one dataset row per listing — id, url, language, title, price, priceCurrency, make/makeKey/makeId, model/modelKey/modelId, firstRegistrationDate, firstRegistrationYear, mileage, fuelType, transmissionType, bodyType, conditionType, powerHp, powerKw, consumptionCombined, drive, hadAccident, accidentFree, currentlyDamaged, roadworthy, hasWarranty, warrantyType, sellerId/sellerName/sellerType/sellerCity/sellerZipCode, seller (profile: address, zipCode, city, phones, website, googlePlaceId), sellerDetailsFetched, sellerCoordinates (latitude, longitude, source), imageCount, images, source, searchSegment (the search that produced the row: the pasted search URL or filters plus the filter query; null for a pasted listing URL), raw. accidentFree is hadAccident inverted (null when the seller did not say). currentlyDamaged and roadworthy are always null because AutoScout24.ch does not publish them; they are there so rows line up with the mobile.de and AutoScout24 (DE, IT, ...) actors.

Behaviors an agent should know:

  • maxItems is required; non-paying users are capped at 60 (default 1000).
  • startUrls (detail or search URLs) take priority over the filter fields.
  • Category and sort apply server-side; make/model/fuel/body/condition/price/year/mileage/power apply client-side while paginating.
  • enrichDetails: true fetches the detail endpoint per listing (cylinders, doors, drive) and doubles the request count.
  • No proxy required (the API host is not behind Cloudflare); residential recommended only for very large runs.
  • Pay-per-event billing — see the Pricing tab on the actor page.

⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Auto Scout 24 Schweiz AG (part of Swiss Marketplace Group) or any of its subsidiaries. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available vehicle-listing data from AutoScout24.ch's public REST API — no authenticated endpoints, paid features, or content behind a login wall. Users are responsible for ensuring their use complies with AutoScout24.ch's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organization.

SEO Keywords

autoscout24 scraper, scrape autoscout24, autoscout24.ch scraper, autoscout24 api, Apify autoscout24, swiss car scraper, car listings scraper, used car scraper, vehicle data api, auto marketplace scraper, car price scraper, car market analysis, used car pricing data, dealer inventory scraper, switzerland automotive data, vehicle listings export, car dealership data, automotive market intelligence