Piotr VassevPiotr Vassev

How to Scrape Kleinanzeigen Listings for Used-Price Research

A search for a used phone can include damaged devices, accessories, trade offers, and several storage capacities. Sorting those ads by the first number in the price field will not produce a reliable market comparison.

The Kleinanzeigen Listings Scraper collects German classified ads from search terms or category/search URLs. I maintain this Apify Actor. It offers listing summaries and a detail mode for descriptions, seller information, attributes, and images. This guide uses those modes to build an asking-price comparison for one phone model.

Kleinanzeigen used-listing research

Keep the first search to one page

You can put keywords in searchTerms or copy a Kleinanzeigen category/search URL into startUrls. A URL is useful when you have already selected a location or other filters on the website. Check that those filters remain in the copied URL before relying on them.

Open the Actor on Apify, choose Input, then JSON, and enter:

{
  "searchTerms": ["iphone 13"],
  "maxPages": 1,
  "maxRequestsPerCrawl": 10,
  "scrapeDetails": false,
  "proxyConfiguration": {"useApifyProxy": false}
}

maxPages is applied per search term or start URL and currently allows one to five pages. maxRequestsPerCrawl is a total HTTP-request ceiling, not an ad-count limit. A single listing-page request can produce many ads, so ten requests does not mean ten output rows.

Click Start, then review the completed run's dataset. Check titles and locations before adding more searches. If the sample is dominated by cases, spare parts, or unrelated generations, narrow the query or use a reviewed category URL. Five pages of an unsuitable query will not make it a better comparison.

Preserve price qualifiers and dates

Listing output includes adId, url, title, price, location, datePosted, a description excerpt, shipping, isPro, imageCount, and scrapedAt.

The published historical listing sample has price: "900 € VB" and datePosted: "Heute, 16:51". “VB” marks an asking price open to negotiation. Preserve it in the raw price column when deriving a numeric amount. Do not silently convert nonnumeric or unusual price text into zero.

“Today” is relative to the collection date, so keep scrapedAt alongside datePosted. The detail example uses an absolute date instead. Normalize dates only after checking the format and the relevant local date; do not treat the two modes as identical text formats.

An empty shipping array does not prove that shipping is impossible. Likewise, isPro distinguishes the source's seller classification, not the trustworthiness of a seller.

Historical Kleinanzeigen listing and detail output

Use detail mode for condition and contents

Repeat a small search with scrapeDetails: true when the listing card leaves important questions open. Each detail request now consumes part of maxRequestsPerCrawl, so the same ten-request limit may stop before all discovered ads are inspected.

Detail records can contain sellerName, category, attributes, and images in addition to the longer description. In the historical phone example, attributes include Art, Farbe, Gerät & Zubehör, and Zustand. These are source labels, and their presence varies by category.

Look for exact model, storage size, stated condition, battery information where supplied, damage, missing parts, and whether the ad is for the device itself. An attribute labeled “Gut” does not replace the description. If an important fact is absent, mark it unknown and keep the ad out of comparisons that require it.

The documented startUrls input is for category/search pages, so this guide does not assume a direct-ad-URL enrichment mode. Search contents may change between your two runs. Join outputs by adId, never by row number, and inspect unmatched rows.

Build a comparable asking-price sample

Export CSV for the first review. Keep IDs, URLs, title, raw price, location, date, collection time, and seller type. For detail output, retain JSON as well so you do not lose the attributes or image arrays.

Remove duplicate ad IDs. Add model, storage, condition, bundle contents, and a reason-for-exclusion column. Separate broken devices and accessories before calculating any summary. If you compare local pickup offers, keep geography consistent and exclude ads whose location is unclear.

Create the numeric price column only for offers with an interpretable amount and currency. Show the count of included ads beside a median, and label the result “observed asking prices.” Negotiation, collection costs, and the final transaction price are not in that statistic.

For a repeat study, keep dated snapshots and match ads by ID. An absent ad should be labeled “not observed in this search,” not “sold.” Follow the source URL if its status matters to your analysis.

Understand the two event rates

Prices as of September 6, 2026 are $0.001 per listing and $0.004 per detail record. The README says these modes charge their respective event rather than both for the same enriched ad. For illustration, fifty listing results cost $0.05 in result events; fifty detail results cost $0.20.

The start event is $0.00005 per GB of allocated memory, minimum one event. Review live pricing, any separate proxy usage, and the actual output count rather than estimating cost from the request cap alone.

If results stop early, check both the page and request limits. If access failures appear, the input supports optional proxies; test a small run after changing the configuration. Missing detail fields can also reflect what the advertiser chose to publish.

The Kleinanzeigen Node.js example can support recurring exports. Keep data from OLX or Depop in separate market samples until category, condition, currency, and geography are comparable.

Frequently asked questions

Does maxRequestsPerCrawl limit the number of ads?

No. It limits HTTP requests across the run. A listing-page request can yield multiple ads, while detail mode also spends requests on individual ad pages.

Are listing and detail charges additive?

The deployed README describes separate modes: listing mode charges listing events, while detail mode charges detail events. The Actor-start charge also applies.

Can I infer a sale from a disappearing ad?

No. An ad may be removed, changed, outside the current page limit, or unavailable to the scraper. Disappearance does not verify a sale or its final price.

Piotr Vassev

Piotr Vassev

Founder of FalconScrape. Building production-grade web scraping systems and data automation pipelines for businesses worldwide.

Connect on LinkedIn