# Kleinanzeigen Scraper \[$0.39/1K 💰] — All Categories (`unfenced-group/kleinanzeigen-classifieds-scraper`) Actor

$0.39 per 1,000 listings — the lowest-priced Kleinanzeigen scraper on the Store. Every category: electronics, cars, furniture, collectables, property. Returns price type, postcode, images and attributes, with a private-seller filter. Same field names as our Marktplaats and 2dehands scrapers.

- **URL**: https://apify.com/unfenced-group/kleinanzeigen-classifieds-scraper.md
- **Developed by:** [Unfenced Group](https://apify.com/unfenced-group) (community)
- **Categories:** E-commerce
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.39 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Kleinanzeigen Scraper — All Categories

![Kleinanzeigen Classifieds Scraper](https://api.apify.com/v2/key-value-stores/ZWyNvTd4gLqXZi4VK/records/banner.png)

Scrape classified listings from kleinanzeigen.de — Germany's largest marketplace — across every category, from trading cards and phones to cars, furniture and rental flats. One search returns title, price, price type, location, images, publish date and item attributes. No API key required.

***

### Why this scraper?

#### 🇩🇪 Every category, one parser

Not a real-estate tool with a product mode bolted on. The extraction reads kleinanzeigen's own structured listing data, so a Pokémon search and an apartment search return the same fields in the same shape.

#### 🔗 Drops into a Marktplaats pipeline unchanged

Field names and the price-type vocabulary are identical to the Marktplaats.nl and 2dehands.be scrapers. If you already consume either of those, this is a third source with no adapter and no mapping layer.

#### 💶 Price type, not just price

`FIXED`, `MIN_BID`, `FAST_BID` and `SEE_DESCRIPTION` are resolved from the German conventions — a plain price, "VB" with a figure, "VB" alone, "Zu verschenken". You can tell a firm price from a negotiable one without parsing German.

#### 🧍 Private sellers, filtered at source

"Private sellers only" is applied by kleinanzeigen itself, not filtered after the fact. That matters because mispriced and one-off items sit with private sellers, and a commercial seller is not always visibly labelled on the results page.

#### 📍 Precise location on every row

Five-digit postcode and city on every listing, plus the district where the source publishes one. Search by any of 3,606 German towns, cities, districts and federal states.

#### 🔒 No personal data, by design

No seller names, no profile links, no avatars, no phone numbers, no email addresses. Seller type ships as a classification — `private` or `commercial` — and nothing that identifies a person.

***

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `searchQuery` | string | (empty) | Keyword to search for, in German. `pokemon karten`, `wohnung mieten`, `iphone 15`. Leave empty to browse a whole category. |
| `categoryId` | string | (all) | Restrict to one of 151 kleinanzeigen categories. Combine with a search query to search within a category. |
| `location` | string | (empty) | German town, city, district or federal state — `Berlin`, `München`, `Nordrhein-Westfalen`. Place names only; postcodes are not accepted here. |
| `minPrice` | integer | (none) | Only listings at or above this price in euros. |
| `maxPrice` | integer | (none) | Only listings at or below this price in euros. |
| `daysOld` | integer | (none) | Only listings published within this many days. `1` means today. |
| `sellerType` | string | `all` | `all`, `private` or `commercial`. Applied by kleinanzeigen itself. Needs a search query or a category alongside it. |
| `maxItems` | integer | `100` | Stop after this many listings. `0` for no limit. |
| `fetchDetails` | boolean | `false` | Open each listing for the full description, exact date, condition, item type, all gallery images and the confirmed seller type. |
| `startUrls` | array | `[]` | Kleinanzeigen search URLs to scrape directly. Overrides every filter above except `maxItems`. |
| `proxyConfiguration` | object | off | Optional. Off by default — see Technical details. |

***

### Output schema

Every field below is present on every record. Fields the source does not publish for a given listing are returned as `null` rather than omitted, so the shape never varies between rows.

#### Always present

| Field | Type | Description |
|---|---|---|
| `itemId` | string | Kleinanzeigen's own listing ID. Stable, and the key to deduplicate on. |
| `title` | string | Listing title as published. |
| `description` | string | null | Description snippet from the results page. |
| `url` | string | Full URL of the listing. |
| `detailUrl` | string | Same as `url`. Present for compatibility with the Marktplaats scrapers. |
| `priceEur` | number | null | Price in euros. `null` when the listing gives no figure. |
| `priceCents` | number | null | The same price in cents, for exact integer arithmetic. |
| `priceType` | string | `FIXED`, `MIN_BID`, `FAST_BID` or `SEE_DESCRIPTION`. See the table below. |
| `priceText` | string | null | The price exactly as displayed, e.g. `200 € VB`. |
| `reserved` | boolean | Whether the listing is marked reserved. |
| `city` | string | null | City or district name. |
| `postalCode` | string | null | Five-digit German postcode. |
| `district` | string | null | Sub-district, where the source publishes one. Populated with `fetchDetails`. |
| `country` | string | Always `Duitsland`, matching the Marktplaats scrapers' Dutch-language country field. |
| `sourceCountry` | string | Always `de`. |
| `imageUrls` | array | Image URLs. One from the results page; the full gallery with `fetchDetails`. Empty for listings published without a photo. |
| `scrapedAt` | string | ISO 8601 timestamp of when this row was collected. |
| `date` | string | null | Publish date, `YYYY-MM-DD`. `null` in categories where kleinanzeigen omits it — see Known limitations. |
| `publishedAt` | string | null | Publish date with time where the source gives one. |
| `searchKeyword` | string | null | The query that produced this row. |
| `categoryId` | string | null | The category this run searched, if one was set. |
| `attributes.condition` | string | null | Item condition. Populated with `fetchDetails`. |
| `attributes.delivery` | string | null | `Versand möglich` where the seller ships, otherwise the source's own delivery note. |
| `extendedAttributes.type` | string | null | Item type as the source classifies it, e.g. `Sammelkartenspiele`. With `fetchDetails`. |
| `extendedAttributes.condition` | string | null | Same as `attributes.condition`. |
| `extendedAttributes.properties` | string | null | Every attribute the listing publishes, as `key: value` pairs. With `fetchDetails`. |
| `sellerType` | string | null | `private` or `commercial`. Always populated when you filter by seller type. |
| `shippingAvailable` | boolean | Whether the seller offers shipping. |
| `isBuyNow` | boolean | Whether the listing supports kleinanzeigen's direct-purchase flow. |
| `isWanted` | boolean | `true` for a wanted ad (*Gesuch*) rather than an item for sale. |
| `isTopAd` | boolean | Whether this is a paid top placement. |
| `viewCount` | null | Always `null`. Present for Marktplaats compatibility — see Known limitations. |
| `favoriteCount` | null | Always `null`. Present for Marktplaats compatibility. |
| `source` | string | Always `kleinanzeigen.de`. |
| `contentHash` | string | Short hash of ID and title, for change detection between runs. |

#### With `fetchDetails: true`

| Field | Type | Description |
|---|---|---|
| `descriptionFull` | string | null | Complete listing description, not the truncated snippet. |
| `descriptionMarkdown` | string | null | The same text. Kleinanzeigen descriptions are plain text, so there is no separate markup to convert. |

#### Price types

| `priceType` | Kleinanzeigen shows | Meaning |
|---|---|---|
| `FIXED` | `25 €`, or `Zu verschenken` | A firm asking price. Giveaways come through as `0`. |
| `MIN_BID` | `200 € VB` | Negotiable, with a starting figure. |
| `FAST_BID` | `VB` | Negotiable, no figure given. `priceEur` is `null`. |
| `SEE_DESCRIPTION` | no price shown | The price is in the description text. |

#### Example record

```json
{
  "itemId": "3506282359",
  "title": "Pokemon Arceus V SWSH204 Promo englisch",
  "description": "Pokemon Promo Karte von Arceus V SWSH 204, siehe Bilder. Die Karte ist auf englisch, Boosterfrisch...",
  "url": "https://www.kleinanzeigen.de/s-anzeige/pokemon-arceus-v-swsh204-promo-englisch/3506282359-234-4236",
  "detailUrl": "https://www.kleinanzeigen.de/s-anzeige/pokemon-arceus-v-swsh204-promo-englisch/3506282359-234-4236",
  "priceEur": 15,
  "priceCents": 1500,
  "priceType": "FIXED",
  "priceText": "15 €",
  "reserved": false,
  "city": "Leipzig",
  "postalCode": "04179",
  "district": "Altlindenau",
  "country": "Duitsland",
  "sourceCountry": "de",
  "imageUrls": [
    "https://img.kleinanzeigen.de/api/v1/prod-ads/images/37/37fc6d99-2e36-4138-8145-0bfa75b68f22?rule=$_59.AUTO",
    "https://img.kleinanzeigen.de/api/v1/prod-ads/images/6e/6e6c64cf-56bc-4fe9-9038-c038153a5eca?rule=$_59.AUTO"
  ],
  "scrapedAt": "2026-09-07T13:58:04.117Z",
  "date": "2026-09-07",
  "publishedAt": "2026-09-07",
  "searchKeyword": "pokemon karten",
  "categoryId": null,
  "attributes": { "condition": null, "delivery": "Versand möglich" },
  "extendedAttributes": {
    "type": "Sammelkartenspiele",
    "condition": null,
    "properties": "Art: Sammelkartenspiele"
  },
  "descriptionFull": "Pokemon Promo Karte von Arceus V SWSH 204, siehe Bilder. Die Karte ist auf englisch, Boosterfrisch und in einwandfreiem Zustand. Versand als Brief mit Toploader möglich.",
  "descriptionMarkdown": "Pokemon Promo Karte von Arceus V SWSH 204, siehe Bilder. Die Karte ist auf englisch, Boosterfrisch und in einwandfreiem Zustand. Versand als Brief mit Toploader möglich.",
  "viewCount": null,
  "favoriteCount": null,
  "sellerType": "private",
  "shippingAvailable": true,
  "isBuyNow": false,
  "isWanted": false,
  "isTopAd": false,
  "source": "kleinanzeigen.de",
  "contentHash": "8f2c1a9d4e6b0357"
}
```

***

### Examples

**Search a keyword across the whole site:**

```json
{
  "searchQuery": "pokemon karten",
  "maxItems": 200
}
```

**Private sellers only, within a price band:**

```json
{
  "searchQuery": "iphone 15",
  "sellerType": "private",
  "minPrice": 200,
  "maxPrice": 600,
  "maxItems": 300
}
```

**Browse a category in one city, with full detail pages:**

```json
{
  "categoryId": "203",
  "location": "Berlin",
  "fetchDetails": true,
  "maxItems": 100
}
```

**Scrape a search URL you already have** — it is paginated for you:

```json
{
  "startUrls": [
    { "url": "https://www.kleinanzeigen.de/s-pokemon-karten/k0" }
  ],
  "maxItems": 500
}
```

**Daily feed — everything posted today, newest first:**

```json
{
  "searchQuery": "fahrrad",
  "location": "Berlin",
  "daysOld": 1,
  "maxItems": 500
}
```

***

### 💰 Pricing

Two prices, because two different amounts of work.

| You get | Price | Charged when |
|---|---|---|
| **Listing** | **$0.39 per 1,000** | A listing is extracted from search results and saved. |
| **Listing with details** | **$0.99 per 1,000** | The listing's own page was also opened for the full description, exact publish date, condition and complete image gallery. |
| Actor start | $0.05 per 1,000 runs | Once per run. |

At $0.39 per 1,000 this is the lowest per-listing price of any Kleinanzeigen scraper on the Apify Store.

You are charged per listing actually saved. Throttled retries, filtered-out listings and failed
requests are never charged, and a listing whose detail page could not be opened is billed at the
plain listing rate, not the detail rate. Compute and proxy costs are absorbed by Unfenced Group.

| Listings | Basic | With details |
|---|---|---|
| 100 | ~$0.04 | ~$0.10 |
| 1,000 | ~$0.39 | ~$0.99 |
| 10,000 | ~$3.90 | ~$9.90 |
| 100,000 | ~$39.00 | ~$99.00 |

> Flat-rate alternatives typically charge $29–$49/month regardless of usage.

Use the **Maximum results** cap to control your spend exactly. You can also set a maximum cost
for a run in the Apify console — this scraper stops cleanly when it reaches it rather than
running on and producing listings you would not be billed for.

***

### Performance

| Run size | Typical time |
|---|---|
| 100 listings | under 30 seconds |
| 1,000 listings | 2–4 minutes |
| 1,000 listings with `fetchDetails` | 20–30 minutes |

`fetchDetails` opens one extra page per listing, so it is roughly fourteen times more traffic and an order of magnitude slower. Leave it off unless you need the full description or the exact publish date.

***

### Known limitations

- **Roughly 1,250 listings per search.** Kleinanzeigen stops paginating at page 50. For a larger harvest, split the search — by category, by city, or by price band — and run each as a separate job.
- **No radius search.** Kleinanzeigen's robots.txt excludes every radius-filtered URL the site offers, so this scraper does not use them. Search a city, a district or a whole federal state instead.
- **Location is by name, not postcode.** `Berlin`, `Köln`, `Bayern` all work. A postcode in the `location` field does not — though the postcode of every listing is returned in the output.
- **No publish date in some categories.** Property and some vehicle listings carry no date on the results page. `daysOld` cannot filter those from the search page alone; set `fetchDetails: true` to read each listing's exact date. The run tells you when this happens rather than silently returning nothing.
- **No view count.** Kleinanzeigen serves its view counter from an endpoint its robots.txt excludes. `viewCount` is present in the output for schema compatibility and is always `null`.
- **Seller-type filtering needs a scope, and reaches about 135 listings.** Kleinanzeigen does not serve a seller-filtered feed of the whole site, so `sellerType` has to be paired with a search query or a category. Those searches also stop at page 5 — beyond that the only URLs the site offers are ones its robots.txt excludes. Narrow by category, location or price band to reach more. Unfiltered searches are unaffected and run to the full ~1,250.
- **Price and recency are applied to the retrieved listings**, not in the search URL. The results are identical either way — you are just never charged for the difference.

***

### Technical details

- **Source:** kleinanzeigen.de — German classified listings, all categories
- **Coverage:** nationwide, 151 categories, 3,606 named locations
- **Proxy:** none by default. Kleinanzeigen does not block datacenter traffic, it throttles it briefly, and the scraper retries with exponential backoff. A proxy is available as an option but is not needed.
- **Retry:** automatic retry on throttling and network errors, exponential backoff, six attempts per request
- **Compliance:** robots.txt is fetched and honoured on every run. No personal data is collected.

***

### Rate this actor

If this scraper does its job, a short review on the **Reviews** tab helps other users find it. Something not working? Open an issue on the **Issues** tab instead — issues get fixed.

***

### Need a custom scraper?

**[Unfenced Group](https://www.unfencedgroup.nl)** builds Apify actors for any website — for free.

If the site you need isn't in our portfolio yet, just ask. We scope, build, and publish it at no cost to you. You only pay for results — we absorb the compute and proxy costs ourselves. Same pay-per-result pricing, same quality, same standards as every actor in this portfolio.

**Get in touch:** [www.unfencedgroup.nl](https://www.unfencedgroup.nl)

# Actor input Schema

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

Keyword to search for, in German. Example: "pokemon karten" for trading cards, "wohnung mieten" for rental flats. Leave empty to browse a whole category instead.

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

Restrict the search to one kleinanzeigen category. Leave as "All categories" to search the whole site. Combine with a search query to search within a category.

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

German town, city, district or federal state to search in — for example "Berlin", "München", "Nordrhein-Westfalen". Postcodes are not accepted here; use a place name. Leave empty to search all of Germany.

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

Only return listings priced at or above this amount in euros. Listings with no numeric price ("VB" with no figure, or price only in the description) are excluded when this is set.

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

Only return listings priced at or below this amount in euros. Listings with no numeric price are excluded when this is set.

## `daysOld` (type: `integer`):

Only return listings published within this many days. 1 means today only. Leave empty for listings of any age.

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

Filter by who is selling. "private" returns only private sellers, which is where under-priced and one-off items are found; "commercial" returns only dealers and shops; "all" returns both. Applied by kleinanzeigen itself, not after the fact. Requires a search query or a category alongside it, and reaches about 135 listings per search.

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

Stop after this many listings. Set to 0 for no limit. Kleinanzeigen caps any one search at roughly 1,250 listings (50 pages), or about 135 when filtering by seller type.

## `fetchDetails` (type: `boolean`):

Open each listing page to add the full description, the exact publish date, the condition and item-type attributes, all gallery images, and the seller type. Roughly fourteen times slower and fourteen times more traffic per listing.

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

Kleinanzeigen search or category URLs to scrape directly, for example https://www.kleinanzeigen.de/s-pokemon-karten/k0. Each URL is paginated automatically. When set, every filter above except Maximum results is ignored.

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

Optional. This scraper runs without a proxy by default because kleinanzeigen does not block datacenter IPs — it only throttles them, and the scraper retries with backoff. Enable a proxy only if you see persistent throttling.

## Actor input object example

```json
{
  "searchQuery": "pokemon karten",
  "categoryId": "220",
  "location": "Berlin",
  "minPrice": 10,
  "maxPrice": 100,
  "daysOld": 7,
  "sellerType": "private",
  "maxItems": 100,
  "fetchDetails": false,
  "startUrls": [
    {
      "url": "https://www.kleinanzeigen.de/s-pokemon-karten/k0"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "searchQuery": "pokemon karten",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("unfenced-group/kleinanzeigen-classifieds-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 = {
    "searchQuery": "pokemon karten",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("unfenced-group/kleinanzeigen-classifieds-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 '{
  "searchQuery": "pokemon karten",
  "maxItems": 100
}' |
apify call unfenced-group/kleinanzeigen-classifieds-scraper --silent --output-dataset

```

## MCP server setup

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