# Europe Used Car Tracker: AutoScout24, Kleinanzeigen, Willhaben (`apizilla/europe-used-car-tracker`) Actor

Scrape used cars from AutoScout24 (8 countries), Kleinanzeigen.de and Willhaben.at in one run. The same car on two sites becomes one result. Monitor mode shows new cars, price drops, price rises and sold cars.

- **URL**: https://apify.com/apizilla/europe-used-car-tracker.md
- **Developed by:** [APIzilla](https://apify.com/apizilla) (community)
- **Categories:** Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 car scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Europe Used Car Tracker do?

Europe Used Car Tracker scrapes **used car listings** from **[AutoScout24](https://www.autoscout24.de)** in 8 countries, **[Kleinanzeigen.de](https://www.kleinanzeigen.de/s-autos/c216)** and **[Willhaben.at](https://www.willhaben.at/iad/gebrauchtwagen)** in one run.

AutoScout24 countries: Germany, Austria, Italy, France, Netherlands, Belgium, Spain and Luxembourg.

It finds the **same car on several portals** and gives you one clean record for it. It also tracks changes between runs: **new cars, price drops, price rises, sold or removed cars** and cars that **came back**.

Run it once, or put it on a schedule and get a daily feed of new cars and price drops.

### Why use Europe Used Car Tracker?

- **Several portals, one dataset.** You do not need one scraper per site.
- **One format.** Every car has the same fields: price, km, first registration, fuel, gearbox, power, seller and location.
- **No duplicates.** A dealer often puts the same car on AutoScout24 and Willhaben. You get it once. The other copies are in `alsoListedOn`.
- **Change alerts.** Turn on monitor mode and every car gets a `changeType`: `new`, `price_drop`, `price_rise`, `back` or `unchanged`. Cars that are gone come as `removed`.
- **Fast and cheap.** No browser. Plain HTTP requests. 512 MB of memory is enough.
- **Pay per car.** Not per page.

Typical users: car dealers, car buyers, importers and exporters, leasing and fleet teams, price analysts and car apps.

You also get everything the Apify platform offers: scheduling, API access, webhooks, integrations (Google Sheets, Make, Zapier, Slack) and proxies.

### What data can Europe Used Car Tracker extract?

| Field | What it is |
| --- | --- |
| `title`, `url` | Ad title and link |
| `source`, `alsoListedOn` | Main portal and the same car on other portals |
| `make`, `model`, `version` | Brand, model and trim |
| `price`, `currency` | Price in EUR |
| `mileageKm` | Mileage in km |
| `firstRegistration` | First registration, for example `2021-06` |
| `fuel`, `gearbox` | petrol, diesel, electric, hybrid ... and manual or automatic |
| `powerKw`, `powerHp` | Power |
| `bodyType`, `colour` | Body type and colour |
| `sellerType`, `sellerName` | dealer or private, and the dealer name |
| `city`, `postcode`, `country`, `lat`, `lon` | Location |
| `images` | Up to 10 photos |
| `listedAt` | Date of the ad |
| `description`, `features` | Seller text and equipment (with Include details) |
| `changeType`, `previousPrice`, `priceChange`, `priceHistory` | Changes in monitor mode |
| `firstSeenAt`, `lastSeenAt`, `removedAt` | When the monitor saw the car |

Some fields only come with **Include details** turned on: description, equipment, and on some portals colour, body type, exact coordinates and the month of first registration.

### How to scrape used cars from AutoScout24, Kleinanzeigen and Willhaben

1. Open the Actor and go to the **Input** tab.
2. Type a **Make** and a **Model**, for example `Volkswagen` and `Golf`.
3. Pick the **Countries**.
4. Optional: set price, year, mileage, fuel, gearbox, or a postcode and radius.
5. Set **Max cars per portal**.
6. Optional: turn on **Monitor changes** and add a schedule, for example every morning.
7. Click **Start**. Download the results as JSON, CSV, Excel or HTML.

Example input:

```json
{
    "make": "Skoda",
    "model": "Octavia",
    "countries": ["DE", "AT"],
    "priceMax": 25000,
    "yearMin": 2019,
    "fuel": "diesel",
    "gearbox": "automatic",
    "maxListingsPerPortal": 50,
    "monitor": true
}
```

### How much does it cost to scrape used cars?

This Actor uses pay per event pricing. You only pay for results. Failed or blocked pages cost nothing.

| Event | When you pay | Price per 1,000 |
| --- | --- | --- |
| `listing-scraped` | Once per unique car in the results | $1.80 |
| `listing-details` | Once per car, only when Include details is on | $1.00 |
| `change-event` | Once per change (new, price drop, price rise, removed, back), only in monitor mode | $0.50 |
| `apify-actor-start` | When a run starts. One event per GB of memory, at least one | $1.00 (about $0.001 per run at the default 512 MB) |

Example: 1,000 cars without details cost about $1.80.

A removed car only costs a `change-event`. Unchanged cars do not cost a `change-event`.

You can set a maximum cost per run. The Actor checks the price of all events for a car before it saves it. If they do not fit, it stops cleanly. You never pay for a car that was not saved.

The Pricing tab shows the exact prices.

### Input

See the **Input** tab for all options. The most important ones:

- **Make** and **Model**: use the names the portals use, for example `Mercedes-Benz` and `C-Klasse`, or `BMW` and `3er`.
- **Countries**: AutoScout24 runs in every country you pick. Kleinanzeigen needs Germany. Willhaben needs Austria.
- **Filters**: min and max price, first registration years, max mileage, fuel and gearbox.
- **Postcode** and **Radius**: only cars near you. Kleinanzeigen needs a German postcode for this. Willhaben has no radius search, so we filter Willhaben cars by distance.
- **Max cars per portal**: default 20. For AutoScout24 every country counts as its own portal. AutoScout24 shows at most 400 cars per search, so use filters for bigger searches.
- **Sort**: newest ads first, or cheapest first.
- **Include details**: off by default. On means one extra page per car.
- **Monitor changes** and **Monitor name**: runs with the same name are compared.
- **Proxy**: Apify Proxy is on by default. Every portal starts on datacenter proxies. If a portal blocks them, that portal switches to residential proxies by itself. This costs you nothing extra.

### Output

Each item is one unique car. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
    "id": "car-3f9a1c2b4d5e6f70",
    "source": "willhaben",
    "url": "https://www.willhaben.at/iad/gebrauchtwagen/d/auto/...",
    "alsoListedOn": [{ "source": "autoscout24", "sourceListingId": "326bf2d3-...", "url": "https://www.autoscout24.de/angebote/...", "price": 19990 }],
    "title": "Skoda Octavia Combi 2.0 TDI Style DSG",
    "make": "Skoda",
    "model": "Octavia",
    "price": 19490,
    "currency": "EUR",
    "mileageKm": 84500,
    "firstRegistration": "2021-03",
    "fuel": "diesel",
    "gearbox": "automatic",
    "powerKw": 110,
    "powerHp": 150,
    "sellerType": "dealer",
    "sellerName": "Autohaus Muster GmbH",
    "city": "Wien",
    "postcode": "1210",
    "country": "AT",
    "changeType": "price_drop",
    "previousPrice": 19990,
    "priceChange": -500
}
```

The run also saves a short summary in the key-value store under `OUTPUT`. It shows the status of every portal and country (ok, partial, blocked, failed), how many cars came from each, how many duplicates were merged and how many changes were found.

### Tips

- Start small. Use a low **Max cars per portal** to test your search.
- Leave **Include details** off if you only need price, km, year, fuel and location. It is faster and cheaper.
- For alerts, turn on **Monitor changes**, keep the same **Monitor name**, and schedule the Actor. Use the **Changes only** view or filter by `changeType`.
- A car is only marked `removed` when its portal worked fine and the search was complete (not cut by the max). If a portal was blocked, we do not mark its cars as removed.
- If you change the filters, the monitor does not report removed cars for that run.

### How does the merge work?

Two ads from different portals are the same car when all of this is true:

- same make and model,
- first registration within 1 month,
- mileage within 2 percent or 1,000 km,
- price within 10 percent,
- same country, and same postcode or within about 30 km,
- fuel, gearbox and power do not contradict each other.

If both ads have a VIN, the VIN decides. The cheapest copy becomes the main record. We keep the rules strict, so two different cars are very rarely merged.

### FAQ and support

**Is it legal to scrape car portals?**
Our Actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our Actors, when used for ethical purposes by Apify users, are safe. However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

This Actor does not collect phone numbers. For private sellers it does not save a name.

**Is mobile.de included?**
Not yet. mobile.de blocks simple requests. It may come later as an option with a residential proxy.

**A portal shows "blocked" in the summary. What can I do?**
Run it again a bit later, or pick the RESIDENTIAL proxy group yourself. Lower the number of cars.

**Can I use it from my own code?**
Yes. See the **API** tab.

**Something is wrong or missing?**
Please open an issue in the **Issues** tab. We usually reply fast.

# Actor input Schema

## `make` (type: `string`):

Car brand, for example "Volkswagen", "BMW", "Mercedes-Benz", "Skoda". Leave empty for all brands.

## `model` (type: `string`):

Model, for example "Golf", "3er", "C-Klasse", "Octavia". Use the name the portals use (German names on AutoScout24.de). Needs a make.

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

AutoScout24 is searched in every country you pick. Kleinanzeigen only runs when Germany is picked, Willhaben only when Austria is picked.

## `priceMin` (type: `integer`):

Lowest price in euros.

## `priceMax` (type: `integer`):

Highest price in euros.

## `yearMin` (type: `integer`):

Oldest first registration year, for example 2015.

## `yearMax` (type: `integer`):

Newest first registration year.

## `mileageMax` (type: `integer`):

Highest mileage in kilometres.

## `fuel` (type: `string`):

Only cars with this fuel. Empty means all.

## `gearbox` (type: `string`):

Only cars with this gearbox. Empty means all.

## `postcode` (type: `string`):

Only cars near this postcode, for example "80331" (Munich). Leave empty to search the whole country.

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

Distance around the postcode. Default 50 km.

## `postcodeCountry` (type: `string`):

The country the postcode is in. Kleinanzeigen needs a German postcode for a radius search.

## `sources` (type: `array`):

Which websites to search.

## `maxListingsPerPortal` (type: `integer`):

Stop after this many cars from each portal. For AutoScout24 every country counts as its own portal. Lower is cheaper and faster.

## `sortBy` (type: `string`):

Which cars come first when there are more than the max: the newest ads or the cheapest.

## `includeNewCars` (type: `boolean`):

Off: used cars only.

## `includeDetails` (type: `boolean`):

Open every car's page to get the description, equipment, colour, body type, exact coordinates and the date the ad went online. Slower, and costs one extra event per car.

## `monitor` (type: `boolean`):

Compare with the last run and mark each car as new, price_drop, price_rise, back or unchanged. Cars that are gone are added as removed. Use it with a schedule, for example every day.

## `monitorName` (type: `string`):

Runs with the same name are compared with each other. Letters, numbers and dashes. Leave empty to make one from your filters.

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

Default: Apify Proxy without a group. Every portal starts on cheap datacenter proxies. If a portal blocks them, that portal switches to residential proxies automatically for the rest of the run (no extra cost for you). Pick a group yourself to turn this off.

## Actor input object example

```json
{
  "make": "Volkswagen",
  "model": "Golf",
  "countries": [
    "DE",
    "AT"
  ],
  "postcodeCountry": "DE",
  "sources": [
    "autoscout24",
    "kleinanzeigen",
    "willhaben"
  ],
  "maxListingsPerPortal": 20,
  "sortBy": "newest",
  "includeNewCars": false,
  "includeDetails": false,
  "monitor": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one item per unique car

## `summary` (type: `string`):

Status per portal and country, counts and charged events

# 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 = {
    "make": "Volkswagen",
    "model": "Golf",
    "countries": [
        "DE",
        "AT"
    ],
    "sources": [
        "autoscout24",
        "kleinanzeigen",
        "willhaben"
    ],
    "maxListingsPerPortal": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apizilla/europe-used-car-tracker").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 = {
    "make": "Volkswagen",
    "model": "Golf",
    "countries": [
        "DE",
        "AT",
    ],
    "sources": [
        "autoscout24",
        "kleinanzeigen",
        "willhaben",
    ],
    "maxListingsPerPortal": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("apizilla/europe-used-car-tracker").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 '{
  "make": "Volkswagen",
  "model": "Golf",
  "countries": [
    "DE",
    "AT"
  ],
  "sources": [
    "autoscout24",
    "kleinanzeigen",
    "willhaben"
  ],
  "maxListingsPerPortal": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call apizilla/europe-used-car-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apizilla/europe-used-car-tracker"
        }
    }
}
```

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/R8IhcUSHyzweSulee/builds/p0bXeRN27cPx5AFxt/openapi.json
