DEV Community

Cover image for How to scrape Kleinanzeigen.de listings by city and radius with Python
Norbert Sobala
Norbert Sobala

Posted on

How to scrape Kleinanzeigen.de listings by city and radius with Python

Kleinanzeigen.de, formerly eBay Kleinanzeigen, is Germany's biggest classifieds site. People sell bikes, cars, furniture and flats there. The site itself only shows 25 listings per page and stops after 50 pages. For a price check or a daily alert you want the data in a table. This post walks through the Kleinanzeigen Scraper on Apify, first without code and then from Python.

My test search: e-bike within 20 km of Berlin, newest first, capped at 40 listings. Every number below is from that run on 22 October 2026.

Kleinanzeigen Scraper results for e-bike listings around Berlin

What the run returned

Kleinanzeigen reported 2,208 matching listings for that search. I only took the newest 40, which covered roughly 12 and a half hours of posts (the oldest timestamped one was from 18:54 UTC the evening before, the newest from 07:20 UTC). Expect a busy category in a big city to fill up fast.

The price summary row gave me this for the 33 listings it analysed:

Metric Value
Min 2 EUR
25th percentile 850 EUR
Median 1,899 EUR
Average 2,002.55 EUR
75th percentile 2,499 EUR
Max 6,599 EUR
Negotiable (VB) 12.12%
Price reduced 3.03%
Shipping offered 72.73%

The top location was Lichtenberg with 16 listings, far ahead of every other district. Most of those came from shops, which brings me to the first lesson: 24 of the 40 listings were from PRO (commercial) sellers, and 4 were promoted TOP ads.

The 2 EUR minimum was a luggage strap, which matched "e-bike" somewhere in its text. More on filtering that out below.

Fields you get per listing

Field Example from this run Notes
title Giant Explore E+ 2 STA amber glow XL E-Bike
price, priceType 1999, fixed negotiable for VB listings
originalPrice, priceReduced Filled when the seller cut the price
location, postalCode Friedrichshain, 10243
distanceKm 4 Distance from your search location
postedAt 2026-10-22T06:08:00Z Missing on some TOP ads
shippingAvailable, buyNow true "Versand möglich", "Direkt kaufen"
isTopAd false Promoted listing
sellerType, isProSeller, shopName commercial, true, Radwelt Mitte RWM 1 GmbH Shop name only for PRO sellers
mileageKm, firstRegistration Cars, already in search results
livingSpaceM2, rooms Real estate
imageUrl, imageCount, url

With Listing details on, you also get the full description, all attributes (brand, model, frame size and so on), the equipment list, all photos and GPS coordinates.

Option 1: no code

  1. Open the Kleinanzeigen Scraper and click Try for free. A free Apify account is enough. You do not need a Kleinanzeigen login or your own proxies.
  2. Type e-bike into Search terms.
  3. Set Location to Berlin and Radius to 20 km. Postcodes like 80331 work too.
  4. Set Max. listings per search to 40.
  5. Add suche and defekt to Exclude words. That drops "looking for" posts and broken bikes, and filtered listings are free.
  6. Turn on Price summary per search.
  7. Click Start. Then open the Listings or Price summaries view, or export CSV, Excel or JSON.

Input form of the Kleinanzeigen Scraper on Apify

Input options worth knowing

  • Kleinanzeigen URLs: set filters on kleinanzeigen.de in your browser and paste the link. Category-specific filters (mileage, first registration, rooms, living space, brand) stay in the URL and the scraper keeps them. Single listings, seller pages and PRO shops work as well.
  • Categories: limit keywords to one or more categories. Picking the e-bike category would have kept my luggage strap out.
  • Title must include (any): keep only listings whose title has one of your words. Also a fix for the strap.
  • Min. / Max. price: a 100 EUR floor removes most accessories in one go.
  • Listing type: offers, wanted ads, or both.
  • Seller type: private or commercial. Useful here, since shops dominated the results.
  • Shipping and Only "Direkt kaufen": shipping only, pickup only, or buy-now listings.
  • Posted within (hours): for example 24. The search stops once it reaches older listings, so daily runs stay cheap.
  • Only price-reduced listings: listings where the seller crossed out an older price.
  • Include TOP ads: switch off for organic results only.
  • Get more than 1,250 results: on by default. Big searches are split into price ranges to get past the 50 page limit.
  • Sellers to track: user IDs, seller links or PRO shop names, with their profile and active listings.

