# Kleinanzeigen Scraper - Kleinanzeigen.de Ads, All Categories (`amitaviv/kleinanzeigen-scraper`) Actor

Scrape Kleinanzeigen.de ads in any category from a search URL or by keyword, place, category, price and seller. One record per ad: price and price type, place, date, description, images, attributes, shipping, seller type. Past the 1,250-ad limit. New-ads monitoring. $0.50 per 1,000 ads.

- **URL**: https://apify.com/amitaviv/kleinanzeigen-scraper.md
- **Developed by:** [Amit Aviv](https://apify.com/amitaviv) (community)
- **Categories:** E-commerce, Real estate, Automation
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 ads

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

## Kleinanzeigen Scraper (kleinanzeigen.de)

Returns ads from Kleinanzeigen.de, Germany's largest classifieds site, in any category, from search URLs you copy out of the browser or from keyword, place, category, price and seller fields. Plain HTTP with no browser, so 100 ads usually take about 5 seconds; apart from the start fee you pay only for delivered ads, and a run that delivers nothing because of an error ends as Failed, never as a green empty run.

### What you get

- Title, price, price type (`fixed`, `negotiable` for "VB", `free` for "Zu verschenken"), the price as shown, the crossed-out old price
- Postcode, place, district or region, posting date (and time for ads posted today or yesterday)
- Offer or wanted ad (Gesuch), category id; with ad pages also the category and parent category names
- Shipping possible ("Versand möglich"; "pickup only" needs ad pages), "Direkt kaufen", promoted (TOP) flag, image count and the first image in large size
- Seller type `private` / `commercial`; for commercial sellers with a Kleinanzeigen shop, the shop name and shop URL (with ad pages, every commercial seller's account name)
- With **Ad pages** on: the full description, all image URLs, every attribute the ad page lists (condition, type, size, living space, rooms, mileage, …) under `attributes` in the site's own German labels, the feature checklist (balcony, fitted kitchen, …), the seller type for every ad, and for commercial sellers the account name, account id, "active since" date and map position
- Automatic splitting past the site's limit of 1,250 ads per search (see "Large searches")
- A monitoring mode that delivers and charges only ads earlier runs have not delivered
- One record per ad, as JSON, CSV or Excel, or through the API
- A run summary (`OUTPUT_SUMMARY` in the run's key-value store): what was requested, delivered and charged; per search what the site reports, how many parts it was read in and how many distinct ads were found; which inputs failed or were ignored; why the run stopped

What it does not return: private sellers' names, user ids, membership dates and map positions, and in person-centred categories (babysitting, tutoring, services, jobs …) private persons' descriptions and photos (unless you opt in, see "Legal and responsible use"); phone numbers or e-mail addresses as fields (the site shows them only after login); inside a private seller's description they are replaced by `[removed]`, while a commercial seller's description is delivered as written, including any contact details the business put there; view counts; anything behind a login, such as messages or phone numbers the site shows only to logged-in users.

### How to use

1. Open kleinanzeigen.de, make the search you want (category, place, radius, price, seller type, category filters such as make or size) and copy the URL from the browser.
2. Paste it into **Search or ad URLs**. Several entries are fine. Or leave it empty and use **Keywords**, **Place**, **Category**, **Price** and **Seller**.
3. Set **Max ads per search** and press Start.
4. Download the results from the Output tab, or read them from the API.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `startUrls` | list of text | none | Search URLs (`kleinanzeigen.de/s-…`) or ad URLs (`kleinanzeigen.de/s-anzeige/…`). The URL's filters and sort order are applied as they are; a page number in it is not (every search is read from page 1). A price filter whose lower price is above its upper price is ignored and listed in the summary. URLs without `https://` and old `ebay-kleinanzeigen.de` URLs are accepted; duplicates are ignored; entries from other sites are ignored and listed in the summary. An ad URL returns that ad from its ad page (charged as ad + ad page). |
| `keywords` | list of text | none | One search per keyword, combined with the fields below. Up to 100 characters (longer ones are shortened, with a warning); `%`, `#`, `?` and `\` are left out. The site cannot search for the single word "anzeige" or "anzeigen": such an entry is ignored and listed in the summary. |
| `location` | text | none | A city, district or postcode as you would type it on the site. The site's own place lookup is used and its first match taken; a place it does not know fails that search with a message. |
| `radiusKm` | choice | only this place | 0, 5, 10, 20, 30, 50, 100, 150 or 200 km around the place; any other value fails the run before any request. |
| `category` | choice | all | One of 154 categories: the site's 15 main categories and their sub-categories. Alone (no keyword, no place) it reads that category in all of Germany. An id not in the list fails the run before any request: for other categories, paste the site's URL. |
| `priceMin`, `priceMax` | number | none | Whole euros. A minimum above the maximum fails the run before any request. |
| `sellerType` | choice | all | The site's own private / commercial filter, for keyword and field searches (a URL keeps its own). |
| `maxItemsPerQuery` | number | 100 | Stop after this many ads for each URL or keyword, 1 to 300,000 (a value outside is read as the nearest one, with a warning). |
| `splitLargeSearches` | yes/no | yes | Read searches with more than 1,250 ads in parts (see "Large searches"). Applies only when the maximum is above 1,250. |
| `includeDetails` | yes/no | no | Complete every delivered ad from its ad page (one extra request and one extra fee per ad). |
| `includePrivateSellerData` | yes/no | no | See "Legal and responsible use". |
| `onlyNew` | yes/no | no | Monitoring: return and charge only ads that earlier runs have not delivered. See "Monitoring". |
| `monitorKey` | text | empty | Name of the monitor memory, to keep two schedules apart. |
| `proxyConfiguration` | proxy | off | Not needed in our tests. Turn on Apify Proxy only if a run reports blocking. |

```json
{
  "keywords": ["e-bike"],
  "location": "Hamburg",
  "radiusKm": "10",
  "category": "217",
  "priceMin": 200,
  "maxItemsPerQuery": 100
}
```

This input was run as `u2fP1QVd2T88Gc6Sm` on 2026-10-14 (build 0.1.9): 100 e-bike ads priced 200 EUR or more within 10 km of Hamburg (the site reported 580), in 3.5 seconds, 100 ads charged.

### Example result

From run `JaadZfz6XVHouiEK4` (2026-10-14, Leipzig rental flats with ad pages on). The description and the image list are shortened here; nothing else is edited.

```json
{
  "id": "3533164466",
  "url": "https://www.kleinanzeigen.de/s-anzeige/-exklusive-3-raum-wohnung-inkl-ebk-balkon-/3533164466-203-30065",
  "title": "*Exklusive 3-Raum-Wohnung inkl. EBK & Balkon!*",
  "price": 1699,
  "priceType": "fixed",
  "priceText": "1.699 €",
  "oldPrice": null,
  "currency": "EUR",
  "description": "Entdecken Sie Ihre neue Etagenwohnung zur Miete im Herzen von Leipzig! Diese charmante Immobilie bietet modernen Wohnkomfort und eine ideale Lage, um das lebendige Stadtleben zu genießen.\n\nDiese Wohnung überzeugt nicht nur durch ihre attrak …",
  "postcode": "04107",
  "location": "Leipzig, Zentrum-Süd",
  "region": "Leipzig",
  "postedDate": "2026-10-06",
  "postedTime": null,
  "adType": "offer",
  "categoryId": 203,
  "category": "Mietwohnungen",
  "parentCategory": "Immobilien",
  "highlights": ["126 m²", "3 Zi."],
  "attributes": {
    "Wohnfläche": "126 m²",
    "Zimmer": "3",
    "Schlafzimmer": "2",
    "Badezimmer": "1",
    "Etage": "1",
    "Wohnungstyp": "Etagenwohnung",
    "Nebenkosten": "190 €",
    "Heizkosten": "190 €",
    "Warmmiete": "2.079 €"
  },
  "features": ["Balkon", "Einbauküche", "Badewanne", "Haustiere erlaubt"],
  "shippingPossible": null,
  "buyNowPossible": false,
  "isTopAd": true,
  "imageCount": 12,
  "imageUrl": "https://img.kleinanzeigen.de/api/v1/prod-ads/images/0f/0fa4e0aa-b2d4-42b2-a507-dada5cb7982d?rule=$_59.AUTO",
  "images": [
    "https://img.kleinanzeigen.de/api/v1/prod-ads/images/0f/0fa4e0aa-b2d4-42b2-a507-dada5cb7982d?rule=$_59.AUTO",
    "https://img.kleinanzeigen.de/api/v1/prod-ads/images/f4/f4a96d54-fd6f-4299-893a-ac9a516555f1?rule=$_59.AUTO",
    "…"
  ],
  "sellerType": "commercial",
  "shopName": "ARGO Residential GmbH & Co. KG",
  "shopUrl": "https://www.kleinanzeigen.de/pro/ARGO-Residential-GmbH-Co-KG",
  "sellerName": "ARGO Residential GmbH & Co. KG - Team Leipzig",
  "sellerId": "76855088",
  "sellerSince": "2020-07-23",
  "latitude": 51.3257394,
  "longitude": 12.3789294,
  "detailsFetched": true,
  "privateDataRedacted": false,
  "searchUrl": "https://www.kleinanzeigen.de/s-wohnung-mieten/leipzig/c203l4233",
  "scrapedAt": "2026-10-14T14:30:13.635Z"
}
```

| Field | Meaning |
|---|---|
| `id` | The site's ad id; stable between runs. |
| `price`, `priceType`, `priceText` | Price in EUR (`null` for "VB" without a figure), `fixed` / `negotiable` / `free`, and the text as shown. |
| `postedDate`, `postedTime` | German local date; the time is shown by the site only for "Heute" and "Gestern". Promoted (TOP) ads show no date on the result list, so without ad pages their `postedDate` is `null`. |
| `highlights` | Short facts the result card shows (size and rooms in property categories, other badges). |
| `attributes`, `features`, `images`, `category` | From the ad page; `null` without ad pages. |
| `shippingPossible` | `true` for "Versand möglich". The result list never shows "Nur Abholung", so without ad pages the value is `true` or `null`; `false` (pickup only) comes from the ad page. |
| `isTopAd` | A promoted ad. The site shows promoted ads at the top of every page; each is delivered once. |
| `sellerType` | `private` or `commercial`. Without ad pages it is known where the result card shows it (a shop link, or "Von Privat" in some categories) or where the search filters the seller type; otherwise `null`. With ad pages, every ad has it. |
| `sellerName`, `sellerId`, `sellerSince`, `latitude`, `longitude` | Ad pages only. For private sellers `null` unless you opt in. |
| `detailsFetched` | Whether the ad page was read (an ad removed between the result page and the ad page keeps its list data, `false`, and is not charged the ad-page fee). |
| `privateDataRedacted` | `true` when private-seller fields were left out (see "Legal and responsible use"). |

Without ad pages, `description` is the short text the result card carries (up to about 250 characters). In person-centred categories, `description`, `imageUrl` and `images` of private sellers' ads are `null` (`images`: empty) unless you opt in. Fields the site does not provide for a given ad are `null`, never missing.

### Pricing

Pay per event. You pay for what is delivered, not for time or memory.

| Event | Free plan | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Actor start (per run, per GB of memory; default 512 MB = once) | $0.0036 | $0.003 | $0.0027 | $0.0024 |
| Ad delivered | $0.0006 | $0.0005 | $0.00045 | $0.0004 |
| Ad page read (only with **Ad pages** on, or for an ad URL) | $0.0006 | $0.0005 | $0.00045 | $0.0004 |

Worked examples on Bronze:

- 1 search, 1,000 ads without ad pages: 1,000 × $0.0005 + $0.003 = **$0.503**.

- The same with ad pages: 1,000 × ($0.0005 + $0.0005) + $0.003 = **$1.003**.

- An hourly monitoring run that finds 3 new ads: 3 × $0.0005 + $0.003 = $0.0045; a run with nothing new costs the $0.003 start fee only.

- Ads that could not be delivered are not charged. An ad found by two searches of the same run is delivered and charged once.

- The maximum total charge you set for a run is respected: the actor stops before it would go over, keeps what was delivered, and says so in the status message (run `gcr4eEdULu2cpWcaz`: limit $0.008 = start fee + 10 ads, 10 ads delivered and charged, Succeeded).

### Large searches: past the 1,250-ad limit

Kleinanzeigen shows at most 50 pages of 25 ads for any search (page 51 and later show page 50 again). When **Max ads per search** is above 1,250 and the site reports more ads than that, the actor reads the search in parts that each stay under the limit: first private and commercial sellers apart, then price bands, halved until each part fits. Every ad is delivered and charged once; the run summary lists how many parts were read and how many distinct ads were found against the number the site reports.

The site's newest-first order is not stable while it is read: ads posted in the same minute (an agency's bulk upload, for example) change places between two page requests, so a whole reading can repeat some ads and miss others. A part (or a whole search of up to 1,250 ads) that comes up short of the site's count is therefore read once more, ordered by price; ads met twice are delivered and charged once.

Measured on 2026-10-14:

- Leipzig rental flats, whole search, 1,679 reported: **1,679 delivered** in 2.6 minutes, read by seller type, both parts read twice (`0LYlgczakM8YhgM3U`). The same search with one reading had found 1,645 (`zYcQdhzEWELaUYH4t`, earlier build). Again with build 0.1.9: 1,682 of 1,682 (`0BCVBV32ZSWek4F3u`, "read in 3 parts (seller type)").
- Hamburg game consoles, whole search, 3,330 reported: 3,215 delivered in 15 parts (seller type, price bands); the 115 missing are ads without a price figure (`arrYiKfmLWynD7kav`).
- Berlin rental flats, whole search, 7,139 reported: 7,022 delivered in 25 parts, 6.5 minutes, one reading (`tffJ9RL9y5oT3kBwC`, earlier build without the second reading; not re-run).
- Munich used cars, 9,560 reported, maximum 5,000: 5,000 delivered in 21 parts, 4 minutes (`eHRmYtkVMfX8bmcFk`).

Ads without a price figure (for example "VB" alone) are in no price band, so a search split by price finds only those of them that were on the first pages read before the split. They were 2-4% of all ads in our tests (Berlin bikes 858 of 38,085, 2.3%; Hamburg consoles 115 of 3,330, 3.5%); the status message says so when it happens. A search split only by seller type loses none. With splitting off, or with a maximum of 1,250 or less, a search is read to page 50 at most.

### Reliability and failure behaviour

| What happened | Run status | Status message (run id where it comes from a real run; the others were produced in offline simulations) |
|---|---|---|
| Ads delivered | Succeeded | `Scraped 100 ads from 1 query` (`AYIdTjIRkdIkggdko`) |
| The site has no ads for the search | Succeeded | `0 results: Kleinanzeigen has no ads for this query` (`JGpcOQ4myv047OaFS`) |
| Some entries worked, some failed | Succeeded | `Scraped 120 ads from 2 queries — 1 of 2 queries failed ("…": …)` (simulated) |
| Nothing delivered because of errors or blocking | **Failed** | `No ads delivered: Kleinanzeigen blocked every attempt; try again later. No ads were charged (the start fee applies).` (simulated) |
| Input the actor cannot use | **Failed**, in under 2 seconds | `Nothing to do: the input has no "startUrls". …` (`qaBwZVJ3DWmmEdS68`); `… not a kleinanzeigen.de / ebay-kleinanzeigen.de URL …` (`xr1Wxti10Vp3uREXj`) |
| Maximum charge below one ad | **Failed**, before any request | `The maximum charge set for this run ($0.0032) is below the price of one ad …` (`l5jxqgX2jvGJhludL`) |
| Maximum charge reached | Succeeded | `Scraped 10 ads from 1 query — stopped at the maximum charge set for this run` (`gcr4eEdULu2cpWcaz`) |
| Run timeout close | Succeeded | `… — stopped just before the run timeout; raise the timeout to get the rest` (simulated) |
| Some entries ignored | Succeeded | `Scraped 20 ads from 2 queries — 1 input entry ignored (see OUTPUT_SUMMARY)` (`Pf8tKvsrXz78CbHs0`: the keyword "anzeigen") |

- Requests are retried with increasing pauses: on network errors, HTTP 429, 401, 403 or a challenge page 4 times without a proxy (pauses from 5 s) and 5 times with one (each from a new proxy session), on HTTP 5xx 3 times. Result pages are requested at most two per second per run.
- Results are saved page by page. A run that is aborted and resurrected keeps what was delivered, does not deliver or charge the same ad twice, and counts what it delivered before the restart against the maximum (`YGopf3Xsu3pBbEHTm`, build 0.1.9: aborted at 54 ads, resurrected, 400 ads for a maximum of 400, 400 unique, 400 charged).
- In 37 test runs on 2026-10-14 from Apify's servers without a proxy (about 3,500 requests counted in the run summaries, up to 1,040 in one run) the site never refused a request: 0 blocks, and 1 retry in all. Behaviour under a real block has been tested offline only.

### Limits

- At most 1,250 ads per search unless the search is split (see above); a search split by price misses 2-4% (ads without a price figure).
- Without ad pages: `description` is the card's short text (up to about 250 characters), `sellerType` is often `null` outside property categories (60 of 100 e-bike ads in `AYIdTjIRkdIkggdko`), and `attributes`, `features`, `images` and `category` are `null`.
- Speed: about 20 ads a second without ad pages (5,000 in 243 s; a whole search read twice about 11 a second); about 3.5 ads a second with ad pages (1,000 in 294 s at the default 512 MB).
- Germany only (kleinanzeigen.de).

### Monitoring: only new ads

1. Turn on **Only new ads** and save the input as a task.
2. Schedule the task (hourly or daily).
3. The first run delivers the newest ads up to the maximum. Every later run reads the search newest first, delivers and charges only ads it has not delivered before for the same search, and stops at the first page on which most ads are known. A run with nothing new ends as Succeeded with `0 new ads…` and charges only the start fee.

Measured on Hamburg bikes (21,496 ads): first run 50 ads (`stSffumwS64bOYqfc`); 90 seconds later 1 ad, posted in between and not in the first run (`XW6WelX0IvMf7QEF1`, 1 page read); right after that `0 new ads in 1 monitored query` (`IqUzerftdrj7BHO15`, 1 page read, 0 ads charged).

Promoted (TOP) ads are skipped in this mode: they are older ads shown on top of every page, and each is also listed at its own date among the ordinary ads. An old ad that its seller renews comes back to the top; if no earlier run delivered it, it is delivered as new. In this mode a sort order in the URL is not applied and large searches are not split. Set the maximum above the number of new ads you expect between two runs.

The memory is a key-value store named `kleinanzeigen-scraper-monitor` in your own account (one record per search and monitor name, at most 10,000 ids each, oldest forgotten first). Delete the store or change **Monitor name** to start over. To be notified, add an integration to the task (email, Slack, webhook) on "run succeeded".

### FAQ

**Do I need a proxy?** Not in our tests: every request from Apify's servers was answered without a proxy. If a run reports blocking, turn on Apify Proxy.

**Why did I get fewer ads than the site shows?** The site shows at most 1,250 per search; raise the maximum above 1,250 and keep "Split large searches" on. The run summary says what the site reported and how many distinct ads were found.

**Can I scrape a single ad?** Yes: paste its URL. It is read from the ad page and charged as ad + ad page.

**Can I run it from code?** Yes: the API, the Apify clients for JavaScript and Python, Make, Zapier, n8n. The Output tab shows the URLs.

**What happens when the site changes?** A page that is not a result list fails that search with a message instead of returning empty data. Report the run id under Issues.

### Legal and responsible use

This actor reads what Kleinanzeigen shows publicly without a login. Many ads are posted by private persons. By default it does not deliver a private seller's name, user id, membership date or map position, and phone numbers and e-mail addresses in a private seller's description are replaced by `[removed]`; such records carry `privateDataRedacted: true`. A commercial seller's description is delivered as written, including any phone number or e-mail address the business put there. Ads whose seller type is unknown are treated as private.

In categories where a private person's ad is about that person (babysitting and childcare, elderly care, tutoring and courses, services, neighbourly help, jobs, pet sitting, musicians and artists, flat shares) the description and the photos of private sellers' ads are left out as well: there people describe themselves, often with first name and age (minors among them), and photos often show them. Title, price, place, date and category are delivered; a title is delivered as the person wrote it and can mention an age or a first name (for example "Schülerin (16) bietet …"). For commercial sellers the business name, shop, account name (which can include a contact person's name, as the business published it) and position are delivered.

The option **Include private sellers' data** delivers all of this as the site shows it. Turn it on only if you have a lawful basis under the GDPR (Art. 6) to process private persons' personal data, and use the data only for that purpose; by turning it on you confirm this.

Kleinanzeigen's terms do not allow automated collection, and its ads and photos may be protected by copyright and database rights. You are responsible for how you use the data: respect the site's terms, copyright and database rights, and data-protection law. Do not re-publish ads or photos, do not build a competing classifieds database from the output, and do not use it to contact sellers for unsolicited marketing. If you are unsure, ask a lawyer before you build on it.

### Changelog

- 2026-10-14 0.1: first release: searches by URL or by fields, ad pages, splitting past 1,250 ads, monitoring.

### Related actors

- [Property Listing Status Checker](https://apify.com/amitaviv/property-listing-status-checker): paste Kleinanzeigen ad URLs you already have and learn which are still online, sold, paused or removed, and whose price changed.
- [Vinted Scraper](https://apify.com/amitaviv/vinted-scraper): second-hand fashion and goods from vinted.de and Vinted's other country sites, with an only-new mode for resellers who also watch Kleinanzeigen.
- [Leboncoin Scraper](https://apify.com/amitaviv/leboncoin-scraper): France's largest classifieds site, all categories, for the same kind of price research or monitoring in France.
- [ImmoScout24 Scraper](https://apify.com/amitaviv/immoscout24-scraper) and [Immowelt Scraper](https://apify.com/amitaviv/immowelt-scraper): Germany's two large property portals, for agency listings with cold and warm rent, energy data and coordinates next to the private property ads found here.

### Support

Open an issue on the actor's **Issues** tab with the run id.

# Actor input Schema

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

Kleinanzeigen search URLs or ad URLs copied from the browser's address bar, e.g. https://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331 (bikes in Berlin). Each search URL is one search; several entries are fine. Make the search on kleinanzeigen.de (any category, place, radius, price, seller type and category filters) and paste its URL. The URL's filters and sort order are applied as they are; its page number is not (every search is read from page 1). URLs without https:// and old ebay-kleinanzeigen.de URLs are accepted. An ad URL (…/s-anzeige/…) returns that ad from its ad page (charged as ad + ad page). Default: empty. Leave empty to search by the keyword, place and category fields instead; both can be used in one run.

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

Search words, one search per entry, e.g. \["e-bike", "iphone 15"]. Each is combined with the place, radius, category, price and seller fields below. Up to 100 characters; % # ? and \ are left out. The site cannot search for the single word "anzeige" or "anzeigen". Default: empty; with no keyword, the place and category fields alone make one search.

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

A German city, district or postcode as you would type it on the site, e.g. München, Berlin Kreuzberg or 10115. The site's own place lookup is used and its first match is taken; a place it does not know fails that search with a message. Applies to keyword and field searches, not to pasted URLs. Default: empty (all of Germany).

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

Radius around the place in kilometres, as text: "0" (only this place, default), "5", "10", "20", "30", "50", "100", "150" or "200". Only with a place.

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

Kleinanzeigen category id as text, sub-categories included, e.g. "217" (Fahrräder & Zubehör), "203" (Mietwohnungen) or "173" (Smartphones); "" (default) for all categories. Alone (no keyword, no place) it reads the whole category in all of Germany. For a category not in this list, make the search on kleinanzeigen.de and paste its URL.

## `priceMin` (type: `integer`):

Lowest price in whole euros, e.g. 200. Applies to keyword and field searches. The site leaves out ads without a price when a price filter is set. Default: no minimum.

## `priceMax` (type: `integer`):

Highest price in whole euros, e.g. 1500. Applies to keyword and field searches. Default: no maximum. A value below priceMin fails the run before any request.

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

The site's own seller filter for keyword and field searches (a pasted URL keeps its own): all (default), private (private sellers only) or commercial (commercial sellers only).

## `maxItemsPerQuery` (type: `integer`):

Maximum number of ads delivered for each search (each URL and each keyword), from 1 to 300,000; default 100. Apart from the start fee you pay only per delivered ad, so this also caps the cost. Kleinanzeigen shows at most 1,250 ads per search; set this higher to have a larger search read in parts (see splitLargeSearches).

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

Only matters when maxItemsPerQuery is above 1,250. On (default): when the site has more ads than 1,250, the search is read in parts (private and commercial sellers, then price bands) that each stay under the site's limit; every ad is delivered and charged once. Ads without a price figure ("VB" only) are in no price band, so a search split by price misses those not met before the split: 2-4% of all ads in our tests. Off: at most 1,250 ads per search. The run summary says how many distinct ads were found against what the site reports.

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

Off (default): what the result list shows (title, price, place, date, short description, first image, shipping flag, seller type where shown). On: each delivered ad is completed from its ad page: full description, all images, attributes (condition, size, rooms, mileage …), features, category names, private or commercial seller for every ad, account name of commercial sellers (and their shop, where they have one). One extra request per ad and an extra ad-page fee per ad (see Pricing).

## `includePrivateSellerData` (type: `boolean`):

Off (default): for private sellers (and ads whose seller type is unknown) the seller's name, user id, membership date and map position are null, and phone numbers and e-mail addresses in the description are replaced by \[removed] (privateDataRedacted: true). In categories where a private ad is about the person (babysitting, care, tutoring and courses, services, neighbourly help, jobs, pet sitting, musicians, flat shares) the description and the photos are left out too. On: all of it is delivered as the site shows it. Turn this on only if you have a lawful basis under the GDPR (Art. 6) to process private persons' personal data, and use it only for that purpose; by turning it on you confirm this.

## `onlyNew` (type: `boolean`):

Off (default): every run delivers the ads it finds. On: return and charge only ads that earlier runs of this actor in your account have not delivered for the same search, for scheduled monitoring. Searches are then read newest first (a sort order in the URL is not applied, and large searches are not split); promoted TOP ads are skipped, since each is also listed at its own date. The first run delivers the newest ads up to the maximum; later runs stop once a page is mostly known, so set maxItemsPerQuery above the number of new ads you expect between two runs. The memory is a key-value store named kleinanzeigen-scraper-monitor in your account; delete it to start over.

## `monitorKey` (type: `string`):

Only with onlyNew. A free name for the monitor memory, e.g. hamburg-bikes. Runs with the same search and the same monitor name share one memory; give two schedules different names to keep their memories apart. Default: empty (one shared memory per search).

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

Default and recommended: no proxy. In our tests the site answered every request from Apify's own addresses. If a run reports that it was blocked, switch on Apify Proxy; each retry then goes out from a different address.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331"
  ],
  "radiusKm": "0",
  "category": "",
  "sellerType": "all",
  "maxItemsPerQuery": 100,
  "splitLargeSearches": true,
  "includeDetails": false,
  "includePrivateSellerData": false,
  "onlyNew": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All delivered ads as JSON, one object per ad. Main fields: id, url, title, price (EUR), priceType (fixed, negotiable or free), priceText, oldPrice, description, postcode, location, region, postedDate, postedTime, adType (offer or wanted), categoryId, category, highlights, attributes, features, shippingPossible, isTopAd, imageUrl, images, imageCount, sellerType (private or commercial), shopName, shopUrl, sellerName, detailsFetched, privateDataRedacted, searchUrl, scrapedAt. A value the site does not give is null.

## `resultsCsv` (type: `string`):

All delivered ads as a CSV file, one row per ad, with the same fields as the JSON output (lists and the attributes object are flattened into columns).

## `summary` (type: `string`):

JSON record OUTPUT_SUMMARY: what was requested, delivered and charged; per search what the site reports, how many parts it was read in and how many distinct ads were found; which inputs failed or were ignored and why; warnings; why the run stopped.

# 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": [
        "https://www.kleinanzeigen.de/s-fahrraeder/berlin/c217l3331"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

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

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

```

## MCP server setup

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