# AutoScout24 Scraper - Used Car Listings & Price Drop Monitor (`neverempty/autoscout24-listings-monitor`) Actor

Schedule it hourly or daily and get only new used-car listings, price drops and removed cars from AutoScout24 in Germany, Italy, France, Netherlands, Belgium, Austria, Spain and Luxembourg. Price with currency, price rating, mileage, year, fuel, power, dealer and photo. No login. JSON, CSV or Excel.

- **URL**: https://apify.com/neverempty/autoscout24-listings-monitor.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 car listing returneds

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

## AutoScout24 Scraper - Used Car Listings & Price Drop Monitor

**Schedule it hourly or daily → get only new listings & price drops.** This Actor watches **AutoScout24** used-car searches in **Germany, Italy, France, Netherlands, Belgium, Austria, Spain and Luxembourg** and returns only what changed since the last run: **new cars**, **price drops and rises** (with the previous price) and **removed cars**. Each row has the price **with its currency**, AutoScout24's **price rating**, first registration, mileage, fuel, transmission, power, colour, location, **dealer or private seller**, dealer name, photo and link. Search by **make and model**, **price**, **year**, **mileage**, **fuel**, **transmission**, **seller type** and **postal code + radius**, or paste an AutoScout24 search URL with the site's own filters. No login, no API key. Export as JSON, CSV or Excel, or send rows to Google Sheets, Slack, Make, Zapier or n8n with Apify integrations.

- **Only the changes, every run.** Turn on **Monitor mode** and schedule the Actor. The first run returns the newest cars as a starting point; every later run returns just the changes: `new`, `price_drop`, `price_up` and `removed` rows (each kind can be switched off). You pay for the changes plus a small run start fee per check, not for the same cars again.
- **Price drops with the old price.** A car you already got whose price changed comes back as `price_drop` or `price_up` with `previousPrice` and `priceChange` (for example `-1000`).
- **Removed cars.** A car you got before that is gone from the newest part of the list the watch reads (sold, withdrawn or no longer matching) comes back once as `removed`, with its last title, link and price.
- **New means new.** Cars that only moved up from further down the list are not reported as new.
- **8 countries, one run.** Makes/models times countries, plus pasted search URLs, up to 10 searches per run. A model name that a country spells differently (for example `bmw/3er` on autoscout24.it) is followed to that country's own search.
- **Clean numbers.** `price` is a number in `currency` (EUR), `mileageKm`, `powerKw` / `powerHp` and `engineCcm` are numbers, `firstRegistration` is `YYYY-MM`.
- **Free rows when there is nothing to deliver.** No cars, nothing changed, an unknown make or model, or a page that could not be read come back as free rows that say why.
- **Light.** 256 MB by default; a monitor check of one search with the default settings reads 4 pages.

### What you get

One row per car. Example (the first check of a watch on AutoScout24 Germany, `bmw/3er`, 2026-10-28):

```json
{
  "status": "ok",
  "changeType": "new",
  "isFirstCheck": true,
  "listingId": "a5977da1-bae4-4876-9c16-5c517179684c",
  "url": "https://www.autoscout24.de/angebote/bmw-3er-d-touring-advantage-aut-led-navi-pdc-diesel-schwarz-cat_ma13gr100038ge26va106mt123tr170-a5977da1-bae4-4876-9c16-5c517179684c",
  "title": "BMW 3er Touring 316d",
  "make": "BMW",
  "model": "3er",
  "modelDetail": "316d",
  "version": "d Touring Advantage Aut.LED Navi PDC",
  "variant": "Touring",
  "price": 13900,
  "currency": "EUR",
  "previousPrice": null,
  "priceChange": null,
  "priceFormatted": "€ 13.900",
  "isConditionalPrice": false,
  "priceVatLabel": "inkl. MwSt.",
  "priceRating": "top-price",
  "firstRegistration": "2019-05",
  "mileageKm": 126000,
  "fuel": "Diesel",
  "transmission": "Automatik",
  "powerKw": 85,
  "powerHp": 116,
  "engineCcm": 1995,
  "color": "black",
  "isDamaged": false,
  "locationCountry": "DE",
  "zip": "12347",
  "city": "Berlin",
  "sellerType": "dealer",
  "dealerName": "Auto Mivex GmbH",
  "dealerRating": 5,
  "dealerRatingCount": 68,
  "photoUrl": "https://prod.pictures.autoscout24.net/listing-images/a5977da1-bae4-4876-9c16-5c517179684c_93d26059-d93b-4fe2-b4fb-608d74702dab.jpg/250x188.webp",
  "photoCount": 42,
  "firstSeenAt": "2026-10-28T06:26:00.000Z",
  "country": "de",
  "positionInSearch": 1,
  "listingsInSearch": 11163,
  "searchUrl": "https://www.autoscout24.de/lst/bmw/3er?atype=C&cy=D&sort=age&desc=1",
  "watchName": null,
  "checkedAt": "2026-10-28T06:26:07.404Z"
}
```