Option 2: Python with apify-client and pandas

pip install apify-client pandas
Enter fullscreen mode Exit fullscreen mode
from apify_client import ApifyClient
import pandas as pd

client = ApifyClient("YOUR_APIFY_TOKEN")

run_input = {
    "searchQueries": ["e-bike"],
    "location": "Berlin",
    "radiusKm": "20",
    "maxItemsPerSearch": 40,
    "excludeKeywords": ["suche", "defekt"],
    "priceSummary": True,
}

run = client.actor("liveclaude/kleinanzeigen-scraper").call(run_input=run_input)
items = client.dataset(run["defaultDatasetId"]).list_items().items

df = pd.DataFrame(items)
listings = df[df["recordType"] == "listing"].copy()
summary = df[df["recordType"] == "price-summary"]

# shops carry sellerType "commercial"; other listings have no shop attached
listings["seller"] = listings["sellerType"].fillna("no shop")

bikes = listings[listings["price"] >= 100]
print(bikes.groupby("seller")["price"].agg(["count", "median", "min", "max"]))

bikes.to_csv("ebikes_berlin.csv", index=False)
Enter fullscreen mode Exit fullscreen mode

Note that radiusKm is a string. The input form offers fixed values (0, 1, 2, 3, 5, 10, 15, 20, 30, 50, 100, 150, 200).

Output from my run:

            count  median     min     max
seller
commercial     23  2499.0  1590.0  6599.0
no shop        12   815.0   249.0  2000.0
Enter fullscreen mode Exit fullscreen mode

That split tells you more than the overall median. Shops in this search started at 1,590 EUR and sat around 2,499 EUR. Listings without a shop had a median of 815 EUR. If you are hunting for a used e-bike, set Seller type to private and the overall 1,899 EUR median stops being misleading.

Two listings were below 100 EUR and the filter dropped them.

Scheduling and alerts

The scraper has a monitoring mode built for alerts:

  1. Save your input as a task.
  2. Turn on Only new listings (monitoring). Later runs return only listings you have not seen, plus price drops.
  3. Keep Detect sold / reserved / deleted listings on. Listings that vanish are reported as sold, reserved or removed, with daysOnMarket. Every record has listingStatus so you can route them.
  4. Combine with Posted within (hours) set to 2 or 24 and schedule hourly or daily.
  5. Give the task a Monitor name like ebikes-berlin if you run several monitors.

For searches over 2,000 results, sold detection and older price drops only work after you narrow the search with a location, category or price range. My 2,208 result query would need a price band for that.

Results can go to Google Sheets, Slack, Make, Zapier, n8n or any webhook, or you can call the scraper from an AI agent through the Apify MCP server.

Pricing per 1,000 results

Pay per event. Current prices per 1,000 events:

Event Free Starter Scale Business
Listing $1.30 $1.20 $1.05 $0.90
Listing details (optional) $1.20 $1.10 $1.00 $0.90
Seller / shop profile $2.00 $1.80 $1.60 $1.50

A price summary row costs about one cent and each run has a start fee of $0.00005. Filtered listings, already seen listings in monitoring mode and failed pages are free. At Free plan prices, my 40 listing run with one summary works out to roughly six cents. You can set a maximum cost per run and it stops there.

Responsible use

Many Kleinanzeigen sellers are private people. The scraper does not collect phone numbers or e-mail addresses of private sellers, and Kleinanzeigen hides them anyway. PRO shops publish business contact details on their shop pages, and only those end up in seller records. If you turn on seller profiles, you may get display names of private sellers too; leave them out of anything you publish or share, and keep in mind that GDPR covers storing them. Kleinanzeigen's terms apply to what you do with the data. Use small, targeted searches with filters and you will collect less data and pay less.

This tutorial was written with AI assistance and checked by the author. All numbers come from a real run of the scraper.

Top comments (0)