# Kleinanzeigen Listings Scraper (`automatic/kleinanzeigen-scraper`) Actor

Collect public listings from kleinanzeigen.de, Germany's classifieds marketplace, with pagination and optional listing details. Search across categories or focus on Immobilien rentals and purchases.

- **URL**: https://apify.com/automatic/kleinanzeigen-scraper.md
- **Developed by:** [Philip Kirkbride](https://apify.com/automatic) (community)
- **Categories:** E-commerce, Real estate
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 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

## Kleinanzeigen Listings Scraper

Collect public listings from kleinanzeigen.de, Germany's classifieds marketplace, with pagination and optional listing details. Search across categories or focus on Immobilien rentals and purchases. Each result is a unique listing; missing source fields remain null.

### Quick start

Run with empty input to collect 20 bicycle listings across Germany. Details are off by default, so this typically needs one search request plus its redirect and finishes well within five minutes when the source is available.

```json
{"keyword":"fahrrad","maxResults":20,"includeDetails":false}
```

For Berlin apartment rentals:

```json
{"category":"apartments-rent","location":"Berlin","radiusKm":"10","maxResults":20,"includeDetails":true}
```

You can supply a kleinanzeigen.de search URL instead of keyword, category, location and radius. Price limits can constrain either mode. Use an exact city name; ambiguous locations fail with a short message so a similarly named place is never silently substituted. Advanced categories, postal locations and source-specific filters are supported through search URLs.

### Input

| Field | Purpose |
| --- | --- |
| `keyword` | Search phrase; empty input searches for `fahrrad` |
| `category` | All, Immobilien, apartments or houses for rent/buy, cars, bicycles, electronics, home/garden or fashion |
| `location`, `radiusKm` | Exact city and optional radius (0, 5, 10, 20, 30, 50, 100, 150 or 200 km) |
| `priceFrom`, `priceTo` | Inclusive EUR bounds; unknown prices excluded when constrained |
| `searchUrl` | HTTPS search page URL; replaces search construction inputs |
| `maxResults` | Unique listing limit, 1–1250; default 20 |
| `includeDetails` | Fetch one additional page per listing; default false |
| `proxyConfiguration` | Optional Apify proxy fallback after direct access is blocked; disabled by default |
| `maxTotalChargeUsd` | Optional additional spending ceiling; the platform run charge limit also applies |

### Output

Results appear in the default dataset and can be exported as JSON, CSV or Excel. The output links to that dataset; the `OUTPUT` record contains counts, request totals, stop reason and source issues.

Fields: `id`, `url`, `title`, `price`, `currency`, `priceType` (`fixed`, `VB`, `free`), `categoryPath`, `location` (`postcode`, `city`, `district`), `postedAt`, `sellerType` (`private` or `commercial`), `descriptionExcerpt`, `imageUrls`, `rooms`, `livingAreaM2`, `transactionType` (`rent` or `buy`), `warmRent`, `coldRent`, `detailsParsed`, and `detailsError`.

Seller names, seller IDs, phone numbers and email addresses are never output as fields. The description excerpt is the seller's own text: it is limited to 1000 characters and contact-bearing lines, sign-off blocks (a German closing such as `LG`, `VG`, `MfG`, `Viele Grüße` or `Mit freundlichen Grüßen`, at the start of a line or after `.`, `!`, `?` or `,`, together with the rest of its line when that is at most three capitalised words without digits, as in `LG Alex`; when the closing ends its line, up to three following lines that together form such a name tail go too, and later lines are kept; the abbreviations count in capitals or with only a capital first letter (`Lg`, as phones autocapitalise), never all-lowercase, and may follow `Danke und` or `Danke &` like the spelled-out closings; a bare `LG` or `Lg` followed by an all-caps word or a product word such as `Monitor`, `Smart` or `Gram` is the brand and stays; an excerpt that is only a sign-off is dropped), honorific names (`Herr`, `Herrn`, `Frau` or `Hr.`, or `Fr.` followed by a title, plus up to three capitalised name words with any `Dr.`/`Prof.`/`med.`/`Dipl.-Ing.` titles before them and `von`/`van`/`de`/`zu` particles between them; a few common words, such as `Größe`, `Gr.` or `Holle`, never count as a name word, so `Frau Größe M` stays and `Frau Schwarz Gr. 38` keeps `Gr. 38`) and introduced names (`Ich heiße …`, `mein Name ist …`, `Ansprechpartner(in): …`; a line with such an introduction whose name is not capitalised is dropped) are removed, but other free text may still mention people or a street address the seller wrote in (commercial sellers often give their shop address). Locality labels reflect source geography; the source sometimes supplies a district without its enclosing city, and outside the city states the state name in the locality is dropped so `city` stays the town. Rent fields exist only for rentals (`transactionType` `rent`) and are populated from explicitly labelled source values, or from the displayed price when its label, the attribute list or the title names the kind — the full words `Kaltmiete`/`Warmmiete`/`Kosten insgesamt`, or a bare `Kalt`/`Warm` sitting directly next to an amount (`2200 Kalt`, `1036 warm`); an unlabelled, contradictory or non-rental price leaves both null. Relative dates use the observation date in UTC; dates have day precision.

### Limits and source availability

The public search interface exposes at most 50 pages (about 1250 organic listings, with promoted cards and duplicates reducing coverage). Narrow your search to obtain additional coverage. External sponsored cards are excluded and promoted listings are deduplicated by listing ID. Listings can change or disappear between search and details; failed details retain the search result with `detailsError`.

Blocked or changed pages produce a status message and retain results already delivered. Optional proxy fallback requires your explicit configuration; no residential route is enabled by default. Retry-After delays are honored, and the actor stops when the full delay cannot fit. A shared deadline reserves 20 seconds for final delivery and shutdown. A single empty page is fetched again before it is accepted as empty. Forward pagination is followed in whatever form the source renders it, including pages whose forward links are script-driven rather than plain anchors.

Pricing: $0.005 per run start plus $0.00075 per delivered listing. The start charge applies to every run, including a search with zero results. A listing costs the same with or without `includeDetails`; there is no separate details charge. Examples: 20 listings = $0.020, 1,000 listings in one run = $0.755. Start events are managed by the platform; each unique stored listing uses the SDK's default dataset item event. Blocked, empty, malformed and duplicate cards produce no listing charge. The optional input spending ceiling includes the planned start charge; the actual platform ledger is checked before each request and emission. Larger runs may finish early at the time, source or charge limit, and any run that stops before the requested limit says so in its status message and in the `OUTPUT` issues; a search that returns no listings finishes with zero results and a plain no-results message.

# Actor input Schema

## `keyword` (type: `string`):

Keyword to search. Empty input searches for fahrrad. Use searchUrl for advanced filters.

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

Category for generated searches, including apartment and house rental or purchase.

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

Exact city name, such as Berlin. Ambiguous names require a search URL. Omit for Germany.

## `radiusKm` (type: `string`):

Search radius in kilometres around location; zero uses the selected place only.

## `priceFrom` (type: `number`):

Inclusive price constraint in EUR. Unknown prices are excluded when this constraint is set.

## `priceTo` (type: `number`):

Inclusive price constraint in EUR. Unknown prices are excluded when this constraint is set.

## `searchUrl` (type: `string`):

HTTPS kleinanzeigen.de search page. Replaces keyword, category, location and radius; price constraints still apply.

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

Maximum unique listings; source exposes at most 50 pages per search.

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

Fetch one detail page per listing for description and property rent fields.

## `maxTotalChargeUsd` (type: `number`):

Optional additional spending ceiling including the planned $0.005 start and $0.00075 per listing; platform run charge limit also applies.

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

Optional fallback after a direct request is blocked. Disabled by default. Residential use requires an explicit proxy choice.

## Actor input object example

```json
{
  "keyword": "fahrrad",
  "category": "all",
  "radiusKm": "0",
  "maxResults": 20,
  "includeDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "keyword": "fahrrad",
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatic/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 = {
    "keyword": "fahrrad",
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automatic/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 '{
  "keyword": "fahrrad",
  "maxResults": 20
}' |
apify call automatic/kleinanzeigen-scraper --silent --output-dataset

```

## MCP server setup

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