| Field | What it is |
|---|---|
| `changeType` | Monitor mode: `new`, `price_drop`, `price_up`, `removed` or `unchanged`. Empty in a normal search. |
| `isFirstCheck` | `true` on the rows of a watch's first run (the starting point). |
| `price`, `currency` | Price as a number and its currency. Empty when the listing shows no price. |
| `previousPrice`, `priceChange` | The price at the previous check and the difference (negative = cheaper). |
| `priceRating` | AutoScout24's price rating: `top-price`, `good-price`, `fair-price`, `somewhat-expensive`, `expensive` (as the site names them), or empty when the site shows no rating. |
| `firstRegistration` | Month of first registration, `YYYY-MM`. |
| `mileageKm`, `powerKw`, `powerHp`, `engineCcm` | Numbers. |
| `fuel`, `transmission` | As shown on the site, in its language. |
| `color` | Exterior colour in English when the listing address names it. |
| `sellerType` | `dealer` or `private`. |
| `dealerName`, `dealerContactName`, `dealerPhones`, `street`, `dealerRating` | Dealer details as shown in the list. Empty for private sellers. |
| `firstSeenAt` | When this watch first saw the car (the list does not show a publication date). |
| `positionInSearch`, `listingsInSearch` | Position in the newest-first list and how many cars the search has. |
| `status` | `ok` for a car; otherwise a free row with a `note` that says why. |

### Input

```json
{
  "makeModels": ["bmw/3er", "volkswagen/golf"],
  "countries": ["de", "at"],
  "priceTo": 25000,
  "yearFrom": 2018,
  "mileageTo": 120000,
  "fuelTypes": ["diesel", "petrol"],
  "transmission": "automatic",
  "maxResultsPerSearch": 50,
  "monitorMode": true
}
```

- `makeModels`: `make/model` as in an AutoScout24 search address (`bmw/3er`, `mercedes-benz/c-klasse`, `fiat/500`), or a make alone (`audi`).
- `countries`: `de`, `it`, `fr`, `nl`, `be`, `at`, `es`, `lu`. Empty = Germany.
- `searchUrls`: paste an AutoScout24 search with any site filter (body type, power, colour, equipment ...). It is always read newest first.
- Filters: `priceFrom` / `priceTo` (EUR), `yearFrom` / `yearTo`, `mileageFrom` / `mileageTo` (km), `fuelTypes`, `transmission`, `sellerType`, `zipCode` + `radiusKm`.
- `maxResultsPerSearch`: 1 to 5,000 (default 50).
- Monitor mode: `monitorMode`, `includePriceChanges` (on), `includeRemoved` (on), `includeUnchanged` (off), `watchName`, `resetMonitoringState`.

### Monitor mode

1. Schedule the Actor (Schedules tab, for example every hour or every morning) with `monitorMode: true`.
2. The first run returns the newest `maxResultsPerSearch` cars of each search with `changeType: new` and `isFirstCheck: true`, and remembers them.
3. Every later run reads the newest `maxResultsPerSearch` cars plus one more page and returns:
   - `new`: cars that appeared since the previous check,
   - `price_drop` / `price_up`: cars you already got whose price changed, with `previousPrice`,
   - `removed`: cars you already got that are gone from the part of the list the watch reads.
4. A run where nothing changed returns one free `no-changes` row.
5. New cars that did not fit into `maxResultsPerSearch` or your maximum charge are not charged and come in the next run.
6. Use `watchName` to keep separate watches for the same search (one per client or per alert channel).

### Pricing

Pay per event:

- **Run start**: once per run that returns cars, and once per monitor-mode run that read and compared the list, even when nothing changed (it pays for the check).
- **Listing returned**: per car row delivered (`new`, `price_drop`, `price_up`, `removed`, `unchanged` or a normal search row). Free rows are never charged.

If your maximum total charge has no room for the run start fee plus one car, the run requests nothing and is charged nothing.

### Good to know

- Up to 5,000 cars per search in a normal run: large searches are read in price ranges, so cars without a price can be missing. Monitor mode reads only the newest part of each search.
- One AutoScout24 search pages through at most 200 pages (4,000 cars). Monitor mode watches the newest part of a search; for a very large search, narrow it (model, year, price, region) so new cars are not missed between checks.
- `removed` is judged on the part of the list the watch reads (the newest `maxResultsPerSearch` cars plus one page). A car you got long ago that has slid further down is not reported as removed.
- With a price filter, AutoScout24 leaves out cars that show no price. Splitting a large search into price ranges therefore skips cars without a price.
- `fuel`, `transmission` and `priceVatLabel` are the words shown on the site, in its language. The list shows no publication date, so `firstSeenAt` is when this watch first saw the car.
- Dealer contact names and phone numbers are returned only when AutoScout24 shows them in the search list. Nothing is collected from listing pages.
- Two schedules running the same search with the same `watchName` at the same moment can return the same new car twice; give each schedule its own `watchName`.
- Unofficial. Reads the public AutoScout24 search pages a person sees without logging in.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

