# Mobile.de Scraper: Cars, Prices, Dealers & Ratings (`automation_craft/mobile-de-scraper`) Actor

Scrape mobile.de cars, motorbikes, vans, trucks by make, model, keyword, place, dealer or pasted links, no login, past 2,000 ads a search. Rows carry price, mobile.de price rating, mileage, registration, power, KBA codes, dealer phone. Monitor new ads and price drops; CSV or API, pay per listing.

- **URL**: https://apify.com/automation_craft/mobile-de-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (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.47 / 1,000 listings

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

### Mobile.de Scraper: Cars, Prices, Dealers & Ratings

**Mobile.de Scraper** turns mobile.de, the German vehicle marketplace, into clean rows: one row per ad with the
price, mobile.de's own price rating and the six price thresholds behind it, mileage, first registration, power in kW and
hp, fuel, gearbox, body type, colour, emission class, previous owners, HU, KBA HSN and TSN, finance plans, the place, and
the seller (a dealer's name, phone and star rating). Search by make and model, keyword, place with a radius or a dealer's
stock, across 13 vehicle types (cars, motorbikes, motorhomes, vans, trucks, buses, trailers, machines, e-bikes and more),
paste mobile.de search links, or give ad links. No login, no browser.

Searches larger than mobile.de's 2,000 ad limit are split into price slices on their own. Turn on **Listing details** for
the full description, equipment, every attribute and the dealer's address, opening hours and newest reviews, and **Dealer
profiles** for up to 10 reviews, e-mail addresses, WhatsApp number, website, imprint and VAT id. Name a **monitor** and
schedule the Actor: each run delivers and bills only ads it has not delivered before, tracks price changes and removed ads,
and can send them to Telegram, Slack, Discord, WhatsApp or your webhook.

#### Who uses it

- **Car dealers and traders** watching makes, models and regions for new stock and price drops, and checking where an ad
  sits against mobile.de's price rating.
- **Buyers and importers** reading a model across Germany or abroad with net prices and VAT, mileage, registration and HU.
- **Lead and market teams** reading a dealer's whole stock, its rating, phones and, with Dealer profiles, its e-mail
  addresses and reviews.
- **Analysts and data teams** who need mobile.de as rows in JSON, CSV or Excel, in German or English labels, through the
  Apify API.

#### Features

| Feature | Settings | Event billed |
|---|---|---|
| Makes and models by name ("Volkswagen Golf", "BMW 3er Reihe (all)" for a model group) or id; makes or models to leave out | `makeModels`, `excludeMakeModels` | Listing |
| mobile.de's own keyword search | `keywords` | Listing |
| 13 vehicle types: car, motorbike, motorhome, van, truck, semi trailer truck, trailer, semi trailer, bus, construction, agricultural, forklift, e-bike | `vehicleType` | Listing |
| Places: German postcodes and place names through mobile.de's own place service, places in France, Italy, Poland or Romania with their country, coordinates; a radius in whole km; the vehicle's country | `locations`, `radiusKm`, `country` | Listing |
| A dealer's whole stock, by dealer id or storefront link | `dealers` | Listing |
| Pasted mobile.de search links, every parameter read and checked | `searchUrls` | Listing |
| Single ads by link or id, read with their details | `adUrls` | Listing by URL |
| Named filters: fuel, gearbox, body type, colour, special categories, drive, emission class, price rating, condition, seller type, damage, VAT, doors, emission sticker, price, year, mileage, power (kW or hp), seats, engine size, previous owners, HU months, online within 1 to 14 days, dealer stars, roadworthy, pictures, reduced price, video, quality seal, leasing, export offers, equipment | see Input | no charge |
| Any other mobile.de filter by its own parameter name | `filters` | no charge |
| Row filters: words to keep or leave out, an online since window, ads you already have, custom rules on any output field | `includeKeywords`, `excludeKeywords`, `postedWithinHours`, `postedWithinDays`, `postedAfter`, `postedBefore`, `excludeAdIds`, `customFilters` | no charge |
| 9 sorts, caps per run, per search and in pages, a start page | `sort`, `maxItems`, `maxItemsPerSearch`, `maxPagesPerSearch`, `startPage` | no charge |
| Past 2,000 ads a search: price slices from mobile.de's own price percentiles | `splitLargeSearches` (on) | no charge |
| The promoted top ad of page 1 (highlighted ads always come in their place) | `includeTopAds` (on) | Listing |
| Description, equipment, every attribute, all photos, finance plan; a dealer's address, phones, opening hours, contact person, rating breakdown and 2 newest reviews | `includeDetails` | Listing details |
| A dealer's storefront and rating pages, once per dealer per run: up to 10 reviews, e-mails, WhatsApp, website, imprint, VAT id | `includeDealerProfiles`, `maxDealerReviews` | Dealer profile |
| A monitor: only ads new to it, run after run | `monitorName` | Listing (new ads only) and Results page |
| Price and field changes, removed and reappeared ads | `trackChanges`, `trackFields` (with a monitor) | Listing update |
| Every known ad again as a full snapshot; reposts marked or left out | `emitUnchanged`, `markReposts`, `skipReposts` | Listing (snapshot rows) |
| Notifications: Telegram, Slack, Discord, WhatsApp Cloud API, webhook (HMAC SHA-256 signature, extra headers) | see The monitor and notifications | free |
| Labels in German or English; prices also in one of 15 other currencies at the European Central Bank's rate of the day | `language`, `currency` | included |
| Image size, description format and length, compact rows, empty fields left out | `imageSize`, `descriptionFormat`, `descriptionMaxLength`, `compactOutput`, `excludeEmptyFields` | included |
| A private seller's phone and exact coordinates (off by default) | `includePersonalData` | free |
| A coverage row per search, free status rows for misses, a run summary and an HTML run report (key `REPORT`) | always | free |

### Quick start

1. Type a make and model (for example `Volkswagen Golf`, `BMW 3er Reihe (all)` or `Mercedes-Benz C 200`) and a place (`Berlin`,
   `10115`, `München, Bayern` or `52.52, 13.40`) with a radius.
2. Optional: pick filters (fuel, gearbox, price, year, mileage, power, seller type, price rating) or a vehicle type.
3. Set **Maximum listings** and press **Start**.
4. Download the rows as JSON, CSV or Excel, or read them through the API.

Example input, the Actor's own prefill:

```json
{
    "makeModels": ["Volkswagen Golf"],
    "locations": ["Berlin"],
    "radiusKm": 50,
    "maxItems": 10
}
```

Dealer offers of the BMW 3 series around Munich, 2020 or newer, under 60,000 km, with a good or very good price rating
and the details:

```json
{
    "makeModels": ["BMW 3er Reihe (all)"],
    "locations": ["München, Bayern"],
    "radiusKm": 50,
    "sellerType": "dealer",
    "yearMin": 2020,
    "mileageMax": 60000,
    "priceRatings": ["very_good", "good"],
    "includeDetails": true,
    "maxItems": 200
}
```

Motorbikes across Germany, newest first, with English labels and prices also in US dollars:

```json
{
    "vehicleType": "motorbike",
    "language": "en",
    "currency": "USD",
    "maxItems": 100
}
```

### What you get

One row per ad (`type: "listing"`), one coverage row per search (`type: "search"`), free status rows for anything that did
not end as a listing (`type: "status"`), with change tracking a removed row per ad a monitor no longer finds
(`type: "removed"`), and one run summary at the end (`type: "summary"`).

#### Listing fields

Fill rates were measured on a 2,000 row run on 2026-10-15 (Volkswagen Golf across Germany, newest first, 2,000 listing
rows: 726 dealer, 1,273 private and 1 company car; `includePersonalData` off).

| Field | What it holds | Filled |
|---|---|---|
| `adId`, `url`, `title`, `subtitle` | mobile.de's ad id, the ad's link, the title and subtitle | 100 % (subtitle 99.5 %) |
| `make`, `model`, `vehicleType`, `category`, `bodyType`, `condition` | make and model as mobile.de lists them, the vehicle type, body type, new or used | 100 % (`bodyType`, added after this run: 1,500 of 1,500 on a later run) |
| `price`, `currency`, `priceNet`, `vat`, `vatReclaimable`, `priceNegotiable`, `previousPrice` | gross price in euros, the net price and VAT where a business can reclaim it, the price before a reduction | price 100 %, net price 16.9 %, previous price 0.7 % |
| `priceRating`, `priceRatingLabel`, `priceRatingBands` | mobile.de's price rating (`VERY_GOOD_PRICE` to `HIGH_PRICE`, or `NO_RATING`), its label, the six thresholds in euros | field 100 %, a rating other than `NO_RATING` 44.5 %, thresholds 46.5 % |
| `mileageKm`, `firstRegistration`, `firstRegistrationYear` | kilometres, month and year of first registration | 99.8 %, 98.5 % |
| `powerKw`, `powerHp`, `fuel`, `gearbox` | engine power, fuel and gearbox in the run's language | power 95.2 %, fuel 98.5 %, gearbox 98.2 % |
| `engineSizeCcm`, `color`, `doors`, `seats`, `emissionClass` | as the seller gives them | 40.6 to 44.8 % |
| `previousOwners`, `hu`, `countryVersion` | previous owners, the general inspection (HU) date or "Neu", the market version | 36.5 %, 83.5 %, 22.6 % |
| `consumption`, `co2Emissions`, `co2Class` | where the search answer carries them (more with Listing details) | 4.1 % |
| `kbaHsn`, `kbaTsn` | the German type approval codes | 28.8 % |
| `financePlans`, `monthlyFinanceRate`, `leasingRateMonthly`, `leasing` | mobile.de's finance plans (bank, term, rates, instalments), leasing offers | finance 1,999 of 2,000, leasing 1.6 % |
| `sellerType`, `sellerTypeLabel`, `sellerId` | dealer, private or company, the seller's id (the same on every ad of one seller) | 100 % |
| `dealerName`, `sellerPhone`, `dealerRating`, `dealerRatingCount`, `dealerLogo` | a dealer's name, phone, stars and number of ratings | name and phone on 726 of 726 dealer rows, rating on 610 of 726 |
| `postcode`, `city`, `country` | the vehicle's place | 100 % |
| `imageCount`, `image` | the number of photos and the first one | 100 %, 98.1 % (median 12 photos) |
| `placement`, `highlights`, `badges`, `qualitySeal`, `delivery` | `organic`, `highlighted` (a paid highlight in the order) or `topAd`; the ad's highlights and seals | placement 100 % (118 highlighted, 1 top ad) |
| `onlineSince`, `daysOnline` | when the ad went online and days since (newest and oldest sorts) | 100 % |
| `converted` | with `currency`: the price and net price converted, the rate, its date and source | with a currency other than EUR |
| `searchKey`, `searchLabel`, `searchPage`, `searchSlice`, `searchPosition`, `source`, `monitorName`, `deliveryId`, `scrapedAt` | what found the ad (`search` for searches and search links, `adUrl` for ad links), the search, its page, price slice and position, when the row was made | set by the Actor |
| `detailsIncluded`, `dealerProfileCharged`, `pageCharged` | whether this row's details were read and billed, whether it carried the dealer's one charged profile, whether it carried its page's Results page charge | set by the Actor |
| `change`, `possibleRepostOf` | with a monitor: what changed since the last delivery; an earlier ad id of the same vehicle | monitor runs |

#### Listing details (`includeDetails`, and every ad link)

Measured on 96 distinct rows with details from four runs on 2026-10-15 (51 dealer, 45 private rows).

| Field | What it holds | Filled |
|---|---|---|
| `description` (and `descriptionHtml`, `descriptionMarkdown` by `descriptionFormat`) | the seller's full text | 100 % |
| `attributes` | every attribute as `{tag, label, value}` (consumption, CO2, cylinders, tank, weights, last service ...) | 100 % (median 15) |
| `features` | the equipment list | 88.5 % (median 8) |
| `images` | every photo link | 92.7 % (median 12) |
| `damageCondition`, `accidentFree`, `engineType` | condition, accident free flag, drive type | 99 to 100 % |
| `climatisation`, `manufacturerColor`, `interior`, `cylinders` | as named | 67.7 %, 74.0 %, 43.8 %, 37.5 % |
| `lastServiceDate`, `lastServiceMileage`, `batteryCapacity`, `electricRange` | where the seller gives them (no electric car in this sample) | 6 to 7 %; 0 % |
| `financePlanDetail`, `partnerLinks` | the finance plan in full; mobile.de's partner offers | 97.9 %, 58.3 % |
| `dealer` | `name`, `address`, `postcodeAndCity`, `country`, `phones`, `homepageLink`, `latitude`, `longitude`, `languages`, `openingHours`, `contactPerson`, `memberSince`, `rating`, `about`, `latestReviews` | on 51 of 51 dealer rows; name, address, phones, coordinates 100 %, rating 72.5 %, opening hours 58.8 %, latest reviews 62.7 %, contact person 29.4 % |
| `privateSeller` | `location`, `latitude`, `longitude` (rounded to 2 decimals with `includePersonalData` off), `phones` (only with it on) | on 45 of 45 private rows |

#### Dealer profile (`includeDealerProfiles`)

`dealerProfile` carries `customerId`, `name`, `storefrontUrl`, `website`, `emails`, `phone`, `cellPhone`, `whatsApp`, `fax`,
`address` (street, postcode, city, country, coordinates), `vatId`, `imprint`, `onMobileDeFor`, `languages`, `ratingScore`,
`ratingCount`, `ratingsPage` and `reviews` (up to `maxDealerReviews`, 10 by default: date, score, buyer's shown first name,
bought a car, liked, disliked, recommends, ad matched reality, part scores, salesperson, dealer reply). Measured on one
dealer in two runs on 2026-10-15: name, two e-mail addresses, phone, WhatsApp, address, VAT id, imprint and 10 reviews
filled; the dealer showed no website. mobile.de serves only a handful of these pages per run (10 pages, 3 per dealer: about 3 dealers); rows past
that come without the profile and without its charge, and a profile that could not be read is never billed. A dealer's
profile is billed once per run and carried free on its later rows.

#### Removed rows (`trackChanges`)

`adId`, `url`, `reason` (`notFoundByCompleteSearches`), `message`, `lastPrice`, `firstSeenPrice`, `priceChangeCount`,
`firstSeenAt`, `daysTracked`, `monitorName`, `scrapedAt`. Written only when every search of the run was read to its end (no
ad links, no posted window, no stop); when more than half of the tracked ads (and more than 5) are missing at once, none
are reported and the run says so in a free row.

#### Sample row (a real row of the prefill run; some fields left out)

```json
{
    "type": "listing",
    "adId": "453714340",
    "url": "https://suchen.mobile.de/fahrzeuge/details.html?id=453714340",
    "title": "Volkswagen Golf VIII 1.5 eTSI Goal DSG LED Navi App-Connect",
    "make": "Volkswagen",
    "model": "Golf",
    "vehicleType": "Car",
    "category": "Limousine",
    "condition": "used",
    "price": 23950,
    "currency": "EUR",
    "priceNet": 20126.05,
    "vat": "19% MwSt.",
    "vatReclaimable": true,
    "previousPrice": 24490,
    "priceRating": "REASONABLE_PRICE",
    "priceRatingLabel": "Fairer Preis",
    "priceRatingBands": [16200, 21100, 22700, 25300, 27100, 30200],
    "mileageKm": 49497,
    "firstRegistration": "12/2024",
    "powerKw": 85,
    "powerHp": 116,
    "fuel": "Benzin",
    "gearbox": "Automatik",
    "emissionClass": "Euro 6e",
    "previousOwners": 1,
    "hu": "Neu",
    "monthlyFinanceRate": 230,
    "sellerType": "dealer",
    "sellerId": "40743285",
    "dealerName": "Autoland NL Hönow",
    "dealerRating": 5,
    "dealerRatingCount": 15,
    "sellerPhone": "+49 (0)3342 6044009",
    "postcode": "15366",
    "city": "Hoppegarten OT Hönow",
    "country": "DE",
    "imageCount": 36,
    "placement": "topAd",
    "onlineSince": "2026-08-09T01:06:00.000Z",
    "daysOnline": 67,
    "searchLabel": "Volkswagen Golf within 50 km of Berlin",
    "searchPage": 1,
    "searchPosition": 1,
    "source": "search",
    "detailsIncluded": false,
    "scrapedAt": "2026-10-15T04:03:38.045Z"
}
```

#### Coverage row (one per search)

`searchKind`, `searchLabel`, `searchMakeModel`, `searchKeyword`, `searchPlace`, `searchRadiusKm`, `searchDealerId`,
`vehicleType`, `sort`, `adsOnMobileDe` (mobile.de's total), `searchCap`, `slices`, `slicesWalked`, `adsBeyondReach`,
`pagesRead`, `adsSeen`, `adsDelivered`, `alreadyDelivered`, `knownToMonitor`, `filteredOut` and `filteredOutBy` (per filter),
`removedOrGone`, `detailsFailed`, `newAdsMayLieBeyond` (a monitor), `complete`, `stoppedBy`, `morePagesOffered` and a `note`.

#### Free status rows

A setting or an item the Actor refused (`invalid`), a make, model or place name that matches several entries
(`ambiguous`, with the candidates), a place mobile.de's place service does not know (`unknown_place`), an ad that was sold or
withdrawn or an id that never existed (`not_found`), an ad or a page that could not be read (`failed`), a search whose
filters mobile.de did not apply as sent (`search_not_applied`), an ad link a monitor already delivered (`skipped`), a
notification that failed (`notification_failed`), and the reason a run stopped (`limit_reached`, `source_unavailable`,
`monitor_unavailable`). A run writes 20 such rows plus one per paid event; past that it writes the first row of
each kind and counts the rest in the summary.

#### How searches are read

- **Past 2,000 ads.** mobile.de serves at most 100 pages of 20 ads for one search. When a search holds more and your caps
  want more, it is split into whole euro price slices cut at mobile.de's own price percentiles, each slice read from its
  first page; a slice still over 2,000 is halved again. The coverage row counts the slices and anything left beyond reach
  (ads without a price, or added during the walk). A platform run delivered 2,400 ads from one search of 59,021 this way.
- **Every filter checked.** mobile.de answers an unknown filter value or parameter with a wider search, without a word. The
  Actor sends only values from mobile.de's own lists, sends places as coordinates from mobile.de's own place service, and
  compares mobile.de's echo of the applied search with what it sent on every page; a page that differs is billed as nothing
  and gets a free `search_not_applied` row.
- **One row per ad.** An ad found by several searches in one run is delivered and billed once.
- **Access.** Requests leave through one Apify residential exit in Germany per run, one at a time, at 1.5 a second by
  default. A refusal is asked once more on the same exit after a pause; a second refusal ends the run's reading with a free
  `source_unavailable` row.

### How much does it cost to scrape mobile.de?

You pay per listing row delivered, plus a small start fee per run. Platform usage and the residential proxy are included.

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Listing (per 1,000 ads from searches and search links) | $0.66 | $0.60 | $0.55 | $0.47 |
| Results page (per 1,000 pages of up to 20 ads that delivered a paid row; in a monitor run, every page read) | $2.00 | $1.90 | $1.80 | $1.60 |
| Listing details (per 1,000 rows, only with `includeDetails`) | $2.03 | $1.86 | $1.68 | $1.45 |
| Listing by URL (per 1,000 ads from `adUrls`) | $2.60 | $2.40 | $2.20 | $1.90 |
| Listing update (per 1,000 changes and removed rows, monitor runs with `trackChanges` only) | $0.66 | $0.60 | $0.55 | $0.47 |
| Dealer profile (per 1,000 dealers, only with `includeDealerProfiles`) | $25.00 | $24.00 | $22.00 | $20.00 |
| Actor start (per run) | $0.0075 | $0.0075 | $0.0075 | $0.0075 |

Platinum and Diamond plans pay the Gold price. The Actor start event is a flat $0.0075, charged once per run, with no plan
discount. The Store pricing card shows these same prices per 1,000 events: "$0.60 / 1,000" on the Listing row means one
listing costs $0.0006, and "$24.00 / 1,000" on the Dealer profile row means one dealer profile costs 2.4 cents.

- **1,000 listings from one search** fill 50 results pages of 20: 1,000 Listings + 50 Results pages + 1 Actor start. That is
  $0.66 + $0.10 + $0.0075 = **$0.7675** on Free, $0.60 + $0.095 + $0.0075 = **$0.7025** on Bronze, $0.55 + $0.09 + $0.0075 =
  **$0.6475** on Silver and $0.47 + $0.08 + $0.0075 = **$0.5575** on Gold. With Listing details on, add $1.86 on Bronze:
  $2.5625.
- **100 ad links** on Bronze cost 100 x $0.0024 = $0.24, plus $0.0075: $0.2475.
- **A monitor run** on Bronze over 2 searches reads 3 pages each (6 x $0.0019 = $0.0114); with 12 new listings it costs
  $0.0114 + 12 x $0.0006 + $0.0075 = $0.0261.
- **Dealer profiles** for 3 dealers on Bronze add 3 x $0.024 = $0.072 to the run.
- **What is never billed:** ads left out by your filters, an ad found twice in one run, ads a monitor already delivered
  (unless change tracking finds a change, or you ask for a full snapshot), sold, withdrawn and unknown ads, a page whose
  filters mobile.de did not apply, a dealer profile that could not be read, coverage, status and summary rows, the run
  report and the notifications.
- **Limits:** set **Maximum listings** (100 when left empty) and, in the run options, a maximum charge for the run: the
  Actor stops before it would pass either, and a row whose events do not all fit is withheld whole. Maximum listings counts
  listings, changes and removed rows together. A run also spends a small allowance on work that delivers nothing billable
  (place lookups, pages whose ads your filters leave out), USD 0.0012 plus a share of every paid event it delivers; a long
  list of searches that find nothing stops early with a free run row that says so.

### Input

| Setting | What it does |
|---|---|
| `makeModels` | car makes or makes with a model as mobile.de lists them, a model group with "(all)", or ids such as `25200;14` (cars only) |
| `keywords` | free text for mobile.de's own keyword search |
| `vehicleType` | car (default), motorbike, motorhome, van, truck, semi_trailer_truck, trailer, semi_trailer, bus, construction, agricultural, forklift, ebike |
| `locations`, `radiusKm` | postcodes, place names, `"Paris, FR"` style places, or coordinates; a radius of 1 to 1,000 whole km (50 by default; mobile.de searches whole kilometres only) |
| `country` | only vehicles offered in this country (two letters: DE, AT, NL ...) |
| `dealers` | dealer ids (`sellerId` on every row) or storefront links `https://home.mobile.de/<NAME>` |
| `searchUrls` | `https://suchen.mobile.de/fahrzeuge/search.html?...` links (the first page); a parameter the Actor does not know refuses the link with a free row |
| `adUrls` | `details.html?id=` links, `.../auto-inserat/<name>/<id>.html` links or ids, each billed as a Listing by URL |
| named filters | `fuelTypes`, `gearbox`, `bodyTypes`, `colors`, `vehicleCategories`, `driveTypes`, `emissionClasses`, `priceRatings`, `condition`, `sellerType`, `damaged`, `vat`, `doors`, `emissionSticker`, `minPrice` to `maxPrice`, `yearMin` to `yearMax`, `mileageMin` to `mileageMax`, `powerMinKw` to `powerMaxKw` or `powerMinHp` to `powerMaxHp`, `seatsMin` to `seatsMax`, `engineSizeMin` to `engineSizeMax`, `previousOwnersMax`, `huValidMonths`, `onlineWithinDays`, `minDealerRating`, `roadworthyOnly`, `withPicturesOnly`, `priceReducedOnly`, `withVideoOnly`, `qualitySealOnly`, `leasingOnly`, `excludeExportOffers`, `features` |
| `filters` | any other mobile.de parameter by name: a list of values or `{"min": n, "max": n}`; an unknown name or value refuses the run with a free row |
| row filters | `includeKeywords`, `excludeKeywords`, `customFilters`, `postedWithinHours`, `postedWithinDays`, `postedAfter`, `postedBefore` (newest or oldest sort), `excludeAdIds` (up to 5,000) |
| `sort` | newest (default), oldest, price_low, price_high, mileage_low, mileage_high, registration_new, registration_old, relevance |
| `maxItems`, `maxItemsPerSearch`, `maxPagesPerSearch`, `startPage`, `splitLargeSearches`, `includeTopAds` | caps and how far each search is read |
| `includeDetails`, `includeDealerProfiles`, `maxDealerReviews` | the two add-ons |
| `language`, `currency`, `imageSize`, `descriptionFormat`, `descriptionMaxLength`, `compactOutput`, `excludeEmptyFields` | how rows are written |
| `includePersonalData` | a private seller's phone and exact coordinates (off by default; see Privacy) |
| monitor and notifications | `monitorName`, `trackChanges`, `trackFields`, `emitUnchanged`, `markReposts`, `skipReposts`, `notificationLimit`, `notifyOnlyChanges` and the channel settings below |
| `failIfIncomplete`, `requestsPerSecond`, `proxyConfiguration` | fail the run when a search was not read to its end; the pace (0.5 to 2 a second); Apify residential in Germany (default) or your own proxy links |

A run holds up to 100 searches (makes and models x keywords x places x dealers, plus one per search link) and up to 5,000
ad links.

### The monitor and notifications

Name a monitor (`monitorName`) and schedule the Actor (every hour, for example). The monitor remembers every ad it delivered
in a named store this Actor creates for itself, up to 40,000 ads, so each run delivers and bills only ads it never
delivered before; known ads are skipped for free. A monitor reads newest first, the newest 3 pages of 20 ads of each search
by default (set `maxPagesPerSearch` to change it), and pays a Results page for each page it reads; when the coverage row
says `newAdsMayLieBeyond`, raise the pages or run more often. One monitor name belongs to one set of settings: a run with
other settings delivers nothing and gets a free row saying so.

- **Change tracking** (`trackChanges`): a known ad whose price changed comes back with `change` (previous price, difference,
  first seen price, up to 6 dated prices, drop in percent since first seen), billed as a Listing update. With `trackFields`
  a change of other fields counts too (`changeType: "updated"`, `changedFields`). When every search was read to its end, an
  ad the monitor tracks that the run did not meet gets a `removed` row; one that comes back is `reappeared`.
- **Snapshots and reposts:** `emitUnchanged` delivers known ads again (billed as Listing); `markReposts` marks a new ad with
  the same seller, make, model, first registration, mileage and power as one the monitor delivered earlier under another
  id (`possibleRepostOf`), and `skipReposts` leaves it out free. Two such twins that are both new in one batch (the ads of
  one page, or 10 with details) are both delivered.
- **Notifications** (free, with or without a monitor) after the rows were delivered and billed: Telegram (your own bot, one
  message per listing), Slack and Discord incoming webhooks and WhatsApp Cloud API (one message per run), each naming up to
  `notificationLimit` listings (10 by default, up to 30); a webhook (`webhookUrl`) gets JSON batches of 100, up to 1,000 a
  run, signed in the header `x-signature-sha256` with `webhookSecret` (8 to 200 characters), with your own `webhookHeaders`. A failed call never
  fails the run: it is a free `notification_failed` row, without your address or token.

### Privacy and personal data

Private sellers and company cars count as private persons. With `includePersonalData` off (the default), the phone number
mobile.de shows for them is not delivered, phone numbers and e-mail addresses written into their title, subtitle and
description are replaced with `[phone number removed]` and `[e-mail removed]`, and the exact coordinates of the details are
rounded to 2 decimals (about 1 km); their HTML description (`descriptionFormat` html or all) is rebuilt from the masked
text, as plain paragraphs. With it on, these come as mobile.de shows them logged out. A dealer's name, address,
phones, opening hours, rating and contact person are business data and are always delivered. Dealer reviews carry the
reviewer's shown first name as mobile.de shows it. Photos are delivered as links; they belong to the people who posted
them. You are responsible for a lawful use of personal data, GDPR included.

### Legal

This Actor is not affiliated with, endorsed by or sponsored by mobile.de. mobile.de is a trademark of its owner.
mobile.de's terms forbid automated extraction, and German law protects databases (the database maker's right, sections 87a
to 87e of the Urheberrechtsgesetz). You are responsible for a lawful use of the data, for complying with the GDPR for any
personal data, and for keeping a scheduled monitor to what you need.

### What this Actor does NOT do

- **No login, no messages to sellers, no offers, no saved searches or anything else that needs a mobile.de account.**
- **No private seller phone numbers or exact coordinates unless you turn on `includePersonalData`.** Dealers' business
  contacts are always delivered.
- **No e-mail addresses from a dealer's own website.** E-mail addresses come only as the dealer shows them on its mobile.de
  storefront (Dealer profiles). No other sites are read.
- **No AI summaries of an ad and no translation.** Descriptions come as the seller wrote them; `language` sets the language
  of mobile.de's labels only.
- **No more than 2,000 ads from one mobile.de search page walk.** Past that the search is split by price automatically
  (`splitLargeSearches`, on by default, not in a monitor); ads without a price cannot be reached that way and are counted
  on the coverage row.
- **No more than 10 reviews per dealer, and about 3 dealer profiles per run.**
- **No radius in miles.** mobile.de searches a radius in whole kilometres only; give `radiusKm` (1 mile is 1.609 km).
- **No export into Notion, Airtable or other apps from inside the run.** Connect the dataset with Apify's integrations,
  using your own accounts.
- **No preloaded snapshot.** Every run reads mobile.de live; the data is as fresh as the run.
- **Field names in English only.** mobile.de's labels come in German or English (`language`).

### FAQ

#### Does mobile.de have an API?

mobile.de's own APIs (search, ad stream, seller) are for dealers and contracted partners and answer an anonymous call with
HTTP 401. This Actor reads the same public ads any visitor sees, with no login, and gives them to you as rows you can read
through the Apify API (examples below).

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

This Actor reads only public ads without logging in, and a private seller's phone number comes only when you turn it on.
mobile.de's terms forbid automated extraction and German law protects databases, so you are responsible for a lawful use of
the data, the GDPR included (see Legal).

#### How many ads can one mobile.de search return?

mobile.de serves at most 2,000 ads (100 pages of 20) for one search. Past that, this Actor splits the search into price
slices on its own and reads every slice; the coverage row gives mobile.de's total, the slices read and anything left beyond
reach.

#### What is the mobile.de price rating?

It is mobile.de's own rating of an ad's price against the market, from very good price to high price. Every row carries it
(`priceRating`, `priceRatingLabel`) with the six price thresholds mobile.de rates the vehicle against (`priceRatingBands`),
and you can search by it (`priceRatings`).

#### How do I get alerts for new mobile.de listings?

Name a monitor and schedule the Actor, every hour for example. Each run delivers and bills only ads the monitor has not
delivered before, and can send them to Telegram, Slack, Discord, WhatsApp or your webhook.

#### Why does this Actor run with limited permissions?

It needs nothing beyond its own storages: it reads mobile.de's public ads and writes to its own dataset and key-value store.
Limited permissions keep it from touching anything else in your account. A monitor's memory is a named store the Actor
creates for itself.

### API

Each example starts a run and waits for its rows (the run-sync endpoint suits short runs; use `maxItems` to keep them short).

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~mobile-de-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"makeModels": ["Volkswagen Golf"], "locations": ["Berlin"], "radiusKm": 50, "maxItems": 10}'
```

```js
const res = await fetch('https://api.apify.com/v2/acts/automation_craft~mobile-de-scraper/run-sync-get-dataset-items', {
    method: 'POST',
    headers: { Authorization: 'Bearer <YOUR_API_TOKEN>', 'Content-Type': 'application/json' },
    body: JSON.stringify({ makeModels: ['Volkswagen Golf'], locations: ['Berlin'], radiusKm: 50, maxItems: 10 }),
});
const rows = await res.json();
console.log(rows.filter((r) => r.type === 'listing'));
```

```python
import requests

