# mobile.de Scraper — Cars, Prices & Dealers (`tortuga/mobile-de-scraper`) Actor

Scrape mobile.de car listings from any search URL or make, model and filters: price (gross/net), price rating, mileage, first registration, power, fuel, dealer, images, optional full specs.

- **URL**: https://apify.com/tortuga/mobile-de-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 listing scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## mobile.de Scraper

Scrape car listings from mobile.de, Germany's largest car marketplace. For each car you get the title, make, model and variant, gross and net price with VAT, mobile.de's price rating ("Sehr guter Preis", "Guter Preis", ...), first registration, mileage, power in kW and PS, fuel, gearbox, body type, colour, number of previous owners, postcode and town, the seller type, and the dealer's name, address and rating. You also get every image URL and the listing URL. Start from any mobile.de search URL, or type a make, a model and filters. Turn on **Include listing details** to also get the description, the full equipment list, the technical data table, the accident-free status and more dealer information.

The actor reads the same JSON that mobile.de's own apps load, not the HTML page. That keeps the output complete and stable and makes runs fast: up to 100 listings come back per request, about 3,000 listings a minute. You pay only for the listings you get.

### What data does mobile.de Scraper extract?

| Field | Description |
|---|---|
| `id`, `url` | mobile.de listing id and the listing URL |
| `title`, `make`, `model`, `variant` | e.g. `"Audi A6 3.0 TDI quattro S-Line"`, `Audi`, `A6`, `3.0 TDI quattro S-Line` |
| `price`, `currency` | Asking price (gross, EUR) |
| `priceNet`, `vatRate`, `vatDeductible` | Net price and VAT rate when the dealer shows VAT ("MwSt. ausweisbar") |
| `priceType` | `fixed` or `negotiable` (VB) |
| `priceRating`, `priceRatingLabel` | mobile.de's market price rating: `VERY_GOOD_PRICE` / "Sehr guter Preis", `GOOD_PRICE`, `REASONABLE_PRICE`, `INCREASED_PRICE`, `HIGH_PRICE` (null when mobile.de shows none) |
| `firstRegistration`, `firstRegistrationYear` | `"09/2023"`, `2023` |
| `mileageKm`, `powerKw`, `powerHp` | `120765`, `210`, `286` |
| `fuel`, `gearbox`, `bodyType`, `colour`, `doors`, `seats`, `engineCapacityCcm` | As shown on mobile.de (German labels, e.g. `Diesel`, `Automatik`, `Kombi`, `Schwarz`) |
| `previousOwners` | Number of previous owners (Fahrzeughalter) |
| `condition`, `damaged`, `readyToDrive` | `used` / `new`, unrepaired damage flag, roadworthy flag |
| `accidentFree`, `damageCondition` | `true` when mobile.de says "Unfallfrei" (with details) |
| `generalInspectionUntil`, `emissionClass`, `fuelConsumption`, `co2Emissions`, `co2Class` | HU date, Euro class and the consumption / CO2 data when the listing has it |
| `country`, `postcode`, `city`, `latitude`, `longitude` | Where the car is. Private sellers' coordinates are rounded to about 1 km |
| `sellerType` | `dealer`, `private` or `company` (company cars) |
| `dealerName`, `dealerAddress`, `dealerRating`, `dealerRatingCount`, `dealerReviewsUrl` | Dealer business details and its mobile.de rating |
| `images`, `imageCount` | All image URLs (1024 px) |
| `hsnTsn` | German KBA key numbers (HSN/TSN) when the dealer provides them |
| `partnerSite` | Set when the ad comes from a partner site (e.g. `kleinanzeigen`, `automobile.it`) |
| `createdAt`, `modifiedAt`, `renewedAt` | When the ad was created, last changed and last renewed (ISO, UTC) |
| `makeId`, `modelId`, `sellerId`, `searchUrl`, `scrapedAt` | mobile.de ids, the search the listing came from, and the time of the run |

With **Include listing details** you also get:

| Field | Description |
|---|---|
| `description` | Full description text (line breaks kept) |
| `features` | Complete equipment list (`["ABS", "Apple CarPlay", "Sitzheizung", ...]`) |
| `technicalData` | The whole technical data table keyed by mobile.de's attribute names (`mileage`, `firstRegistration`, `numberOfPreviousOwners`, `hu`, `climatisation`, `envkv.co2Emissions`, `envkv.consumptionDetails.fuel`, `interior`, ...) |
| `accidentFree`, `damageCondition` | e.g. `true`, `"Gebrauchtfahrzeug, Unfallfrei"` |
| `trimLine`, `interior`, `manufacturerColour`, `constructionYear`, `emissionsSticker`, `highlights` | Trim line, upholstery, the manufacturer's colour name, construction year, emissions sticker |
| `dealerLanguages`, `dealerOnMobileSince`, `dealerRecommendationRate`, `dealerContactPerson`, `dealerContactRole` | Dealer languages, on mobile.de since, recommendation rate, and the contact person the dealer publishes on the listing |