## `makeModels` (type: `array`):

Schedule it hourly or daily with Monitor mode on to get only new listings and price drops. Write make/model as in an AutoScout24 search address, for example bmw/3er, volkswagen/golf, mercedes-benz/c-klasse, fiat/500, or just a make such as audi. Each one is searched in each country. Leave this and Search URLs empty to run the example bmw/3er on autoscout24.de.

## `countries` (type: `array`):

Which country's cars to list, each on its own AutoScout24 site. Empty = Germany. Prices are in euros.

## `searchUrls` (type: `array`):

Optional. Paste an AutoScout24 search address with all your filters set on the site, for example https://www.autoscout24.de/lst/bmw/3er?fregfrom=2018\&priceto=25000. The list is always read newest first. The filters below do not change a pasted URL.

## `priceFrom` (type: `integer`):

Optional. Lowest price in euros. With a price filter, cars without a price are not listed by AutoScout24.

## `priceTo` (type: `integer`):

Optional. Highest price in euros.

## `yearFrom` (type: `integer`):

Optional. Earliest year of first registration, for example 2018.

## `yearTo` (type: `integer`):

Optional. Latest year of first registration.

## `mileageFrom` (type: `integer`):

Optional. Lowest mileage in kilometres.

## `mileageTo` (type: `integer`):

Optional. Highest mileage in kilometres, for example 100000.

## `fuelTypes` (type: `array`):

Optional. Only cars with these fuels. Empty = all fuels.

## `transmission` (type: `string`):

Optional. Only automatic or only manual cars. Empty = both.

## `sellerType` (type: `string`):

Optional. Only dealers or only private sellers. Empty = both.

## `zipCode` (type: `string`):

Optional. Search around this postal code, for example 80331. Works with one country at a time.

## `radiusKm` (type: `integer`):

Optional. Distance from the postal code in kilometres, for example 50. Needs a postal code.

## `maxResultsPerSearch` (type: `integer`):

How many cars to return per search, newest first (empty = 50). One AutoScout24 search shows at most 4,000 cars; above that, a normal run reads the search in price ranges to reach more. In Monitor mode this is the most new cars returned per search and run; price changes and removed cars are always returned.

## `monitorMode` (type: `boolean`):

Schedule it hourly or daily and get only what changed. On: the first run returns the newest cars (changeType new, isFirstCheck true) and remembers them as the starting point. Every later run returns only cars that are new since the previous check (new), cars whose price went down or up (price_drop / price_up, with previousPrice) and cars that are gone from the list (removed). Each run that reads the list is charged the run start fee even when nothing changed; then a free row says so.

## `includePriceChanges` (type: `boolean`):

On (default): also return cars returned before whose price changed since the previous check, with previousPrice and priceChange. Off: no price change rows.

## `includeRemoved` (type: `boolean`):

On (default): also return cars returned before that are gone from the part of the list this watch reads (sold, withdrawn or no longer matching the search), with their last known title, link and price. Off: no removed rows.

## `includeUnchanged` (type: `boolean`):

Off (default): cars that did not change are not returned. On: return them too, with changeType unchanged (each is a charged row).

## `watchName` (type: `string`):

Optional. Keeps separate memories for Monitor mode, for example one per client (letters, digits, dot, dash, underscore; up to 40). Runs with the same watch name and the same search share what has already been returned.

## `resetMonitoringState` (type: `boolean`):

On: forget what this watch has seen for these searches before running, so this run is a first check again.

## Actor input object example

```json
{
  "makeModels": [
    "bmw/3er"
  ],
  "countries": [
    "de"
  ],
  "maxResultsPerSearch": 50,
  "includePriceChanges": true,
  "includeRemoved": true,
  "includeUnchanged": false
}
```

# Actor output Schema

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

One row per car: listing ID, link, make, model, version, price with currency, price rating, first registration, mileage, fuel, transmission, power, colour, location, seller type, dealer name and photo. In Monitor mode each row has changeType new, price_drop, price_up, removed or unchanged, with previousPrice. A search with no cars, nothing changed, an unknown make or model, a page that could not be read or a run that hit its maximum charge comes back as a free row that says why.

# 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 = {
    "makeModels": [
        "bmw/3er"
    ],
    "countries": [
        "de"
    ],
    "maxResultsPerSearch": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/autoscout24-listings-monitor").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 = {
    "makeModels": ["bmw/3er"],
    "countries": ["de"],
    "maxResultsPerSearch": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/autoscout24-listings-monitor").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 '{
  "makeModels": [
    "bmw/3er"
  ],
  "countries": [
    "de"
  ],
  "maxResultsPerSearch": 50
}' |
apify call neverempty/autoscout24-listings-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/autoscout24-listings-monitor"
        }
    }
}
```

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/r9GFJBBgRN6lK63aX/builds/uiZ7kmZFeZUZqG6Kq/openapi.json
