# Kleinanzeigen.de Scraper: Listings, Prices & Ad Details (`kyungminlee/kleinanzeigen-listings-scraper`) Actor

Scrape Kleinanzeigen.de (ex eBay Kleinanzeigen) ads by keyword, category, place or search URL, past the 125-result limit. Price, VB, category, postcode, date, shipping, photos; optional details: full description, attributes, coordinates. Private sellers stay anonymous. Unofficial.

- **URL**: https://apify.com/kyungminlee/kleinanzeigen-listings-scraper.md
- **Developed by:** [Kyungmin Lee](https://apify.com/kyungminlee) (community)
- **Categories:** E-commerce, Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Kleinanzeigen.de Scraper do?

**Kleinanzeigen.de Scraper** collects classified ads from [Kleinanzeigen.de](https://www.kleinanzeigen.de) (formerly eBay Kleinanzeigen), Germany's largest classifieds site. Search by **keyword**, **category** and **place** (16 states and 30+ big cities), or paste any Kleinanzeigen search URL. You get one flat row per ad: **title**, **price** with the **VB** (negotiable) and *Zu verschenken* (free) flags, **category**, **postcode and place**, **posted date**, **shipping possible**, **Direkt kaufen**, offer or wanted ad, a **short description**, the main **photo**, and card details such as mileage and first registration for cars or living space and rooms for flats.

Turn on **ad details** to also get the **full description**, all **attributes** (condition, type, size, mileage, rooms, rent costs, ...), **features** (Balkon, Keller, ...), **all photos**, **state and city**, **coordinates**, shipping details and the time the ad was last bumped.

It reads the same public pages a logged-out visitor sees. No account, cookies or browser are needed.

This is an **unofficial** tool. It is not affiliated with, endorsed by or connected to Kleinanzeigen GmbH or the Adevinta group.

### Why use Kleinanzeigen.de Scraper?

- **Built to finish.** Every page has a hard timeout and is retried on a fresh IP; the Actor slows down when the site pushes back. A bad page or search is skipped and logged, never the whole run, and the Actor stops cleanly with partial results before the run timeout instead of being killed. A `SUMMARY` record shows exactly what was read for each search.
- **More than 125 ads per search.** Kleinanzeigen allows robots to read only 5 result pages (125 ads) of a search. The Actor splits a big search into smaller ones by place and category and merges them without duplicates.
- **Privacy by design.** For private sellers it returns only "private" - never a name, user ID, profile link or phone number. Phone numbers and e-mail addresses inside private ads' texts are masked. For commercial sellers it returns the shop or company name.
- **Fair pricing.** You only pay for ads saved. Failed pages, duplicates and ads removed by your filters are never charged.
- **Use cases:** price research for used goods, cars and rentals; reselling and arbitrage alerts; market and demand analysis per region; lead lists of commercial shops; monitoring new ads with a daily schedule.

### How to scrape Kleinanzeigen

1. Click **Try for free**.
2. Enter one or more **search terms** (e.g. `fahrrad`, `iphone 15`), and optionally a **category** and **places**. Or paste **Kleinanzeigen URLs** of search pages or single ads.
3. Set **Maximum ads per search** and switch on **Include ad details** if you need them.
4. Optionally filter by price or by offers / wanted ads.
5. Click **Start** and download the results as JSON, CSV or Excel, or read them through the Apify API.

### Input

```json
{
  "searchQueries": ["e-bike", "lastenrad"],
  "category": "217",
  "locations": ["berlin", "hamburg"],
  "maxResults": 300,
  "splitSearches": true,
  "includeDetails": false,
  "minPrice": 200,
  "maxPrice": 3000,
  "offerType": "offers",
  "searchUrls": ["https://www.kleinanzeigen.de/s-wohnung-mieten/leipzig/c203l4233"]
}
```

- Every search term is searched in every selected place (here 2 terms x 2 places = 4 searches); without places, all of Germany.
- `searchUrls`: search pages keep their place, category, keyword and allowed attribute filters. Single ads (`/s-anzeige/...`) always return the full details.
- `maxResults` counts per search; 0 means as many as can be reached.
- `proxyConfiguration`: by default requests start on the run's own connection and move to Apify datacenter proxy IPs (a new IP per retry) as soon as Kleinanzeigen blocks or rate-limits it. Residential groups or your own proxy URLs are used for every request.

### Output

One dataset item per ad (details on):

```json
{
  "adId": "3517861201",
  "url": "https://www.kleinanzeigen.de/s-anzeige/e-mtb-nox-hybrid-all-mtn-5-9-pro-l/3517861201-217-6954",
  "title": "E-MTB NOX HYBRID ALL-MTN 5.9 PRO L",
  "price": 2900,
  "priceText": "2.900 €",
  "currency": "EUR",
  "negotiable": false,
  "free": false,
  "priceType": "FIXED",
  "category": "Fahrräder & Zubehör",
  "categoryPath": ["Auto, Rad & Boot", "Fahrräder & Zubehör"],
  "postcode": "96242",
  "locality": "Sonnefeld",
  "city": "Sonnefeld",
  "state": "Bayern",
  "latitude": 50.23,
  "longitude": 11.15,
  "postedAt": "2026-10-06",
  "adType": "offer",
  "shippingPossible": false,
  "shipping": "Nur Abholung",
  "attributes": {"Art": "Herren", "Typ": "Mountainbikes", "Zustand": "Sehr Gut"},
  "description": "Zum Verkauf steht dieses E-MTB Fully der Marke NOX ...",
  "imageCount": 6,
  "images": ["https://img.kleinanzeigen.de/api/v1/prod-ads/images/66/669943e3-..."],
  "sellerType": "private",
  "companyName": null,
  "searchInput": "e-bike / Fahrräder & Zubehör / Berlin",
  "detailScraped": true,
  "scrapedAt": "2026-10-07T12:00:00+00:00"
}
```

The run's key-value store also has a `SUMMARY` record: Kleinanzeigen's total per search, how many ads were saved, how the search was split, filtered or skipped items, failed pages and request timings.

### Data fields

| Field | Description |
|---|---|
| `adId`, `url` | Kleinanzeigen ad ID and page |
| `title` | Ad title |
| `price`, `priceText`, `currency` | Price in euros as a number, and as shown (e.g. "1.100 € VB") |
| `negotiable`, `free`, `priceType` | VB (Verhandlungsbasis), *Zu verschenken*, and with details `FIXED` / `NEGOTIABLE` / `GIVE_AWAY` |
| `category`, `categoryId`, `categoryPath` | Category name and ID (path with details) |
| `postcode`, `locality`, `locationId` | Postcode and place as listed |
| `city`, `state`, `latitude`, `longitude` | With details. Private sellers' coordinates are rounded to about 1 km |
| `postedAt`, `postedText`, `bumpedAt` | Posting date ("Heute, 18:28" becomes a Berlin-time timestamp); last bump with details |
| `adType`, `isWanted` | `offer` or `wanted` (*Gesuch*) |
| `isTopAd` | Paid "TOP" placement |
| `shippingPossible`, `shipping`, `directBuy`, `sellerGuarantee`, `securePayment` | Shipping and buying options |
| `descriptionSnippet`, `description` | Short text from the result list; full text with details |
| `cardAttributes` | Key facts shown in the result list, e.g. "122.000 km", "EZ 07/2018", "63 m²", "2 Zi." |
| `attributes`, `features` | With details: all attributes and feature tags |
| `imageUrl`, `imageCount`, `images` | Main photo, number of photos, all photo URLs with details |
| `sellerType` | `private` or `commercial` (from the result list when shown, always with details) |
| `companyName`, `isProShop` | Commercial sellers only: shop or company name |
| `searchInput`, `searchPath` | Which search and which split (place / category) found the ad |
| `detailScraped`, `detailError`, `pageTemplate` | Ad page status |

### Pricing: how much does it cost to scrape Kleinanzeigen?

Pay per event, only for ads saved:

| Event | Price | When |
|---|---|---|
| `listing` | $0.0008 ($0.80 per 1,000) | One ad from the search results |
| `listing-detail` | $0.0015 ($1.50 per 1,000) | One ad with its ad page, charged **instead of** `listing` |

A 50-ad test costs about $0.04. 10,000 ads cost about $8 (about $15 with details).

Failed pages and searches are never charged. If an ad page cannot be loaded, you still get the search data for that ad and pay only the `listing` price. Set a maximum charge for the run and the Actor stops exactly there.

### Tips and limits

- **How the 125-ad limit is handled.** Kleinanzeigen's robots.txt allows only result pages 1-5 of any search. When you ask for more, the Actor first saves those 125 newest ads exactly as the site lists them, then reads the same search in every sub-place the site's own location filter lists (states, then cities and districts), biggest first, and where a place still has more than 125 ads, in every category. Each ad is saved once. Results therefore come newest first per place, not in one global order.
- robots.txt also disallows Kleinanzeigen's **price filter, sorting, radius and seller-type URLs**. The Actor never requests them: price and offer/wanted filters are applied to the ads it reads (filtered ads are not charged); a pasted URL with sorting, a radius or a seller-type filter is read without it, and the log says so.
- Very common terms (hundreds of thousands of ads) cannot be read completely; the `SUMMARY` record says how many ads were out of reach.
- Speed (our cloud tests, 3 parallel sessions): without details about 2,000 ads per minute; with details about 1 ad per second (300 ads in 6 minutes). Raise `maxConcurrency` to 5 for faster detail runs.
- **Run timeout.** About 30 seconds before the run's timeout the Actor stops starting new pages, saves what it has and finishes as *Succeeded*. Ads still waiting for their detail page are saved with their search data (`detailError` says why) and charged as `listing`. For big detail runs, raise the timeout (default 1 hour).
- Contact details are not collected: phone numbers and messaging need a Kleinanzeigen login, and this Actor never logs in.
- To monitor new ads, save your input as a task, set a small `maxResults` and schedule it daily.

### FAQ

#### Do I need a Kleinanzeigen account?

No. The Actor reads public pages only and never logs in or uses cookies.

#### Does it collect personal data?

As little as possible. For private sellers it saves only that the seller is private: no name, initials, user ID, profile link, street or phone number; phone numbers and e-mail addresses inside private ads' titles and descriptions are replaced with "\[phone removed]" / "\[email removed]", and coordinates are rounded to about 1 km. For commercial sellers it saves the shop or company name. You are responsible for handling the data in line with the GDPR.

#### Why did I get fewer ads than Kleinanzeigen's total?

Check `maxResults`, your price / offer filters and the `SUMMARY` record. Ads already saved by another search in the same run are skipped, and robots.txt limits how deep a single search can go.

#### Is it legal to scrape Kleinanzeigen?

The Actor collects public ads at a polite rate, only from pages and URL forms Kleinanzeigen's robots.txt allows. You are responsible for how you use the data and for following the laws and terms that apply to you.

#### Is this an official Kleinanzeigen product?

No. This is an unofficial, independent tool and is not affiliated with Kleinanzeigen. Kleinanzeigen is a trademark of its owner.

Found a problem or need another field? Open an issue on the **Issues** tab.

# Actor input Schema

## `searchQueries` (type: `array`):

What you would type into the Kleinanzeigen search box, one per line (German works best), e.g. `fahrrad`, `iphone 15`, `sofa`. Each term is searched in every place selected below (or all of Germany). Leave empty to browse a category or place without a keyword.

## `category` (type: `string`):

Limit the search terms (or browsing) to one Kleinanzeigen category. Leave empty for all categories.

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

Search in these German states or cities. Leave empty for all of Germany. For any other town or district, open kleinanzeigen.de, choose the place there and paste the result URL into **Kleinanzeigen URLs**.

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

Paste URLs from kleinanzeigen.de, one per line: search result pages (`https://www.kleinanzeigen.de/s-...`, with any place, category or keyword) or single ads (`https://www.kleinanzeigen.de/s-anzeige/...`). Ad URLs always return the full ad details. Filters that Kleinanzeigen's robots.txt does not allow in URLs are handled as described in the README: price, offer/wanted and "Direkt kaufen" filters are applied to the results by the Actor; sorting, radius and seller-type filters are removed.

## `maxResults` (type: `integer`):

How many ads to save for each search (each search term in each place, and each search URL). 0 = as many as can be reached. Ads already saved by another search in the same run are skipped and do not count. The run's maximum charge can lower this.

## `splitSearches` (type: `boolean`):

Kleinanzeigen's robots.txt allows only the first 5 result pages (125 ads) of any search. When a search has more ads and you ask for more, the Actor first saves those 125 newest ads, then reads the same search in each sub-place (state → city → district) and, where a place is still too big, in each category, and merges everything without duplicates. Turn off to stop at 125.

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

Also open every ad page to add the full description, all attributes (e.g. condition, size, mileage, rooms, living space, rent costs), features, all photos, state, coordinates, shipping details and the last bump time. One extra request per ad, charged as `listing-detail` instead of `listing`.

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

Keep only ads with at least this price. Ads without a price (only "VB") are left out when a price filter is set.

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

Keep only ads with at most this price. Free ads ("Zu verschenken") count as 0 €.

## `offerType` (type: `string`):

Kleinanzeigen mixes offers with "Gesuch" (wanted) ads. Keep both, or only one kind.

## `maxConcurrency` (type: `integer`):

How many pages are loaded at the same time, each session pausing 1-2 seconds between its requests. Higher is faster; lower is gentler.

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

With the default Apify proxy, requests go out on the run's own connection first (the most reliable in our tests) and switch to Apify datacenter proxy IPs whenever Kleinanzeigen blocks or rate-limits it, with a fresh IP for every retry. If you choose specific proxy groups (e.g. residential) or your own proxy URLs, they are used for every request. Turn the proxy off to use only the run's own connection (with longer pauses when blocked).

## Actor input object example

```json
{
  "searchQueries": [
    "fahrrad"
  ],
  "maxResults": 50,
  "splitSearches": true,
  "includeDetails": false,
  "offerType": "all",
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "searchQueries": [
        "fahrrad"
    ],
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kyungminlee/kleinanzeigen-listings-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 = {
    "searchQueries": ["fahrrad"],
    "maxResults": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("kyungminlee/kleinanzeigen-listings-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 '{
  "searchQueries": [
    "fahrrad"
  ],
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call kyungminlee/kleinanzeigen-listings-scraper --silent --output-dataset

```

## MCP server setup

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