Kleinanzeigen.de Scraper
Pricing
from $1.59 / 1,000 results
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. Prices, specs, locations, images and dates, past the 1,250-result cap. GDPR-clean: no seller names or contact data, ever.
Pricing
from $1.59 / 1,000 results
Rating
0.0
(0)
Developer
Lowland Data
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
3 days ago
Last modified
Categories
Share
Kleinanzeigen.de is where Germany's second-hand market actually happens, and the site shows it one page at a time. If you want to know what a used e-bike really sells for, or how many BMW 3ers sit in your price band this week, the search box is the wrong tool. You end up scrolling and copying by hand.
This turns any Kleinanzeigen search into a table: price, whether it is a VB asking price, locality, photos, posting date, shipping flag, one row per ad, plus the full ad text and spec fields if you switch on detail enrichment. Seller names, IDs and profile links are never collected.
Live health record: lowlanddata.com/status/kleinanzeigen-scraper - 30-day success rate and daily canary results, failures included. Full input/output reference: tool page.
No seller personal data, ever. This scraper is built GDPR-first: seller names, IDs, phone numbers and profile links never appear in the output, not as an option you have to remember to switch off, but by design. The only seller information included is whether the ad comes from a business or a private seller.
Quick start (30 seconds)
- Put what you'd type in the Kleinanzeigen search box into searchQuery, e.g.
e-bike. - Click Start. That's the whole minimum setup.
- When the run finishes, open the dataset's Overview tab for a clean table, or Export it as CSV/Excel/JSON.
Everything else (price range, category, seller type, full-description enrichment) is an optional refinement, explained in the Input table below. To make it run by itself, create a Schedule in the Apify Console with the same input and add an email or Slack integration on the runs.
Already have your search set up on kleinanzeigen.de? Paste the address of the results page into startUrls instead, with every filter you picked on the site (shipping, direct buy, condition...). Paste several to watch several searches in one run, and switch on onlyNewListings so each scheduled run returns only the ads you have not received yet.
What you can build with it
- Catch underpriced deals the minute they post. Sort by date, watch a category, and every new ad arrives parsed (price, negotiability and shipping flag included) while the deal is still live.
- Price a used car with real market data. Pull every BMW 3er in your price band with full specs (
mileage,firstRegistration,fuel,transmission) and build the price-vs-mileage curve that tells you what a fair offer is. - Track a market week over week. Snapshot "E-Bikes unter 1.500 €" on a schedule and watch supply, median asking price and negotiation room (
NEGOTIABLEshare) shift over time. - Feed an AI agent clean data. Structured, predictable fields with zero personal data: an assistant or pipeline can store and process it without a compliance review first.
What you get
Each listing is one dataset item:
{"listingId": "3255625724","title": "KTM Macina Style 710 E-Bike Damen Trekking","description": "Sehr gut erhaltenes E-Bike, Akku 750 Wh, Bosch Performance Line...","priceCents": 329900,"priceType": "NEGOTIABLE","location": "10115 Berlin Mitte","postedAt": "Heute, 09:12","imageUrl": "https://img.kleinanzeigen.de/api/v1/prod-ads/images/...","url": "https://www.kleinanzeigen.de/s-anzeige/...","adType": "offer","shippingPossible": true,"attributes": { "condition": "Sehr Gut", "brand": "KTM", "color": "Schwarz" },"sellerType": "private"}
Field notes, so you know exactly what you are buying:
priceCentsis the asking price in euro cents.priceTypetells you how to read it:FIXED,NEGOTIABLE(the German "VB", open to offers) orGIVEAWAY("Zu verschenken").adTypeseparates real offers fromwantedads ("Gesuch", someone looking for an item). Filter on it before doing any price analysis; raw scrapers that skip this quietly pollute your data with wish-list prices.locationis the area-level postcode + district the marketplace displays, not a seller address.postedAtis the posting date exactly as displayed: a date, orHeute/Gesternlabels for recent ads.postedDateis the same date normalized toYYYY-MM-DD(relative labels resolved in German local time); it is omitted on the rare row whose label cannot be parsed.attributesare the whitelisted, non-personal specs from the detail page (with Scrape full descriptions on): condition, brand, color and size for goods; mileage, first registration, fuel, transmission and power for cars; living area and rooms for property.descriptionis the search snippet by default and the full listing text with Scrape full descriptions on.
How much does it cost to scrape Kleinanzeigen?
$1.99 per 1,000 listings delivered, pay-as-you-go: no subscription, and you pay per result rather than per hour. A run that finds nothing still costs the $0.005 actor start. In plain dollars:
- 100 listings ≈ $0.20, a daily category watch.
- 500 listings ≈ $1.00, a solid market snapshot, full descriptions included with
scrapeDetails. - A 1,000-listing crawl ≈ $2, a whole search neighbourhood.
The per-result price is all-inclusive: no separate platform-usage charges, even with scrapeDetails enabled. Higher Apify plans get automatic unit-price discounts (down to $1.99/1,000 on Gold). Free-plan runs are limited to a sample of 5 items, enough to evaluate the output format against your real query.
Not technical? Let your AI assistant set it up
Copy this into ChatGPT, Claude or any AI assistant, fill in the one line, and follow the conversation:
Help me set up the "Kleinanzeigen.de Scraper" actor on Apify(https://apify.com/lowlanddata/kleinanzeigen-scraper). Guide me one step at a time.What I want to watch: [E.G. "e-bikes between 500 and 5000 EUR, alert me on new ads"]Guide me to:1. Propose my input values: searchQuery (what I'd type in the Kleinanzeigen searchbox, German terms work best), optional priceMinEur/priceMaxEur, optional location + radiusKm forlistings near a city (e.g. "München" + 10), sortBy "date" for newest-firstmonitoring, postedAfter/postedBefore (YYYY-MM-DD) to keep only listings from adate window, sellerType if I only want private or business ads,scrapeDetails true if I want full descriptions and specs, and maxItems.If I already have searches set up on kleinanzeigen.de, use startUrls with theaddresses of their results pages instead, and onlyNewListings true so scheduledruns return only ads I have not received yet.2. If my watch fits one category: browse kleinanzeigen.de to that category and readthe number from the URL (/s-fahrraeder/c217 means categoryId 217), then add it.3. Create a free Apify account (apify.com), open the actor page, paste the valuesinto the Input form, and start a run.4. Set up a daily Schedule in the Apify Console with the same input, plus an emailor Slack integration so new results reach me automatically.5. Show me how to export results as CSV/Excel, or read them from the API if I code.6. If the results are what I wanted, remind me at the end to leave a quick rating on the actor page, and to report anything broken or missing on its Issues tab.
Input
| Field | Description |
|---|---|
searchQuery | Free-text search, e.g. e-bike. Provide this, a category, or both. |
searchQueries | Several free-text searches in one run, each with the filters below. A listing found by two searches is delivered once. Up to 50. |
startUrls | Addresses of Kleinanzeigen results pages, copied from your browser. Every filter in the URL applies, including the ones this form has no field for (shipping, direct buy, condition). When given, the form's search fields are ignored and the run status says which. Up to 50. |
categoryId | Numeric category ID (the c217-style number in the site's URLs) to scope the crawl. |
location / radiusKm | Radius search: a German city or region name (e.g. München) plus a radius in km (up to 200), resolved via the site's own location search. |
priceMinEur / priceMaxEur | Only listings within this price range, in EUR. |
sortBy | date (newest first, default) or price_asc (cheapest first). |
postedAfter / postedBefore | Date window (YYYY-MM-DD). Keeps only listings posted inside it, using the normalized postedDate field. Listings whose date cannot be read are excluded while a window is set. The site serves only its newest results per query, so a window further back may need a narrower query. |
sellerType | any (default), private, or business. |
scrapeDetails | Fetch each listing's page for the full description + specs. Slower, richer. |
maxItems | Stop after this many listings, across all searches of the run. Default 1,000. With several searches, each gets an equal share of what is left. |
onlyNewListings | Return only listings this search has not delivered before. The first run returns the usual results and remembers them; skipped listings are not charged. |
resetState | With onlyNewListings: forget what was delivered and return the full results once. |
With no query and no category, a run returns the newest listings across the whole site, and says so in its status.
Pasting a search URL
Run your search on kleinanzeigen.de, pick every filter you want, and copy the address bar, e.g. https://www.kleinanzeigen.de/s-fahrraeder/berlin/versand:ja/fahrrad/k0c217l3331r10. The page number in the URL does not matter, every run starts from the first page. Sorting by price is kept; any other sort order runs newest first and the status says so. A listing page (/s-anzeige/...) or an address from another site is refused before the run starts.
Finding a category ID
Browse Kleinanzeigen to the category you want and read the number from the URL: /s-fahrraeder/c217 → 217. Every category and subcategory has one.
Use it from your code
Run the actor and get items straight back with one HTTP call (fine for scoped runs up to ~5 minutes):
curl "https://api.apify.com/v2/acts/lowlanddata~kleinanzeigen-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \-X POST -H "Content-Type: application/json" \-d '{"searchQuery": "e-bike", "maxItems": 100}'
Node.js:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });const run = await client.actor('lowlanddata/kleinanzeigen-scraper').call({searchQuery: 'e-bike',maxItems: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_API_TOKEN>")run = client.actor("lowlanddata/kleinanzeigen-scraper").call(run_input={"searchQuery": "e-bike", "maxItems": 100})items = client.dataset(run["defaultDatasetId"]).list_items().items
Schedules (e.g. a daily price snapshot), webhooks and the Make/Zapier/n8n integrations all work out of the box: this is a standard Apify actor.
Use it in n8n
There is a dedicated community node, so Kleinanzeigen listings can flow straight into an n8n workflow - a scheduled search into Sheets, Telegram alerts on new rows, a database sync - with the Actor's full input as a form.
In n8n: Settings → Community nodes → Install, enter:
n8n-nodes-kleinanzeigen-scraper
Connect it with your Apify API token (or OAuth2 on n8n Cloud) and the Actor runs on your Apify account, billed exactly like a run started here.
Use it with AI agents (MCP)
Claude, Cursor and other MCP-capable agents can run this scraper as a tool through Apify's hosted MCP server: the agent fills in the search itself, starts the run and reads the results, no glue code.
Claude Code:
$claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/kleinanzeigen-scraper"
Cursor or Claude Desktop (add a custom connector / MCP server with this URL):
https://mcp.apify.com?actors=lowlanddata/kleinanzeigen-scraper
Sign in with your Apify account when prompted. Runs are billed to it. Setup details per client: Apify MCP docs, or start from this actor's own MCP page: apify.com/lowlanddata/kleinanzeigen-scraper/api/mcp.
Prompts that work once connected:
- "Find the 20 newest e-bike listings between €500 and €2000 on Kleinanzeigen with full descriptions and summarize the best three."
- "Snapshot Wohnmobil listings posted today and table them by price and location."
- "Search Kleinanzeigen for Makita drills from private sellers and flag anything at least 20% under the median."
Beyond the 1,250-result window
Kleinanzeigen shows at most 50 pages (~1,250 results) per search: on a site with hundreds of thousands of ads per category, a naive scraper silently loses everything past that. This scraper automatically splits large queries by category and price band and deduplicates across the shards, so broad crawls are not quietly truncated.
Is it legal to scrape Kleinanzeigen?
Public listing data (prices, descriptions, specs, area-level locations) is public commercial information, and this scraper is built so that the hard part of the question never arises: no personal data enters your dataset in the first place. Germany's data-protection authorities are among Europe's strictest; an output that carries no personal data is the point of this actor, not an afterthought.
Seller-identifying data is never extracted: the scraper reads named fields from named parts of the page and simply never touches the seller profile block, so there is nothing to filter out afterwards. The only seller signal kept is business vs private (Gewerblicher/Privater Nutzer). Requests are rate-limited to keep load on the marketplace negligible, and no anti-bot protections are bypassed.
One honest limit: titles and descriptions are the seller's own words, delivered as-is. If a seller chooses to type contact details into their listing text, that text is not rewritten: the guarantee covers the data fields, not the content sellers publish about themselves.
Troubleshooting
The actor fails fast with the reason in the run's status message:
- "... is a single listing, not a search" / "... is not a search results page": a URL in
startUrlspoints at an ad or another page. Open the search results on kleinanzeigen.de and copy that address. - "priceMinEur must not be higher than priceMaxEur.": inverted price range.
- "The site markup may have changed, or the request was blocked.": Kleinanzeigen changed their page structure or rejected the request; the actor refuses to return silently empty data. Check the Issues tab. Such changes get fixed quickly.
- Fewer items than requested on a free plan: the 5-item free sample cap; run on a paid Apify plan for full results.
Is there a Kleinanzeigen API alternative?
Kleinanzeigen publishes no public API for listings. This actor is the practical alternative: the same listings as structured JSON through one HTTP call (run-sync-get-dataset-items), on a schedule, or as an MCP tool for AI agents, with the GDPR question already answered in the data itself.
Does Kleinanzeigen block scrapers?
The site serves its listings as regular server-rendered pages, and this actor stays inside that welcome: paced requests, standard datacenter proxies, load kept negligible. No CAPTCHA fights, no bot-wall cat-and-mouse, and when the site's markup changes, the actor fails with a readable message instead of silently returning wrong data.
How do I monitor Kleinanzeigen prices?
Paste your searches into startUrls (or list them in searchQueries), switch on onlyNewListings, and add a daily (or hourly) Schedule in the Apify Console with an email/Slack integration on the runs. The first run returns the current listings; every run after that returns only the ads that appeared since, with the price already parsed (VB and "Zu verschenken" normalized). Listings you already received are skipped and not charged, and so are listings posted on a day before your previous run, so a watch never back-fills older listings it simply had not reached. A newest-first search stops reading as soon as it reaches known listings, so a quiet day is a quick, cheap run. Keep the default newest-first order for this: sorted by price there is no "since", and older listings you never received count as new. The AI-assistant prompt above walks a non-technical user through exactly this setup.
FAQ
Can I get seller names or phone numbers? No, by design. That is the product: data you can store, share and process without a GDPR review. The output tells you only whether the seller is a business or a private person.
Do I get full listing descriptions? Yes, enable scrapeDetails and each listing carries its full description plus the spec table, translated to stable English keys. Off by default to keep runs fast and cheap.
What do VB and "Zu verschenken" become? Normalized machine-readable price types: NEGOTIABLE and GIVEAWAY, so your price analysis never chokes on German price idioms.
Can I filter wanted ads (Gesuche) out? Every item carries adType (offer/wanted), so price analysis can exclude wanted ads with one filter.
How fresh is the data? Live at run time: every run queries the site directly. For continuous freshness, schedule the actor.
Can I export to Excel or CSV? Yes, every dataset exports as CSV, Excel, JSON or XML from the Apify Console or API.
What happens above 1,250 results? The site caps any single search at ~1,250 results; the actor automatically splits large queries and deduplicates, and flags honestly when a shard is still larger than the window.
Does it work with Make, Zapier or n8n? Yes, it is a standard Apify actor; all platform integrations, webhooks and schedules apply.
Can I scrape Kleinanzeigen without an API key? There is no API key to get: Kleinanzeigen publishes no public listings API. Create a free Apify account, fill in the input form, and this actor does the rest.
What does it cost per 1,000 listings? $1.99, all-inclusive: platform usage is covered by the per-result price, even with scrapeDetails on. Higher Apify plans pay less per unit, down to $1.99/1,000 on Gold.
Why did I only get 5 listings back? Free Apify plans are limited to a 5-item sample per run, a real taste of the output against your own query. A paid plan removes the cap.
Can I paste a search URL from Kleinanzeigen? Yes, put the results page address into startUrls. Every filter in it applies, including ones the input form has no field for, such as shipping, direct buy or condition. Paste up to 50 to run them all in one go.
Can a scheduled run return only the new ads? Yes, switch on onlyNewListings. Each search remembers what it delivered, for 90 days, in a key-value store in your own Apify account. Ads you already received are skipped and not charged. Changing a search's filters starts a fresh memory, and resetState clears it on purpose.
Can I search only around my city? Yes, set location to a German city or region ("München", "Berlin") and radiusKm up to 200; the actor resolves it through the site's own location search.
How do I find the right category ID? Browse kleinanzeigen.de to the category and read the number out of the URL: /s-fahrraeder/c217 means categoryId: 217.
Can I scrape only private sellers, without dealers? Set sellerType to private (or business for the opposite). The default returns both.
Does it work for used cars with mileage and specs? Yes. With scrapeDetails enabled, car listings carry mileage, first registration, fuel, transmission and power as structured attributes, enough to build a price-vs-mileage curve.
What exactly is in the location field? The area-level postcode and district the marketplace itself displays, e.g. "10115 Berlin Mitte", never a seller address.
What happens when a run is blocked or the site changes? The actor stops with a readable error instead of returning silently empty or wrong data. Failed and empty runs are free.
Does this actor send anything back to the developer? On failure only, and only this: the actor name and build number, a one-word error category, the error message truncated to 300 characters, and a one-way hash of your input. That hash lets us see that the same input keeps failing without us ever seeing what it was. Your input, your results and your identity are never sent, and a successful run sends nothing at all. Set reportFailures to false and the actor behaves in exactly the same way, minus the report. The reason this exists: your runs execute in your own Apify account, so when one fails we see a number on a counter and no reason - in September 2026 that cost days of guesswork on a bug that was hurting paying users.
What input combinations will fail? Five, and each fails immediately with the reason: a search URL that is not a Kleinanzeigen results page (a single ad, another site, or text that is not a URL), a radius without a location (there is nothing to measure from), a minimum price above the maximum, an empty searchQuery string (leave the field out instead of sending ""), and a postedAfter/postedBefore that is not YYYY-MM-DD or a full ISO timestamp. That last one is deliberate: 08/09/2026 is refused rather than read as the ninth of August, which is what a date parser would otherwise do to a European writing the eighth of September.
What happens if I give no query and no category? You get the newest listings across the whole site, and the run says so in its status. It is a real mode, not an error - useful for a broad watch feed, and it means an agent calling this actor with no input gets data rather than a failure.
Which proxies do I need for Kleinanzeigen? The default Apify datacenter proxies are what most runs need, and there is no CAPTCHA fight. The site does refuse a share of datacenter exits, though: the actor answers that by retrying on fresh IPs, and a run it cannot get through with fails instead of returning empty. If a schedule of yours fails repeatedly at the same hour, switching that run to residential proxies clears it.
Can ChatGPT or Claude run this scraper for me? Yes, connect it through Apify's hosted MCP server and any MCP-capable agent can fill in the search, start the run and read the results on its own.
Is it legal to scrape Kleinanzeigen? Public listing data is public commercial information, and this actor never extracts seller-identifying data in the first place: the GDPR question is answered in the dataset itself, not in a disclaimer.
Does this exist for Marktplaats or 2dehands as well? It does: see the related scrapers below, built with the identical GDPR-clean output guarantee for the Netherlands and Belgium.
Related scrapers
Working the German/Benelux second-hand market? The same GDPR-clean guarantee, same output shape:
- Marktplaats.nl Scraper: the Netherlands' largest marketplace.
- 2dehands & 2ememain Scraper: Belgium's largest second-hand marketplaces.
Support
Found an issue or missing a field you need? Open an issue on the actor's Issues tab: reports get fixed, this actor is actively maintained.
Working well for you? A rating on this page takes ten seconds and helps other buyers find a GDPR-clean option among the lookalikes: it is also the clearest signal of what we should build next.