Kleinanzeigen.de Scraper
Scrape Kleinanzeigen.de as clean JSON: paste your search links or run several searches at once, and get only new listings on a schedule.
Scrape Kleinanzeigen.de as clean JSON: paste your search links or run several searches at once, and get only new listings on a schedule. Prices, specs, locations, images and dates, past the 1,250-result cap. GDPR-clean: no seller names or contact data, ever.
$1.99 / 1,000 · 99.8% success over 1,033 public runs in the last 30 days.
Run it on Apify → Free to try - runs bill per result on your own account.
What you give it
Every field is optional unless marked; sensible defaults do the rest.
| Field | Type | What it does | Default |
|---|---|---|---|
searchQuery |
string | Free-text search, e.g. e-bike. Optional: with no query and no category the run returns the newest listings site-wide. An empty string is not accepted - leave the field out instead. |
e-bike |
searchQueries |
array | Several searches in one run, one per line, e.g. gazelle and cube. Each one uses the filters below (category, location, price, seller type). A listing found by two searches is delivered once. Up to 50. |
- |
startUrls |
array | Set up a search on kleinanzeigen.de with any filters you like (shipping, direct buy, condition, radius...), then paste the address of the results page here. Add as many as you watch, up to 50. When URLs are given, the search fields of this form are ignored and the run status says which ones were. Posted-date window, full descriptions, max items and only-new mode still apply. An ad's own address belongs in listingIds below; another site is refused with the reason. | - |
listingIds |
array | Re-check listings you already know instead of searching: one ad ID per line (the number at the end of every ad address, and the listingId of every dataset item), or the ad's full address. Each one is read from its own page, so it carries the full description, the specs and every photo (imageUrls) whether or not Scrape full descriptions is on. A listing that is gone from the site is skipped, named in the log and not billed. When given, the search fields of this form are ignored and the run status says which. Up to 50. |
[] |
categoryId |
integer | Numeric Kleinanzeigen category ID to scope the crawl, e.g. 217 for Fahrräder. Category IDs appear in the site's URLs as c217. Optional. |
- |
location |
string | German city or region to search in, e.g. "Berlin" or "München" - resolved via the site's own location search. Combine with radiusKm for a radius search. | - |
radiusKm |
integer | Only return listings within this many km of the location. Requires a location - a radius on its own fails the run, because there is nothing to measure from. | - |
priceMinEur |
integer | Only return listings priced at or above this amount. Must not be higher than the maximum. Optional. | - |
priceMaxEur |
integer | Only return listings priced at or below this amount. Optional. | - |
sortBy |
string | Newest first is the default and the right choice for monitoring; price ascending surfaces the cheapest offers first. | date |
postedAfter |
string | Only keep listings posted on or after this date. Listings whose posting date cannot be read are excluded when a window is set. Format: YYYY-MM-DD (for example 2026-09-08) or a full ISO timestamp such as 2026-09-08T14:30:00Z. Slash dates like 08/09/2026 are refused on purpose: they are read as September in Europe and August in the United States, and this actor will not guess which you meant. |
- |
postedBefore |
string | Only keep listings posted on or before this date. Format: YYYY-MM-DD (for example 2026-09-08) or a full ISO timestamp such as 2026-09-08T14:30:00Z. Slash dates like 08/09/2026 are refused on purpose: they are read as September in Europe and August in the United States, and this actor will not guess which you meant. |
- |
sellerType |
string | Only private sellers, only business sellers, or both. | any |
scrapeDetails |
boolean | Fetch each listing's detail page for the full description, the category specs (condition, brand, car mileage, property size, ...) and every photo in its gallery (imageUrls; the search page shows one photo per ad). One extra request per listing, so noticeably slower — but much richer output. |
False |
maxItems |
integer | Stop after this many listings, across all searches of the run. With several searches, each gets an equal share of what is left. | 1000 |
onlyNewListings |
boolean | For scheduled runs: return only listings this search has not delivered before. The first run returns the usual results and remembers them; later runs skip them, and skipped listings are not charged. The memory is kept per search (and per task) in a key-value store named kleinanzeigen-scraper-seen-listings in your own account, for 90 days. Changing a search's filters starts a fresh memory. |
False |
resetState |
boolean | With only-new mode or a watch: forget what was delivered or watched, return the full results (or record a fresh baseline) once and remember again. | False |
reportFailures |
boolean | When a run fails, send the developer the actor name and build, an error category, the error message (truncated) and a one-way hash of your input - so a bug can be fixed without anyone asking you to reproduce it. Your input itself, your results and your identity are never sent, and successful runs send nothing at all. Switch this off and the actor behaves exactly the same. | True |
What you get back
One JSON object per result, with exactly these fields - no seller identities, no contact data, ever.
A real result row from a recent run:
{
"adType": "offer",
"attributes": {},
"description": "Verkaufe gebrauchtes Gazelle-Fahrrad in gutem Zustand. Alle Zahnräder funktionieren, kommt mit Kette.",
"imageUrl": "https://img.kleinanzeigen.de/api/v1/prod-ads/images/5b/5bd6b7cc-1f33-4b94-a94b-eec32a6558ad?rule=$_2.AUTO",
"listingId": "3542105483",
"location": "10247 Friedrichshain",
"postedAt": "Heute, 06:57",
"postedDate": "2026-10-16",
"priceCents": 7000,
"priceType": "FIXED",
"shippingPossible": true,
"title": "Gazelle Fahrrad L mit Gangschaltung",
"url": "https://www.kleinanzeigen.de/s-anzeige/gazelle-fahrrad-l-mit-gangschaltung/3542105483-217-3353"
}
| Field | Type | Meaning |
|---|---|---|
listingId |
string | Kleinanzeigen ad ID. |
title |
string | Listing title as posted. |
description |
string | Listing description: the search snippet by default, the full text when scrapeDetails is enabled. |
priceCents |
integer | Asking price in euro cents. 0 for giveaways ('Zu verschenken'); absent when the listing shows no amount. |
priceType |
string | FIXED for a plain price, NEGOTIABLE when marked 'VB' (Verhandlungsbasis), GIVEAWAY for 'Zu verschenken'. |
location |
string | Area-level location as the marketplace displays it: postcode and district, not a seller address. |
postedAt |
string | Posting date as displayed: a date, or a relative label like 'Heute, 09:12' (today) or 'Gestern' (yesterday). |
imageUrl |
string | URL of the listing's first image, when present. |
imageUrls |
array | Every photo in the listing's gallery, large size, in the site's order. Filled with scrapeDetails or for listings requested through listingIds; the search page alone carries one photo (imageUrl). |
url |
string | Direct link to the listing. |
adType |
string | 'offer' for items for sale; 'wanted' for Gesuch ads (someone searching, not selling) — exclude those from price analysis. |
shippingPossible |
boolean | Whether the listing is tagged 'Versand möglich' (shipping available). |
attributes |
object | Whitelisted, non-personal listing specs from the detail page (requires scrapeDetails): condition, brand, color, size for goods; mileage, firstRegistration, fuel, transmission, power for cars; livingArea, rooms for property — when the listing has them. |
sellerType |
string | Whether the ad comes from a private or business seller (detected with scrapeDetails, or implied by the sellerType input filter). The only seller-related field in the output. |
postedDate |
string | Posting date normalized to YYYY-MM-DD (from the site's display date). |
status |
string | The site's own state of the ad, present once its page was read (listingIds, or scrapeDetails on): active, reserved (the "Reserviert" veil a seller puts on an ad; it is still on the site and comes back as a normal row), or another state the site raises. Deleted and expired ads are not delivered at all - a lookup skips them as gone. |
Health
99.8% success over 1,033 public runs in the last 30 days. Live record, failures included: status page.
Full documentation, examples and the AI-assistant prompt live on the store page.
Questions
Is scraping Kleinanzeigen legal?
This is not legal advice. The actor reads what any logged-out visitor sees on kleinanzeigen.de, with no login, no CAPTCHA solving and no private endpoints, and it extracts no seller name, contact detail or profile, so the output holds no personal data. Whether your own use of the listings is allowed under the site's terms and your jurisdiction's rules is yours to assess.
Can I get only new listings?
Yes. Switch on onlyNewListings and every scheduled run delivers only the listings it has not delivered before, which is what an hourly watch needs. The first run returns the full result set as a baseline, and resetState starts the memory over.
How much do 10,000 listings cost?
$19.90, billed per delivered listing at $1.99 per 1,000. That price covers the run's platform usage, and a run that fails or returns nothing bills nothing.
Does it return seller phone numbers?
No. The only seller field is whether the seller is a business or a private person. Names, phone numbers, profiles and exact addresses are never extracted, and a test on every build fails if one ever appears, so this is not a setting that can be switched off.
Can I re-check listings I already have?
Yes. Put their ids or addresses into listingIds and each one is read from its own page with its full description, specs and photos, plus the site's own state of the ad: active or reserved. A deleted or expired ad is skipped, named in the log and never billed.
What happens to VB and Zu verschenken prices?
They become machine-readable price types: a VB price is marked NEGOTIABLE and a giveaway GIVEAWAY, so a price analysis never chokes on German price idioms. Wanted ads carry adType wanted so they can be filtered out with one condition.