### How to scrape mobile.de car listings

1. Open [suchen.mobile.de](https://suchen.mobile.de/fahrzeuge/search.html?vc=Car), set any filters and sort order, and copy the address from your browser. Or skip this step and fill in **Make**, **Model** and the filters in the input.
2. Paste the URL into **Start URLs**. You can add several searches, and single listing URLs too.
3. Set **Max items** and start the run. Download the results as JSON, CSV or Excel, or read them through the API.

The Make / Model search covers the filters most buyers use: price, first registration year, mileage, power (kW), fuel, gearbox, body type, new or used, dealer or private seller, and a German postcode or town with a radius. Any other mobile.de filter works through a search URL. That includes equipment, colour, price rating, number of owners, VAT, online since and EV range.

### Input example

```json
{
  "make": "BMW",
  "model": "3er",
  "yearFrom": 2019,
  "priceTo": 30000,
  "mileageTo": 100000,
  "fuelTypes": ["diesel"],
  "gearbox": ["automatic"],
  "location": "80331",
  "radiusKm": 100,
  "sellerType": "dealer",
  "sort": "newest",
  "maxItems": 500,
  "includeDetails": false
}
```

Or with search URLs:

```json
{
  "startUrls": [
    { "url": "https://suchen.mobile.de/fahrzeuge/search.html?isSearchRequest=true&ms=1900%3B10%3B%3B&vc=Car&dam=false&fr=2020%3A&sb=p&od=up" },
    { "url": "https://suchen.mobile.de/fahrzeuge/details.html?id=422503914" }
  ],
  "maxItems": 1000
}
```

Model names follow mobile.de: `3er` is the whole 3 Series (320, 330e, M3, ...), `320` is only the 320, and `Golf` includes the Golf Variant and Sportsvan. If a model name is not found, the run stops and lists the names mobile.de knows for that make.

### Output example

```json
{
  "id": "49895674843104",
  "url": "https://suchen.mobile.de/auto-inserat/audi-a6-3-0-tdi-quattro-s-line-pano-hud-st-hz-leder-3-wertingen/49895674843104.html",
  "title": "Audi A6 3.0 TDI quattro S-Line PANO*HuD*St.Hz*LEDER*3",
  "make": "Audi",
  "model": "A6",
  "variant": "3.0 TDI quattro S-Line PANO*HuD*St.Hz*LEDER*3",
  "price": 35850,
  "priceNet": 30126.05,
  "currency": "EUR",
  "vatRate": 19.0,
  "vatDeductible": true,
  "priceType": "fixed",
  "priceRating": "GOOD_PRICE",
  "priceRatingLabel": "Guter Preis",
  "firstRegistration": "09/2023",
  "firstRegistrationYear": 2023,
  "mileageKm": 120765,
  "powerKw": 210,
  "powerHp": 286,
  "fuel": "Diesel",
  "gearbox": "Automatik",
  "bodyType": "Kombi",
  "colour": "Schwarz",
  "doors": "4/5",
  "seats": 5,
  "engineCapacityCcm": 2967,
  "previousOwners": 1,
  "condition": "used",
  "damaged": false,
  "accidentFree": true,
  "readyToDrive": true,
  "country": "DE",
  "postcode": "86637",
  "city": "Wertingen",
  "latitude": 48.561834,
  "longitude": 10.688548,
  "sellerType": "dealer",
  "sellerId": "459539",
  "dealerName": "Autohaus Ohnheiser GmbH & Co. KG VW Agentur",
  "dealerAddress": "Industriestrasse 4, 86637 Wertingen",
  "dealerRating": 4.9,
  "dealerRatingCount": 43,
  "dealerReviewsUrl": "https://www.mobile.de/bewertungen/OHNHEISER",
  "images": [
    "https://img.classistatic.de/api/v1/mo-prod/images/73/736d0978-8f28-4ef1-8d18-2faac9c315f2?rule=mo-1024w",
    "https://img.classistatic.de/api/v1/mo-prod/images/d0/d0da01f0-b662-42dd-b5f7-156a4b98a53d?rule=mo-1024w"
  ],
  "imageCount": 17,
  "createdAt": "2026-10-09T23:32:02Z",
  "renewedAt": "2026-10-09T23:32:02Z",
  "damageCondition": "Gebrauchtfahrzeug, Unfallfrei",
  "features": ["ABS", "Abstandstempomat", "Abstandswarner", "Alarmanlage", "Allradantrieb", "Ambiente-Beleuchtung", "Android Auto", "Apple CarPlay"],
  "technicalData": {
    "mileage": "120.765 km",
    "cubicCapacity": "2.967 cm³",
    "power": "210 kW (286 PS)",
    "fuel": "Diesel",
    "numberOfPreviousOwners": "1",
    "hu": "Neu",
    "climatisation": "4-Zonen-Klimaautomatik",
    "interior": "Vollleder, Schwarz"
  },
  "interior": "Vollleder, Schwarz",
  "manufacturerColour": "Brillantschwarz",
  "constructionYear": 2023,
  "dealerLanguages": "Deutsch, English",
  "dealerOnMobileSince": "27.08.2002",
  "detailsFetched": true,
  "scrapedAt": "2026-10-09T21:40:00Z"
}
```

(Shortened: real items carry every field from the table above. Fields that need details are absent or null when **Include listing details** is off.)

### How many listings can I get per search?

mobile.de serves at most **2,000 listings per search**. When a search has more and **Max items** asks for more, the actor splits it into price bands of up to 2,000 listings each, using a few tiny count requests, and collects them all. In a test, BMW 3 Series from 2025 returned all 3,045 of 3,045 listings in 41 seconds. Results then come band by band, cheapest band first, and each band keeps your sort order. Very broad searches (all 1.5 million cars) need many bands; it is faster to split them yourself by make, model or region. Turn off **Split searches over 2,000 results** to stop at the first 2,000.

### Does it work without login? Does it collect phone numbers?

Yes, no login and no mobile.de account are needed. The actor reads only what anyone sees on mobile.de without logging in. It does **not** export phone numbers, messenger links or anything else hidden behind a click. It never exports private sellers' names or street addresses: for private sellers you get the postcode, the town and coordinates rounded to about 1 km. Dealers are businesses, so their name, address, rating and the contact person they publish on the listing are included.

### Do I need a proxy?

Yes. mobile.de is protected by Akamai, which turns away most datacenter IP addresses. The default proxy, Apify **Residential** proxy in Germany, worked on 100% of requests in our tests. Residential traffic is billed by Apify per GB, and this actor uses very little of it: about 1 MB per 1,000 listings (one request per 100 listings), or about 10 MB per 1,000 listings with details. A denied request is retried automatically on a fresh IP and browser fingerprint.

### Monitor changes on a schedule

Turn on **Only new or changed items** to watch a search. Each run remembers what earlier runs returned and outputs only new listings and listings whose price changed. Unchanged listings are dropped before any detail request, so they are not charged. **Max items** then sets how many listings are checked per run; keep the "Newest first" sort, e.g. 100-200 for a make and model in your region. Save the input as a task in Apify and add a Schedule (for example every hour or daily). Give each watch its own **Monitoring key** if several schedules use the same search. Every output item gets `changeType` (`new` or `changed`), and changed items get `previousValues` with the old price, e.g. `{"price": 24990}`.

### Pricing

Pay per result: you are charged for each listing saved to the dataset, plus a small extra per listing when **Include listing details** is on. See the Pricing tab for the current prices. There is no start fee. Platform usage is small: at the default 512 MB memory our test runs used about $0.01-0.02 per 1,000 listings without details (proxy traffic, compute and dataset writes) and about $0.10 per 1,000 with details.

### Integrations and API

Run it from the Apify API or a schedule, and send the results to Google Sheets, Slack, Make, Zapier, n8n or a webhook. Use `maxItems` to cap the cost of each run. Typical uses are dealer stock and price monitoring, used-car market research, price comparisons by make, model and year, and lead lists of dealers.

### Is it legal to scrape mobile.de?

This actor collects publicly visible listing data that anyone can see on mobile.de without logging in. It does not log in, it does not collect phone numbers or anything else behind a click, and it does not export private sellers' names or addresses. Dealer contact persons are personal data under the GDPR. You are responsible for having a legitimate purpose and a legal basis for processing them, and for respecting mobile.de's terms of use. If in doubt, ask a lawyer.

Postcode and town coordinates for the **Postcode or town** filter come from [GeoNames](https://www.geonames.org/) (CC BY 4.0).

### Support

Found a bug or need a field that is not there? Open an issue on the Issues tab with the input you used and the run link.

# Actor input Schema

## `startUrls` (type: `array`):

mobile.de search URLs with any filters and sort set in the browser (open the search on suchen.mobile.de and copy the address bar, e.g. https://suchen.mobile.de/fahrzeuge/search.html?isSearchRequest=true\&ms=3500%3B%3B21%3B\&vc=Car), or single listing URLs (https://suchen.mobile.de/fahrzeuge/details.html?id=... or .../auto-inserat/.../<id>.html), which return that listing with full details. Leave empty if you use the Make / Model search fields below.

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

Brand as shown on mobile.de, e.g. BMW, Volkswagen (or VW), Mercedes-Benz, Audi, Tesla, Porsche. Leave empty for all makes.

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

Model or model series as named on mobile.de, e.g. 3er (the whole 3 Series), 320, X5, Golf, A6, C-Klasse, Model 3. Needs a make. The run fails with the list of valid names if it is not found.

## `variant` (type: `string`):

Text that must appear in the model description, e.g. 320d, Avant, GTI, quattro.

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

Minimum asking price (gross) in euros.

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

Maximum asking price (gross) in euros.

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

Earliest year of first registration, e.g. 2018.

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

Latest year of first registration.

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

Minimum mileage in kilometres.

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

Maximum mileage in kilometres.

## `powerFromKw` (type: `integer`):

Minimum engine power in kW (1 kW = 1.36 hp; 100 kW = 136 hp).

## `powerToKw` (type: `integer`):

Maximum engine power in kW.

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

Only these fuel types. Leave empty for all.

## `gearbox` (type: `array`):

Only these transmissions. Leave empty for all.

## `bodyTypes` (type: `array`):

Only these body types. Leave empty for all.

## `condition` (type: `string`):

Only new or only used cars. Leave empty for both.

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

Only dealers, only private sellers, or only company cars (Firmenfahrzeuge). Leave empty for all.

## `location` (type: `string`):

Search around this German postcode or town, e.g. 10115, 80331, Köln, Hamburg. Leave empty for all locations (mobile.de also lists cars from other EU countries).

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

Used with Postcode or town: distance around it in km (mobile.de offers 10, 20, 50, 100, 200, 500). Empty = 50 km.

## `sort` (type: `string`):

Order of the results. Applies to the Make / Model search and to start URLs that have no sort of their own. 'Newest first' (online since, incl. renewed ads) is best for monitoring.

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

Stop after this many listings in total (across all searches). Keeps cost predictable. mobile.de returns at most 2,000 listings per search; larger searches are split into price bands automatically (see below).

## `splitLargeSearches` (type: `boolean`):

mobile.de serves at most 2,000 listings per search. When a search has more and Max items asks for more, cut it into price bands of up to 2,000 listings each (a few tiny count requests) so you can get every listing. Results then come band by band, cheapest band first.

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

Also load every listing's full record: description text, complete equipment list, technical data table (consumption, CO2, HU, interior, trim line, construction year ...), accident-free status, dealer languages / member since / contact person. One extra request per listing; charged as an extra 'detail' event (see pricing).

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new listings or listings whose price changed. Use with a Schedule; unchanged items are not charged. With this on, Max items is the number of listings checked per run (e.g. the newest 200).

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

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

mobile.de is protected by Akamai, which turns away most datacenter IPs. Apify RESIDENTIAL proxy (Germany) is the default and works reliably; residential traffic is billed by Apify per GB, and this actor uses about 1 MB per 1,000 listings (about 8 MB with details).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://suchen.mobile.de/fahrzeuge/search.html?isSearchRequest=true&ms=1900%3B10%3B%3B&vc=Car&dam=false"
    }
  ],
  "sort": "newest",
  "maxItems": 100,
  "splitLargeSearches": true,
  "includeDetails": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "startUrls": [
        {
            "url": "https://suchen.mobile.de/fahrzeuge/search.html?isSearchRequest=true&ms=1900%3B10%3B%3B&vc=Car&dam=false"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/mobile-de-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 = {
    "startUrls": [{ "url": "https://suchen.mobile.de/fahrzeuge/search.html?isSearchRequest=true&ms=1900%3B10%3B%3B&vc=Car&dam=false" }],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/mobile-de-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 '{
  "startUrls": [
    {
      "url": "https://suchen.mobile.de/fahrzeuge/search.html?isSearchRequest=true&ms=1900%3B10%3B%3B&vc=Car&dam=false"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}' |
apify call tortuga/mobile-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/mobile-de-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/pOcwZil1wIVgeUq8P/builds/ho6QSwzcC8LjOawqX/openapi.json
