# Kleinanzeigen Scraper — Listings, Prices & Sellers (`tortuga/kleinanzeigen-scraper`) Actor

Scrape Kleinanzeigen.de (eBay Kleinanzeigen) ads from any search URL or keyword + location: price, VB, postcode, date, attributes, images, seller type, optional full details.

- **URL**: https://apify.com/tortuga/kleinanzeigen-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** E-commerce, Real estate
- **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

## Kleinanzeigen Scraper

Scrape Kleinanzeigen.de (formerly eBay Kleinanzeigen), Germany's largest classifieds site: title, price, price type (VB / Festpreis / zu verschenken), postcode and town, posting date, category, attribute chips (mileage, first registration, m², rooms, ...), shipping option, all image URLs, seller type (private or commercial) and shop name, from any search URL or from a keyword + location + category. Turn on **Include ad details** to also get the full description, the complete attribute table, equipment features, region and the seller's display name, member-since date and badges.

Paste the Kleinanzeigen URL you see in your browser, with whatever filters and sort you picked, or type a keyword and a city and get every ad as clean JSON, CSV or Excel, or straight into your app through the API. It reads the structured data Kleinanzeigen embeds in its own pages, so the output is complete and stable, runs are fast (25 ads per request) and you pay only for the listings you get.

### What data does Kleinanzeigen Scraper extract?

Every ad on a results page gives you:

| Field | Description |
|---|---|
| `id`, `url` | Kleinanzeigen ad id and the ad URL |
| `title` | Ad title |
| `price`, `currency`, `priceText` | Numeric price in EUR and the text as shown (`"1.250 € VB"`) |
| `priceType` | `FIXED` (Festpreis), `NEGOTIABLE` (VB), `GIVE_AWAY` (zu verschenken) |
| `originalPrice` | Previous price when the seller reduced it |
| `adType` | `OFFER` (Angebot) or `WANTED` (Gesuch) |
| `postcode`, `district`, `locationText`, `locationId` | e.g. `"79117"`, `"Freiburg im Breisgau"`, `"Baden-Württemberg - Freiburg im Breisgau"` |
| `date`, `time`, `dateText` | Posting / bump date as ISO date, time for today's and yesterday's ads, and the raw text (`"Heute, 04:46"`) |
| `categoryId`, `categoryName`, `parentCategoryId`, `parentCategoryName` | e.g. `173` Smartphones in Elektronik |
| `attributes` | Attribute chips from the card: `["177.000 km", "EZ 07/2018"]`, `["59 m²", "3 Zi."]` (a name/value object when details are on) |
| `shippingAvailable`, `buyNowEnabled` | "Versand möglich" and "Direkt kaufen" flags |
| `onlineViewing` | Property ads offering an online viewing |
| `descriptionSnippet` | The description preview from the results page |
| `imageUrls`, `imageCount`, `hasVideos` | All photo URLs in large size |
| `sellerType` | `private` or `commercial` |
| `sellerId` | Kleinanzeigen user id |
| `sellerName`, `sellerShopUrl` | Shop / company name for commercial sellers (Pro shops, dealers, agents) |
| `isTopAd`, `isHighlighted`, `isPriorityAd` | Paid placement flags |
| `searchUrl`, `scrapedAt` | The search the ad came from and when |

With **Include ad details** on, each ad also gets:

| Field | Description |
|---|---|
| `description` | Full description text with line breaks |
| `attributes` | Every attribute as name/value: `{"Marke": "BMW", "Kilometerstand": "177.000 km", "Erstzulassung": "Juli 2018", ...}` |
| `features` | Equipment list, e.g. `["Klimaanlage", "Navigationssystem", "Sitzheizung"]` |
| `categoryPath` | e.g. `["Auto, Rad & Boot", "Autos"]` |
| `region` | Federal state, e.g. `"Bayern"` |
| `shipping` | Shipping text as shown: `"Versand möglich"`, `"Nur Abholung"`, `"+ Versand ab 1,99 €"` |
| `sellerName`, `sellerProfileName`, `sellerShopName` | Seller display name as shown on the ad (for shops: the shop name, plus the contact name shown) |
| `sellerActiveSince`, `sellerBadges`, `sellerAdsOnline` | Member since, badges ("TOP Zufriedenheit", "Freundlich", "Zuverlässig") and number of active ads |
| `latitude`, `longitude` | Ad location. Exact for commercial sellers, rounded to about 1 km for private sellers |
| `street` | Business address street, commercial sellers only |
| `detailsFetched` | `true` when the ad page was read |

### How to scrape Kleinanzeigen listings

