# willhaben Car Scraper (`lowlanddata/willhaben-car-scraper`) Actor

Used cars from willhaben.at as clean JSON: make, model, year, mileage, fuel, transmission and price as first-class columns. Dealer or private as a flag - seller identity and exact coordinates are never collected. Pay per result.

- **URL**: https://apify.com/lowlanddata/willhaben-car-scraper.md
- **Developed by:** [Lowland Data](https://apify.com/lowlanddata) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 88.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.69 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## willhaben Car Scraper — GDPR-safe used-car data

Turn **willhaben.at's Gebrauchtwagenbörse** — Austria's used-car board — into structured JSON. Make, model, year, mileage, power, fuel, gearbox and price arrive as first-class columns, not text buried in a title, so a price analysis or a bargain watch starts in a spreadsheet instead of a parsing project.

**Zero seller personal data.** Dealer names, seller IDs and exact map coordinates are structurally never collected — the extractor cannot emit them, so there is nothing to configure and nothing to forget. The single seller-derived field is `sellerType`: `private` or `dealer`. That flag alone tells you the market structure; everything identifying stays on willhaben.

This is the cars-only satellite of the [willhaben Scraper](https://apify.com/lowlanddata/willhaben-scraper), which covers the general Marktplatz.

### Quick start (30 seconds)

1. Type a car search into **searchQuery** — `golf tdi`, `tesla model 3` — or leave it empty to browse the newest cars across all of Austria.
2. Press **Start**.
3. Open the dataset's **Overview** tab for a make/model/year/km/price table, or **Export** as CSV, Excel or JSON.

A price band, newest-first sorting and a date window are there when you want them, and every input works on a Schedule.

### What you can build with it

- **Catch underpriced cars early.** `searchQuery: "bmw 320d"`, `priceMaxEur: 15000`, `sortBy: "date"` on an hourly Schedule — each new match arrives with `mileageKm`, `year` and `priceCents` already numeric, so a "price per remaining kilometer" alert is one formula away.
- **Study the Austrian used-car market.** Empty query, `maxItems: 500`, newest first — a live Austria-wide sample with `state`, `fuel`, `transmission` and `sellerType` on every row. Diesel share in Kärnten vs. Wien is a pivot table, not a research project.
- **Compare dealer and private pricing.** `sellerType` splits every result set in two. What does a dealer margin look like on a five-year-old Octavia? Run the query, group by the flag.
- **Feed a valuation model or AI agent.** Numeric specs, no personal data — rows go straight into a pipeline or an assistant without a scrubbing or compliance pass.

### What you get

One dataset item per car:

```json
{
  "listingId": "1226700001",
  "url": "https://www.willhaben.at/iad/gebrauchtwagen/d/auto/vw-golf-cabrio-1226700001/",
  "title": "VW Golf Cabrio 2.0 TDI DSG",
  "description": "Gepflegtes Cabrio, Service neu.",
  "make": "VW",
  "model": "Golf",
  "modelSpec": "Cabrio 2.0 TDI",
  "year": 2013,
  "mileageKm": 93400,
  "powerKw": 103,
  "fuel": "Diesel",
  "transmission": "Automatik",
  "bodyType": "Cabrio / Roadster",
  "condition": "Gebrauchtwagen",
  "previousOwners": 3,
  "seats": 4,
  "priceCents": 1250000,
  "currency": "EUR",
  "priceDisplay": "€ 12.500",
  "postedAt": "2026-08-26T18:29:00Z",
  "city": "Klosterneuburg",
  "postcode": "3400",
  "district": "Tulln",
  "state": "Niederösterreich",
  "sellerType": "private",
  "imageUrls": ["https://cache.willhaben.at/mmo/fixture/a1.jpg"]
}
```

Field notes, so you know exactly what you are buying:

- `make` and `model` come from willhaben's own car model data, not from parsing the title — `modelSpec` carries the trim and engine line on top.
- `year`, `mileageKm`, `powerKw`, `previousOwners` and `seats` are real integers. When a seller types junk into a numeric field, the value is dropped rather than passed through — a null beats a poisoned column.
- `fuel`, `transmission`, `bodyType` and `condition` are the site's own labels (Diesel, Automatik, Kombi, Gebrauchtwagen, ...), in German as willhaben shows them.
- `priceCents` is the asking price in euro cents; `priceDisplay` keeps the exact on-site string for the rare non-numeric price.
- Location stops at municipality level — `city`, `postcode`, `district`, `state`. willhaben knows the exact coordinates; this actor deliberately never reads them.
- Everything comes from the search result cards. Spec values the card does not carry are null — no detail-page visits, which is also why runs finish in seconds.

### What does willhaben car data cost?

$1.99 per 1,000 cars delivered. Pay-per-event, no subscription, and a run that delivers nothing costs nothing. Concretely:

- **50 cars ≈ $0.10** — an hourly watch on one model.
- **500 cars ≈ $1.00** — the default `maxItems`, a market snapshot.
- **2,000 cars ≈ $3.98** — a whole segment across Austria.

Platform usage of your runs is included in that price — no compute or proxy line items on top. Plain datacenter proxies are all it needs, and a scoped run finishes in seconds. On the Apify free plan, runs return a 25-car sample — enough to judge the columns against your real search before paying anything.

### Not technical? Let your AI assistant set it up

Paste this into ChatGPT, Claude or any assistant, replace the bracketed line, and let it walk you through:

```text
Help me set up the "willhaben Car Scraper" actor on Apify
(https://apify.com/lowlanddata/willhaben-car-scraper). One step at a time, please.

The cars I want to watch: [E.G. "diesel kombis under 12,000 euros"]

Walk me through:
1. Choosing my input: searchQuery (what I'd search on willhaben's car section —
   or empty to browse everything), an optional priceMinEur/priceMaxEur band,
   sortBy "date" for newest-first monitoring, and maxItems.
2. Creating a free Apify account (apify.com), opening the actor page, filling the
   Input form with those values, and starting a run.
3. Adding a daily Schedule in the Apify Console with the same input, plus an email
   or Slack integration so new matches reach me on their own.
4. Exporting results to Excel/CSV — or reading them from the API if I code.
5. At the end, if the results fit, remind me to rate the actor on its page and to
   report anything broken or missing on its Issues tab.
```

### Input

| Field                | Description                                                                                                 |
| -------------------- | ----------------------------------------------------------------------------------------------------------- |
| `searchQuery`        | Keyword for willhaben's car search, e.g. `golf tdi`. Optional — empty browses the newest cars Austria-wide. |
| `priceMinEur`        | Only cars costing at least this many euros.                                                                 |
| `priceMaxEur`        | Only cars costing at most this many euros.                                                                  |
| `sortBy`             | `date` (newest first, default), `price_asc`, `price_desc`, or `relevance`.                                  |
| `postedAfter`        | Only cars posted on or after this date (YYYY-MM-DD). Ends the run early with newest-first sorting.          |
| `postedBefore`       | Only cars posted on or before this date (YYYY-MM-DD).                                                       |
| `maxItems`           | Stop after this many cars (default 500). Free-plan runs are capped at 25.                                   |
| `proxyConfiguration` | Proxy settings; keep Apify proxy enabled.                                                                   |

No field is mandatory — an empty input is a valid run. An impossible combination, such as a minimum price above the maximum, fails immediately and says so in the run's status message.

### Use it from your code

One HTTP call starts a run and returns the cars (good for scoped runs up to ~5 minutes):

```bash
curl "https://api.apify.com/v2/acts/lowlanddata~willhaben-car-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -X POST -H "Content-Type: application/json" \
  -d '{"searchQuery": "golf tdi", "priceMaxEur": 15000, "maxItems": 100}'
```

Node.js:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lowlanddata/willhaben-car-scraper').call({
  searchQuery: 'golf tdi',
  priceMaxEur: 15000,
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lowlanddata/willhaben-car-scraper").call(
    run_input={"searchQuery": "golf tdi", "priceMaxEur": 15000, "maxItems": 100})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Larger jobs run better asynchronously: start the run, let the finished-run webhook fire, then fetch the dataset. Schedules, webhooks and the Make/Zapier/n8n integrations all apply — this is a standard Apify actor.

### Use it with AI agents (MCP)

Through Apify's hosted MCP server, Claude, Cursor and other MCP-capable agents can drive this scraper as a tool — the agent picks the query, runs it and reads the cars back, no glue code involved.

Claude Code:

```bash
claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/willhaben-car-scraper"
```

Cursor or Claude Desktop (add a custom connector / MCP server with this URL):

```text
https://mcp.apify.com?actors=lowlanddata/willhaben-car-scraper
```

Runs bill to the Apify account you sign in with. Per-client setup: [Apify MCP docs](https://docs.apify.com/platform/integrations/mcp), or this actor's own MCP page: [apify.com/lowlanddata/willhaben-car-scraper/api/mcp](https://apify.com/lowlanddata/willhaben-car-scraper/api/mcp).

Prompts that work once connected:

- "Find diesel Kombis under 12,000 euros on willhaben and rank them by price per 10,000 km of remaining life."
- "Get the 100 newest Tesla listings from willhaben and compare private vs dealer asking prices."
- "Watch willhaben for a VW T5 under 20,000 euros and tell me the moment one appears."

### Is it legal to scrape willhaben car listings?

Asking prices, specs and municipality-level locations of publicly advertised cars are public commercial information. The usual hard part — personal data — is designed out of this actor rather than argued around: the extractor maps a fixed whitelist of attributes, and the advertiser block, seller identifiers and exact coordinates are simply not on it. The only seller-derived output is the private-vs-dealer flag. Austria's DSB applies the same GDPR baseline as the rest of the EU, and a dataset with no seller personal data in it is the whole point here.

Requests are paced, the load on willhaben is negligible, and no anti-bot protection is bypassed.

One limit stated plainly: `title` and `description` are the seller's own words, passed through unedited. A seller who writes a phone number into their ad text has published it themselves — the guarantee covers the structured fields, not free text sellers choose to write.

### Is there a willhaben car API?

willhaben offers no public API for reading its car listings. This actor fills that gap: the same Gebrauchtwagenbörse results as clean JSON via one HTTP call (`run-sync-get-dataset-items`), on a schedule, or as an MCP tool — with the GDPR question already settled in the data itself.

### Does willhaben block car scrapers?

The site serves its car search to ordinary requests, and this actor stays ordinary: paced traffic, standard datacenter proxies, tiny footprint. No CAPTCHA arms race — which keeps runs fast and schedules dependable. If a block does land mid-run, everything already collected is delivered with an honest note in the run status, and you are never charged for cars that didn't arrive.

### How do I monitor new cars on willhaben?

Pick your query and price cap, set `sortBy: "date"`, keep `maxItems` small, and put it on a Schedule in the Apify Console with an email or Slack integration on finished runs. Tighter still: set `postedAfter` to yesterday — the dataset then holds only cars posted since, so there is nothing to dedupe and each run stops the moment it reaches older listings. The AI-assistant prompt above sets this up step by step for non-technical users.

### FAQ

**Can I get the dealer's name or phone number?** No, and not via any setting — seller identity is structurally never collected. You get `sellerType` (`private` or `dealer`) and nothing else about the seller. That is what makes the dataset safe to store and share.

**Does it cover both dealers and private sellers?** Yes — willhaben's car search mixes both, and every row carries the `sellerType` flag so you can split them in one filter.

**How do I filter by mileage or year?** After the run: `mileageKm` and `year` are plain integers, so filter in Excel, SQL or a dataframe. The actor's own filters are price, date window and sorting; the numeric spec columns exist precisely so post-filtering is trivial.

**How do I monitor new cars under a price?** `priceMaxEur` plus `sortBy: "date"` on a Schedule — see the monitoring section above. Add `postedAfter` for a dataset of only-new cars per run.

**Can I export willhaben car listings to Excel?** Yes — any dataset exports as Excel, CSV, JSON or XML from the Apify Console or API, with the specs already in separate columns.

**Is this Autoscout24 data?** No — this actor covers willhaben.at only. willhaben runs its own used-car board, the Gebrauchtwagenbörse, and that is exactly what you get here.

**Where does the data come from — does it visit each car's page?** From the search result cards. No detail-page visits, which is why runs take seconds and cost stays at $1.99 per thousand. Spec values the card doesn't carry come back null.

**Why are some spec fields null?** Two honest reasons: the result card didn't state the value, or the seller entered something non-numeric in a numeric field and it was dropped instead of polluting your column.

**Why is priceCents missing on a car?** The seller set a non-numeric price. `priceDisplay` always keeps the exact on-site string, so nothing is silently lost.

**Are the prices negotiable prices or fixed?** They are asking prices as posted — what the seller displays. Whether it's negotiable is between you and the seller; the data tells you what the market is asking.

**Can I browse without a search term?** Yes — leave `searchQuery` empty and the actor pages through the newest cars across Austria, which is the cheapest way to build a market-wide sample.

**Can I get only cars posted today?** Set `postedAfter` to today's date (YYYY-MM-DD). With newest-first sorting the run ends as soon as it provably reaches older cars, so the run stays small and quick.

**What does it cost?** $1.99 per 1,000 cars delivered, all-inclusive — your runs' platform usage is covered, no compute or proxy charges on top. Empty and failed runs are free.

**Do I need residential proxies?** No. Datacenter proxies are sufficient, and there is no hidden proxy surcharge.

**How long does a run take?** Seconds for a scoped run — fast enough that hourly schedules are a normal way to use it.

**What happens if willhaben blocks a run partway?** You get every car collected before the block, the run status says plainly that coverage is partial, and the cars that didn't arrive are never billed. A retry or a narrower query usually completes.

**Why did I only get 25 cars?** The Apify free plan caps this actor at a 25-item sample. Any paid plan lifts the cap to your `maxItems`.

**Can ChatGPT or Claude search willhaben cars for me?** Yes — connect it through Apify's MCP server (section above) and an agent can choose the query, run the scraper and reason over the results in one conversation.

**Does the output include GPS coordinates?** No — deliberately. Location stops at `city`, `postcode`, `district` and `state`, which is enough for regional price comparisons and identifies no one.

**Is it legal to use this car data?** Public asking prices and specs are public commercial information, and the output carries no seller personal data by construction — that question is answered in the dataset itself, not in a disclaimer.

### Related scrapers

Same output discipline, same no-personal-data guarantee, other markets:

- [willhaben Scraper](https://apify.com/lowlanddata/willhaben-scraper) — the parent actor for willhaben's general Marktplatz (everything that isn't a car).
- [Kleinanzeigen.de Scraper](https://apify.com/lowlanddata/kleinanzeigen-scraper) — Germany's biggest classifieds site.
- [Marktplaats.nl Scraper](https://apify.com/lowlanddata/marktplaats-scraper) — the Netherlands' biggest marketplace.
- [OLX.pl Scraper](https://apify.com/lowlanddata/olx-pl-scraper) — Poland's largest classifieds marketplace.

### Troubleshooting

Failures are loud and named in the run's status message:

- **"priceMinEur must not be higher than priceMaxEur."** — the band is inverted; swap the values.
- **"willhaben blocked the run before any results could be fetched..."** — a temporary block on the first request; retrying in a few minutes usually lands on a clean proxy session.
- **"... then the site blocked further requests. Partial coverage ..."** — the cars collected before the block are in the dataset; re-run later or narrow the query.
- **"markup may have changed"** — every collected item came back without a title or price, so the run fails instead of delivering empty rows. Report it on the Issues tab; that failure exists so you never pay for junk.
- **25 cars instead of your maxItems** — the free-plan sample cap; a paid Apify plan removes it.

### Support

Missing a spec column you need, or found a car that parsed wrong? Open a report on the actor's **Issues tab** — this actor is actively maintained and reports get acted on.

If it's earning its keep, a **rating on this page** takes ten seconds and helps the next buyer find the GDPR-clean option — and tells us which market to build next.

# Actor input Schema

## `searchQuery` (type: `string`):

Optional keyword, exactly as you would type it in the willhaben car search, e.g. "golf tdi" or "tesla model 3". Leave empty to browse the newest cars across Austria.

## `priceMinEur` (type: `integer`):

Only cars costing at least this much.

## `priceMaxEur` (type: `integer`):

Only cars costing at most this much.

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

Order of results: date (newest first, best for monitoring), price\_asc, price\_desc, or relevance.

## `postedAfter` (type: `string`):

Only listings posted on or after this date (YYYY-MM-DD or ISO timestamp). With newest-first sorting the run stops early once it reaches older listings.

## `postedBefore` (type: `string`):

Only listings posted on or before this date (YYYY-MM-DD or ISO timestamp).

## `maxItems` (type: `integer`):

Stop after this many cars. Free-plan runs are capped at 25 items.

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

Proxy settings. Keep Apify proxy enabled.

## Actor input object example

```json
{
  "searchQuery": "golf",
  "sortBy": "date",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `cars` (type: `string`):

Scraped willhaben car listings, one JSON object per car.

# 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 = {
    "searchQuery": "golf",
    "sortBy": "date",
    "maxItems": 25,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lowlanddata/willhaben-car-scraper").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 = {
    "searchQuery": "golf",
    "sortBy": "date",
    "maxItems": 25,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("lowlanddata/willhaben-car-scraper").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 '{
  "searchQuery": "golf",
  "sortBy": "date",
  "maxItems": 25,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call lowlanddata/willhaben-car-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lowlanddata/willhaben-car-scraper"
        }
    }
}

```

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/OvecjYvXydexD82MZ/builds/kVfVo1KYK9C33Tmd3/openapi.json