res = requests.post(
    "https://api.apify.com/v2/acts/automation_craft~mobile-de-scraper/run-sync-get-dataset-items",
    headers={"Authorization": "Bearer <YOUR_API_TOKEN>"},
    json={"makeModels": ["Volkswagen Golf"], "locations": ["Berlin"], "radiusKm": 50, "maxItems": 10},
    timeout=330,
)
listings = [r for r in res.json() if r["type"] == "listing"]
```

### Changelog

See the Changelog tab. 0.1: first release.

### More data tools by Automation Craft

- [Kleinanzeigen Scraper & API: Ads, Prices, Places](https://apify.com/automation_craft/kleinanzeigen-scraper)
- [Leboncoin Scraper: Ads, Prices, Real Estate & Cars](https://apify.com/automation_craft/leboncoin-scraper)
- [Kijiji Scraper: Listings, Cars, Rentals & Prices](https://apify.com/automation_craft/kijiji-scraper)
- [OfferUp Scraper: Local Listings, Prices, Sellers](https://apify.com/automation_craft/offerup-scraper)
- [Facebook Marketplace Scraper with Sold Tracker](https://apify.com/automation_craft/facebook-marketplace-scraper)

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/mobile-de-scraper/changelog.md

# Actor input Schema

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

Car makes, or makes with a model, as mobile.de lists them: "Volkswagen", "Volkswagen Golf", "BMW 3er Reihe (all)" (a whole model group), "Mercedes-Benz C 200". Ids work too ("25200;14"). Cars only; for other vehicle types use Keywords or a search link.

## `keywords` (type: `array`):

Free text searched by mobile.de in the ads (its own keyword search), such as "GTI", "Standheizung", "Garantie".

## `vehicleType` (type: `string`):

The kind of vehicle every built search reads. Default: cars. A search link carries its own type.

## `locations` (type: `array`):

German postcodes (10115) or place names as mobile.de's place service writes them (Berlin, "Neustadt an der Weinstraße, Rheinland-Pfalz"), places in France, Italy, Poland or Romania with their country ("Paris, FR"), or coordinates ("52.52, 13.40"). Each is searched with the radius below. A name the service does not know exactly, or that names several places, is a free row listing what it found.

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

The radius around each place (1 to 1,000 km). Default 50 km when a place is given.

## `country` (type: `string`):

Only vehicles offered in this country, as a two letter code: DE, AT, NL, BE, IT ... (mobile.de also lists dealers abroad).

## `dealers` (type: `array`):

A dealer's whole stock: the dealer id shown on every row (sellerId, such as 453428) or the dealer's storefront link https://home.mobile.de/<NAME>. Combined with the makes, keywords, places and filters above.

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

Links of mobile.de results pages, https://suchen.mobile.de/fahrzeuge/search.html?... (paste the first page). Every parameter of the link is read; a parameter this Actor does not know refuses the link with a free row, because mobile.de would drop it and search wider. The filters below apply to built searches; the row filters further down apply to links too.

## `adUrls` (type: `array`):

Single ads: https://suchen.mobile.de/fahrzeuge/details.html?id=461171143, the .../auto-inserat/<name>/<id>.html links, or the id alone. Each is read with its details and billed as a Listing by URL. A sold, withdrawn or unknown ad is a free row.

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

Any of these fuels.

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

Any of these gearboxes.

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

Any of these body types (cars).

## `colors` (type: `array`):

Any of these colours.

## `vehicleCategories` (type: `array`):

Only these special categories.

## `driveTypes` (type: `array`):

Any of these drives.

## `emissionClasses` (type: `array`):

Any of these emission classes.

## `priceRatings` (type: `array`):

mobile.de's own price rating of the ad against the market (Sehr guter Preis, Guter Preis ...).

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

New or used vehicles.

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

Dealers, private sellers or company cars.

## `damaged` (type: `string`):

mobile.de's damaged vehicle filter.

## `vat` (type: `string`):

Vehicles whose VAT a business can reclaim (the seller shows a net price), or not.

## `doors` (type: `string`):

Number of doors.

## `emissionSticker` (type: `string`):

The German environmental sticker (Umweltplakette), at least this one.

## `minPrice` (type: `integer`):

Price in euros, at least.

## `maxPrice` (type: `integer`):

Price in euros, at most.

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

First registration year, at least.

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

First registration year, at most.

## `mileageMin` (type: `integer`):

Kilometres, at least.

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

Kilometres, at most.

## `powerMinKw` (type: `integer`):

Engine power in kW, at least.

## `powerMaxKw` (type: `integer`):

Engine power in kW, at most.

## `powerMinHp` (type: `integer`):

Engine power in hp (PS), at least: sent to mobile.de in kW and checked on each row in hp. Give power in kW or in hp, not both.

## `powerMaxHp` (type: `integer`):

Engine power in hp (PS), at most.

## `seatsMin` (type: `integer`):

Number of seats, at least.

## `seatsMax` (type: `integer`):

Number of seats, at most.

## `engineSizeMin` (type: `integer`):

Cubic capacity, at least.

## `engineSizeMax` (type: `integer`):

Cubic capacity, at most.

## `previousOwnersMax` (type: `integer`):

At most this many previous owners (1 to 4). Allowed values: 1, 2, 3, 4.

## `huValidMonths` (type: `integer`):

The general inspection (HU) still valid for at least this many months; 0 means new HU. Allowed values: 0, 3, 6, 9, 12, 18.

## `onlineWithinDays` (type: `integer`):

mobile.de's own "online since" filter: ads put online within the last 1, 3, 7 or 14 days (works with any sort). Allowed values: 1, 3, 7, 14.

## `minDealerRating` (type: `integer`):

Dealers rated at least 3, 4 or 5 stars. Allowed values: 3, 4, 5.

## `roadworthyOnly` (type: `boolean`):

Vehicles their seller marks as roadworthy (fahrtauglich).

## `withPicturesOnly` (type: `boolean`):

Ads with pictures.

## `priceReducedOnly` (type: `boolean`):

Ads whose price was reduced.

## `withVideoOnly` (type: `boolean`):

Ads with a video.

## `qualitySealOnly` (type: `boolean`):

Ads with a manufacturer's used car quality seal.

## `leasingOnly` (type: `boolean`):

Ads offered with leasing.

## `excludeExportOffers` (type: `boolean`):

mobile.de's "Fuer Gewerbe, Ex-/Import" exclusion.

## `features` (type: `array`):

Vehicles with all of this equipment, as mobile.de lists it (its German names shown).

## `excludeMakeModels` (type: `array`):

Makes or models mobile.de leaves out of every built search, written like Makes and models ("Volkswagen Golf Plus", "Dacia").

## `filters` (type: `object`):

Any other filter of mobile.de's search by its own parameter name: a list of values or {"min": n, "max": n}. Examples: {"clim": \["AUTOMATIC_CLIMATISATION"], "it": \["LEATHER"], "cy": {"min": 6}, "tct": \["TRAILER_COUPLING_FIX"]}. Values are mobile.de's own; an unknown name or value refuses the run with a free row.

## `includeKeywords` (type: `array`):

Keep a row only when its title or subtitle (and its description and equipment, with details on) holds at least one of these words as a whole word, case not mattering.

## `excludeKeywords` (type: `array`):

Leave a row out when its title or subtitle (and its description and equipment, with details on) holds one of these words as a whole word ("Unfall", "Motorschaden", "Bastler").

## `customFilters` (type: `array`):

Rules on the delivered row: \[{"field": "powerHp", "op": "gte", "value": 150}, {"field": "description", "op": "notIncludes", "value": "Export"}]. Ops: includes, notIncludes, equals, notEquals (texts and numbers), gt, gte, lt, lte (numbers). Fields: price, priceNet, mileageKm, firstRegistrationYear, powerKw, powerHp, engineSizeCcm, seats, previousOwners, imageCount, dealerRating, dealerRatingCount, leasingRateMonthly, title, subtitle, make, model, fuel, gearbox, bodyType, color, emissionClass, city, postcode, country, sellerType, dealerName, priceRating, description, features, category. A row without the field fails every rule except notEquals and notIncludes.

## `postedWithinHours` (type: `integer`):

Ads put online within this many hours of the run's start (mobile.de's online date, German time). Needs the newest or oldest sort; a newest first search stops once it passes the window.

## `postedWithinDays` (type: `integer`):

The same window in days. Give one of hours, days or a date.

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

Ads put online on or after this day (German time), YYYY-MM-DD.

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

Ads put online on or before this day (German time), YYYY-MM-DD.

## `excludeAdIds` (type: `array`):

Ad links or ids skipped free on every search (up to 5,000), such as the adId values of an earlier run.

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

The order mobile.de returns ads in. A monitor reads newest first. When a search is split into price slices, each slice is read in this order.

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

The most listing rows the run delivers (searches and links together). Default 100.

## `maxItemsPerSearch` (type: `integer`):

The most listing rows one search or search link may deliver.

## `maxPagesPerSearch` (type: `integer`):

The most results pages (20 vehicles each) read per search, slices included. Without it a search is read to its end or to the caps. A monitor reads 3 pages per search by default.

## `startPage` (type: `integer`):

Begin each search at this results page (1 to 100), to continue a walk an earlier run stopped.

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

mobile.de serves at most 2,000 ads (100 pages) of one search. On (default), a larger search is split into whole euro price slices and every slice is read, so the caps decide how far the run goes; the coverage row says what could not be reached. Not used by a monitor.

## `includeTopAds` (type: `boolean`):

mobile.de shows one promoted vehicle above page 1 of a search. On (default), it is delivered like any row when it passes every filter (placement: topAd). Highlighted ads within the results are always included (placement: highlighted).

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

Read each row's details: the full description, the equipment list, every attribute (consumption, CO2, battery, cylinders, last service ...), all photos, the finance plan, and for dealers the address, all phone numbers, opening hours, contact person, rating breakdown and the 2 newest reviews. Billed as Listing details per row, only when read.

## `includeDealerProfiles` (type: `boolean`):

For dealer rows, read the dealer's storefront and rating pages once per dealer per run: up to 10 reviews with their texts, the e-mail addresses and website the dealer shows. mobile.de allows only a handful of these pages per run (10 pages, 3 per dealer: about 3 dealers); rows past that are delivered without the profile and without its charge. Billed as Dealer profile once per dealer.

## `maxDealerReviews` (type: `integer`):

How many reviews a dealer profile carries (0 to 10, default 10).

## `language` (type: `string`):

The language of mobile.de's labels on the rows (fuel, gearbox, body type, attributes, equipment). Numbers are the same either way; sellers' own texts stay as written.

## `currency` (type: `string`):

Adds the price converted at the European Central Bank's reference rate of the day (the rate and its date are on the row). Prices stay in euros as well.

## `imageSize` (type: `string`):

The size of the image links on the rows.

## `descriptionFormat` (type: `string`):

How the description of the details is delivered.

## `descriptionMaxLength` (type: `integer`):

Cut descriptions to this many characters.

## `compactOutput` (type: `boolean`):

Deliver only the core fields (for agents and quick sheets), plus the details and the dealer profile when you asked for them.

## `excludeEmptyFields` (type: `boolean`):

Drop fields that are empty on a row.

## `includePersonalData` (type: `boolean`):

Off (default): for private sellers and company cars, the phone number mobile.de shows is not delivered, phone numbers and e-mail addresses in their own title, subtitle and description are replaced, and the exact location of the details is rounded to about 1 km. On: those fields are delivered as mobile.de shows them. You are responsible for using personal data lawfully (GDPR included). Dealers' names, addresses and phone numbers are business data and always delivered.

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

A short name (letters, digits, spaces and . \_ , - : # ( ), up to 60) that keeps this search's memory between runs. A memory belongs to one set of settings.

## `trackChanges` (type: `boolean`):

With a monitor: a known ad whose price changed is delivered again with its change (previous price, difference, first seen price, history, drop in percent) as a Listing update; an ad that a later complete run no longer meets is reported as removed (a Listing update), and a removed ad that comes back is delivered as reappeared.

## `trackFields` (type: `array`):

With change tracking: the fields whose change delivers a known ad again as a Listing update (default: price only). A row names the fields that changed (changedFields); a change of a field other than price comes with changeType updated.

## `emitUnchanged` (type: `boolean`):

With a monitor: deliver known ads again too (changeType: unchanged), billed as Listing, for a full snapshot every run.

## `markReposts` (type: `boolean`):

With a monitor: a new ad with the same dealer id, make, model, first registration, mileage and power as an ad the monitor delivered under another id carries possibleRepostOf.

## `skipReposts` (type: `boolean`):

With a monitor: leave such reposts out, free.

## `notificationLimit` (type: `integer`):

How many listings each notification channel names per run (1 to 30, default 10).

## `notifyOnlyChanges` (type: `boolean`):

With a monitor and Deliver known ads again: leave unchanged listings out of the notifications.

## `telegramBotToken` (type: `string`):

Your own bot's token from BotFather: each run sends its listings to the chat below. Free.

## `telegramChatId` (type: `string`):

Your chat id (a number) or a channel name starting with @ where your bot can post.

## `slackWebhookUrl` (type: `string`):

A Slack incoming webhook link (https://hooks.slack.com/...): one message per run with the listings. Free.

## `discordWebhookUrl` (type: `string`):

A Discord channel webhook link (https://discord.com/api/webhooks/...): one message per run with the listings. Free.

## `whatsappAccessToken` (type: `string`):

Your WhatsApp Business Cloud API access token (Meta): one message per run to the number below. Meta delivers free text only within 24 hours of the recipient's last message to your number. Free here; Meta may charge you.

## `whatsappPhoneNumberId` (type: `string`):

The phone number id of your WhatsApp Business account (digits, from the Meta dashboard).

## `whatsappTo` (type: `string`):

The recipient's number in international form without +, such as 491701234567.

## `webhookUrl` (type: `string`):

An https address that receives the listings of each run as JSON (batches of 100, up to 1,000 a run). Free.

## `webhookSecret` (type: `string`):

Signs each webhook call: header x-signature-sha256 is the HMAC SHA-256 of the body with this secret (8 to 200 characters).

## `webhookHeaders` (type: `object`):

Extra headers for the webhook call, such as {"Authorization": "Bearer ..."} (at most 10).

## `failIfIncomplete` (type: `boolean`):

Mark the run as failed when a search or an ad link could not be read to its end (mobile.de refused, a page failed, a filter was not applied, the work allowance ran out). Rows delivered stay delivered and billed.

## `requestsPerSecond` (type: `number`):

The pace of requests to mobile.de (0.5 to 2, default 1.5). One request is in flight at a time.

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

Apify residential proxies in Germany are used by default and included in the price (mobile.de refuses Apify's datacenter addresses). Other Apify groups or countries are refused; your own proxy links (http://user:password@host:port) are used as given.

## Actor input object example

```json
{
  "makeModels": [
    "Volkswagen Golf"
  ],
  "locations": [
    "Berlin"
  ],
  "radiusKm": 50,
  "condition": "any",
  "sellerType": "any",
  "damaged": "any",
  "vat": "any",
  "doors": "any",
  "emissionSticker": "any",
  "roadworthyOnly": false,
  "withPicturesOnly": false,
  "priceReducedOnly": false,
  "withVideoOnly": false,
  "qualitySealOnly": false,
  "leasingOnly": false,
  "excludeExportOffers": false,
  "sort": "newest",
  "maxItems": 10,
  "splitLargeSearches": true,
  "includeTopAds": true,
  "includeDetails": false,
  "includeDealerProfiles": false,
  "language": "de",
  "currency": "EUR",
  "imageSize": "large",
  "descriptionFormat": "text",
  "compactOutput": false,
  "excludeEmptyFields": false,
  "includePersonalData": false,
  "trackChanges": false,
  "emitUnchanged": false,
  "markReposts": false,
  "skipReposts": false,
  "notifyOnlyChanges": true,
  "failIfIncomplete": false
}
```

# Actor output Schema

## `items` (type: `string`):

No description

## `report` (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 = {
    "makeModels": [
        "Volkswagen Golf"
    ],
    "locations": [
        "Berlin"
    ],
    "radiusKm": 50,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/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 = {
    "makeModels": ["Volkswagen Golf"],
    "locations": ["Berlin"],
    "radiusKm": 50,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/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 '{
  "makeModels": [
    "Volkswagen Golf"
  ],
  "locations": [
    "Berlin"
  ],
  "radiusKm": 50,
  "maxItems": 10
}' |
apify call automation_craft/mobile-de-scraper --silent --output-dataset

```

## MCP server setup

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