1. Open [kleinanzeigen.de](https://www.kleinanzeigen.de), search, and set the filters you want (category, location, radius, price, private/commercial, sort).
2. Copy the URL from the address bar into **Start URLs**. Add as many searches as you like.
3. Or skip the browser: fill in **Search keyword**, **Location** (city or postcode), **Radius** and **Category**.
4. Set **Max items** and click **Start**. Download the results as JSON, CSV, Excel or HTML, or read them through the API.

### Input example

```json
{
  "startUrls": [{ "url": "https://www.kleinanzeigen.de/s-autos/muenchen/preis:1000:5000/c216l6411" }],
  "searchQuery": "iphone 15",
  "location": "Berlin",
  "radiusKm": 20,
  "categoryId": "173",
  "sellerType": "private",
  "maxItems": 200,
  "includeDetails": false
}
```

### Output example

```json
{
  "id": "3532637537",
  "url": "https://www.kleinanzeigen.de/s-anzeige/iphone-12-13-pro-max-magsafe-huelle-kamera-linsenschutz/3532637537-173-9365",
  "title": "iPhone 12/13 Pro Max MagSafe Hülle + Kamera Linsenschutz",
  "price": 29.0,
  "priceType": "NEGOTIABLE",
  "priceText": "29 € VB",
  "originalPrice": null,
  "currency": "EUR",
  "adType": "OFFER",
  "postcode": "79117",
  "district": "Freiburg im Breisgau",
  "locationText": "Baden-Württemberg - Freiburg im Breisgau",
  "date": "2026-10-05",
  "time": "04:46",
  "dateText": "Heute, 04:46",
  "categoryId": 173,
  "categoryName": "Smartphones",
  "parentCategoryName": "Elektronik",
  "attributes": [],
  "shippingAvailable": true,
  "buyNowEnabled": false,
  "descriptionSnippet": "Ich verkaufe Zubehör für das iPhone 12 oder 13 Pro Max. Enthalten sind: ...",
  "imageUrls": [
    "https://img.kleinanzeigen.de/api/v1/prod-ads/images/ab/ab799396-6b48-4601-b204-384056be460f?rule=$_59.AUTO",
    "https://img.kleinanzeigen.de/api/v1/prod-ads/images/c0/c099fe0f-defb-452b-9c29-62dc71edcc07?rule=$_59.AUTO"
  ],
  "imageCount": 2,
  "sellerType": "private",
  "sellerId": "25331230",
  "sellerName": null,
  "isTopAd": false,
  "searchUrl": "https://www.kleinanzeigen.de/s-iphone/k0",
  "scrapedAt": "2026-10-05T03:01:12+00:00"
}
```

With details on, a car ad adds for example `"attributes": {"Marke": "BMW", "Modell": "520", "Kilometerstand": "177.000 km", "Erstzulassung": "Juli 2018", "Kraftstoffart": "Diesel", "Leistung": "197 PS", "Getriebe": "Automatik", ...}`, `"features": ["Anhängerkupplung", "Klimaanlage", ...]`, `"region": "Bayern"`, `"sellerName": "Krasniqi"`, `"sellerActiveSince": "2022-04-09"`.

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

Kleinanzeigen shows 25 ads per page (plus up to 2 top ads) and at most 50 pages, so about 1,250 ads per search. That is a limit of the site, not of the scraper. To collect more, split the search: by subcategory, by city or postcode with a radius, or by price band (`minPrice` / `maxPrice`), and add each as its own start URL. Ads that appear in several of your searches are saved and charged only once per run. For "new ads" monitoring, keep the default newest-first sort and set **Max pages per search** to 1-3.

### Does it work for cars, apartments and jobs, not just items for sale?

Yes. Any Kleinanzeigen category works: Autos, Fahrräder, Elektronik, Mietwohnungen, Häuser, Jobs, Dienstleistungen, Haustiere, Zu verschenken and the rest. Category-specific values (mileage, first registration, living space, rooms, condition, type) come in `attributes`; turn on details for the full table.

### Does it collect phone numbers or require a login?

No login is needed. The scraper reads only what any visitor sees on the public pages. Phone numbers are hidden behind a login or click on Kleinanzeigen and are never collected. Seller display names are exported as shown on the ad. For private sellers the street address is never exported and coordinates are rounded to about 1 km.

### Do I need a proxy?

The defaults just work. Search result pages load fine through Apify's datacenter proxy (the default). Kleinanzeigen blocks many datacenter IP ranges on individual ad pages, so when **Include ad details** is on, an ad page that is blocked is retried through the **Proxy for ad pages** (residential Germany by default). In our tests about 1 in 4 ad pages needed the fallback, each about 0.17 MB of residential traffic. You can switch the fallback off, but then some ad pages may come back without details.

Typical platform usage (billed by Apify on top of the result price): about $0.01 per 1,000 listings without details and about $0.40 per 1,000 listings with details.

### 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 ads that are new or whose price, price type (VB / fixed / free) or crossed-out old price changed. Unchanged ads are dropped before any ad page is opened, so they are not charged (top ads that Kleinanzeigen rotates into the results are reported once, the first time they appear). **Max items** then sets how many listings are checked per run (keep the newest-first sort, e.g. 50-100 for the newest ads in a city). Save the input as a task and add a Schedule in Apify (for example every hour or daily); give each watch its own **Monitoring key** if several schedules use the same search. Every output item has `changeType` (`new` or `changed`), and changed items have `previousValues` with the old values, e.g. `{"price": 450, "priceType": "NEGOTIABLE"}`.

### Pricing

Pay per result: you are charged per listing saved to the dataset, plus a small extra per ad page when **Include ad details** is on. See the Pricing tab for the current prices. Platform usage is minimal because each request returns 25 listings.

### Integrations and API

Run it from the Apify API, schedule it (e.g. every hour for new ads in your area), and send results to Google Sheets, Slack, Make, Zapier, n8n or a webhook. Use `maxItems` to cap cost per run.

### Is it legal to scrape Kleinanzeigen?

This Actor collects publicly visible ad data that anyone can see without logging in. It does not log in, does not collect phone numbers or any data behind a click or login, and does not export private sellers' street addresses. Seller display names are personal data under the GDPR when they belong to private individuals: you are responsible for having a legitimate purpose and a legal basis for processing them, and for respecting Kleinanzeigen's terms of use. If in doubt, ask a lawyer.

### 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`):

Kleinanzeigen.de results pages with any filters and sort applied in the browser, e.g. https://www.kleinanzeigen.de/s-autos/muenchen/preis:1000:5000/c216l6411 or https://www.kleinanzeigen.de/s-handy-telekom/berlin/iphone-13/k0c173l3331r10. Single ad URLs (https://www.kleinanzeigen.de/s-anzeige/...) are accepted too and return that one ad with full details. Old ebay-kleinanzeigen.de links are rewritten. Leave empty if you use the search fields below.

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

Alternative to Start URLs: what you would type in the Kleinanzeigen search box, e.g. "iphone 15", "lego star wars", "3 zimmer wohnung".

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

City, district or postcode, resolved by Kleinanzeigen's own search box, e.g. Berlin, München, Köln, 20095. Leave empty for all of Germany.

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

Used with Location: search radius around it (Kleinanzeigen offers 5, 10, 20, 30, 50, 100, 150, 200). Leave empty for the location itself.

## `categoryId` (type: `string`):

Used with the search fields. Pick a category or leave empty for all categories. Any other category id works too (it is the number after 'c' in a Kleinanzeigen URL, e.g. 217 in /s-fahrraeder/c217).

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

Used with the search fields.

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

Used with the search fields.

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

Used with the search fields: only private sellers or only commercial sellers (shops, dealers, agents).

## `adType` (type: `string`):

Used with the search fields: offers (Angebote) or wanted ads (Gesuche).

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

Used with the search fields. Newest first is Kleinanzeigen's default and the best choice for monitoring new ads.

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

Stop after this many listings in total (across all searches). Keeps cost predictable. Kleinanzeigen shows 25 ads per page and at most 50 pages (about 1,250 ads) per search, so split large searches by category, location or price range to get more.

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

Stop each search after this many result pages (1-50). Useful for 'newest ads' monitoring where only the first pages matter.

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

Also open every ad page to get the full description, the complete attribute table (e.g. make, model, mileage, first registration, living space, rooms, condition), equipment features, region, seller display name, member-since date, badges and number of active ads. 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 ads or ads whose price changed. Use with a Schedule; unchanged ads are not charged. With this on, Max items is the number of listings checked per run (e.g. the newest 100).

## `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`):

Proxy for search result pages and the first attempt at ad pages. Apify Proxy (datacenter) works well for Kleinanzeigen search pages and is the default.

## `detailsProxyConfiguration` (type: `object`):

Kleinanzeigen blocks many datacenter IP ranges on ad pages (not on search pages). When 'Include ad details' is on and an ad page is blocked on the main proxy, it is retried through this proxy. Residential Germany is the default and is reliable; residential traffic is billed by Apify per GB (an ad page is roughly 0.1-0.3 MB compressed), and only blocked ad pages use it. Untick 'Use Apify Proxy' here to never use residential.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331"
    }
  ],
  "categoryId": "",
  "sellerType": "",
  "adType": "",
  "sort": "newest",
  "maxItems": 100,
  "maxPagesPerSearch": 50,
  "includeDetails": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "detailsProxyConfiguration": {
    "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://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    },
    "detailsProxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/kleinanzeigen-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://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331" }],
    "proxyConfiguration": { "useApifyProxy": True },
    "detailsProxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/kleinanzeigen-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://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "detailsProxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}' |
apify call tortuga/kleinanzeigen-scraper --silent --output-dataset

```

## MCP server setup

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