Search classified listings by keyword, location and price range.
Searches Kleinanzeigen (formerly eBay Kleinanzeigen) like the site's own search page. Returns up to 25 listings per page with a numeric price, VB (negotiable) and free flags, postcode and district, posting date, seller type and link. Third-party sponsored ads are removed; paid 'top' listings are kept and marked promoted.
- Site
- Kleinanzeigen, Germany
- Version
- v1
- Runs, last 7 days
- No reports yet
- sha256
- 67200164607c…
Requests
sent from your browser, in order- 1GET/s-ort-empfehlungen.json?queryFree-text place to Kleinanzeigen location id. Response is {"_<id>": "<label>"} with _0 = Deutschland first.
- 2GET/s-sortierung:{{params.sort}}/preis:{{params.min_price}}:{{params.max_price}}/seite:{{params.page}}/{{params.query | urlencode}}/k0l{{steps.location.id}}r{{params.radius_km}}Server-rendered result page. The result list is embedded as Astro island props (resultAds). On a zero-result page that island is missing, so the selector falls back to the sorting island, which yields an empty list instead of an error.
Parameters
from your agentlocationstringCity or district, e.g. 'Berlin', 'München', 'Hamburg-Altona'. The first match is used and returned as output.location. Omit to search all of Germany.
max_priceintegerMaximum price in EUR
min_priceintegerMinimum price in EUR
pageintegerResult page, 25 listings per page = 1
querystringrequiredWhat to search for, e.g. 'fahrrad', 'ikea sofa'
radius_kmenumSearch radius around location in km. Only used together with location. 5 | 10 | 20 | 30 | 50 | 100 | 150 | 200
sortenum'preis' = cheapest first. Omit for the site's default relevance order. "preis"
Returns
to your agentlistingsobject[]description, district, free, id, image_url, negotiable, posted_date, posted_relative, posted_time, price_eur, price_text, promoted, seller_type, shipping, title, url, zip
locationstringResolved place label, or 'Deutschland' when no location was given
pageinteger
querystring
totalintegerTotal hits reported by the site (all pages)
Where it can send
- www.kleinanzeigen.de
Anything else is blocked by the extension.
Reads from your session
Nothing. Your browser attaches the site's cookies by itself.
Used only in requests to the addresses on the left. Never sent to wield.run or your agent.
Checks
a run passes when- length(output.listings) > `0`
- output.location == 'Berlin'
- output.total > `0`
- length(output.listings[?price_eur != `null` && (price_eur < `50` || price_eur > `300`) && !promoted]) == `0`
- starts_with(output.listings[0].url || '', 'https://www.kleinanzeigen.de/s-anzeige/')
Raw recipe
Served as canonical JSON from /api/v1/recipes/kleinanzeigen.de/search-listings, so its sha256 matches the ETag and the index.
Check it yourself
curl -s https://wield.run/api/v1/recipes/kleinanzeigen.de/search-listings | shasum -a 256 # 67200164607c1caf820fd70e4ed04e94d467e22cc376fefa18eb34df4fee4fb6
kleinanzeigen.de/search-listings.json, v1
{ "description": "Searches Kleinanzeigen (formerly eBay Kleinanzeigen) like the site's own search page. Returns up to 25 listings per page with a numeric price, VB (negotiable) and free flags, postcode and district, posting date, seller type and link. Third-party sponsored ads are removed; paid 'top' listings are kept and marked promoted.", "effect": "read", "id": "kleinanzeigen.de/search-listings", "keywords": [ "kleinanzeigen", "ebay kleinanzeigen", "gebraucht", "kaufen", "anzeigen suchen", "flohmarkt", "second hand", "used", "classifieds", "marketplace", "listings", "buy used" ], "output": { "schema": { "properties": { "listings": { "items": { "properties": { "description": { "description": "Truncated description snippet", "type": [ "string", "null" ] }, "district": { "type": [ "string", "null" ] }, "free": { "description": "Zu verschenken", "type": "boolean" }, "id": { "type": "string" }, "image_url": { "type": [ "string", "null" ] }, "negotiable": { "description": "VB (Verhandlungsbasis)", "type": "boolean" }, "posted_date": { "description": "Set for older listings; null when the site only says today/yesterday", "format": "date", "type": [ "string", "null" ] }, "posted_relative": { "enum": [ "today", "yesterday", null ] }, "posted_time": { "description": "HH:mm, Europe/Berlin, for today/yesterday listings", "type": [ "string", "null" ] }, "price_eur": { "description": "null when no price is given or the item is free", "type": [ "number", "null" ] }, "price_text": { "description": "Price exactly as the site shows it", "type": [ "string", "null" ] }, "promoted": { "description": "Paid top listing, pinned above the sort order", "type": "boolean" }, "seller_type": { "enum": [ "private", "commercial", null ] }, "shipping": { "description": "Seller offers shipping", "type": "boolean" }, "title": { "type": "string" }, "url": { "format": "uri", "type": "string" }, "zip": { "type": [ "string", "null" ] } }, "type": "object" }, "type": "array" }, "location": { "description": "Resolved place label, or 'Deutschland' when no location was given", "type": "string" }, "page": { "type": "integer" }, "query": { "type": "string" }, "total": { "description": "Total hits reported by the site (all pages)", "type": [ "integer", "null" ] } }, "required": [ "query", "location", "page", "total", "listings" ], "type": "object" }, "value": "let $h = steps.search.heading || '' in {query: params.query, location: steps.location.name || 'Deutschland', page: params.page, total: contains($h, 'keine Ergebnisse') && `0` || to_number(replace(split(split($h, ' von ')[1] || '', ' ')[0], '.', '')), listings: steps.search.listings}" }, "params": { "additionalProperties": false, "properties": { "location": { "description": "City or district, e.g. 'Berlin', 'München', 'Hamburg-Altona'. The first match is used and returned as output.location. Omit to search all of Germany.", "maxLength": 80, "type": "string" }, "max_price": { "description": "Maximum price in EUR", "minimum": 0, "type": "integer" }, "min_price": { "description": "Minimum price in EUR", "minimum": 0, "type": "integer" }, "page": { "default": 1, "description": "Result page, 25 listings per page", "maximum": 50, "minimum": 1, "type": "integer" }, "query": { "description": "What to search for, e.g. 'fahrrad', 'ikea sofa'", "maxLength": 100, "minLength": 1, "type": "string" }, "radius_km": { "description": "Search radius around location in km. Only used together with location.", "enum": [ 5, 10, 20, 30, 50, 100, 150, 200 ], "type": "integer" }, "sort": { "description": "'preis' = cheapest first. Omit for the site's default relevance order.", "enum": [ "preis" ], "type": "string" } }, "required": [ "query" ], "type": "object" }, "provenance": { "method": "browser-inspect", "notes": "spikes/kleinanzeigen.md. No JSON search API: the SRP (Astro microfrontend) embeds the result list in astro-island props (resultAds). Uses the canonical path, not /s-suchanfrage.html, because that form 302-redirects and Chrome hides redirect targets from fetch(redirect:'manual'). Verified path forms: empty sortierung:/preis::/k0l/r segments fall back to defaults; keyword may be percent-encoded. sortierung:preis = PRICE_AMOUNT (cheapest first); other sort tokens (neueste) are ignored by the site. Akamai is present but does not gate the SRP; credentials and custom headers are not needed.", "recorded_at": "2026-11-07T11:45:00+01:00", "recorded_by": "C4" }, "requires_login": false, "schema": "https://wield.run/schema/recipe/v1.json", "site": { "country": "DE", "id": "kleinanzeigen.de", "language": "de", "login_url": "https://www.kleinanzeigen.de/m-einloggen.html", "name": "Kleinanzeigen", "origin": "https://www.kleinanzeigen.de", "origins": [ "https://www.kleinanzeigen.de" ] }, "steps": [ { "description": "Free-text place to Kleinanzeigen location id. Response is {\"_<id>\": \"<label>\"} with _0 = Deutschland first.", "expect": { "assert": "length(keys(body)) > `1`", "content_type": "json", "status": [ 200 ] }, "extract": { "json": { "id": "replace(items(@)[?[0] != '_0'] | [0][0], '_', '')", "name": "items(@)[?[0] != '_0'] | [0][1]" } }, "id": "location", "request": { "headers": { "Accept": "application/json" }, "method": "GET", "query": { "query": "{{params.location}}" }, "url": "/s-ort-empfehlungen.json" }, "when": "params.location" }, { "description": "Server-rendered result page. The result list is embedded as Astro island props (resultAds). On a zero-result page that island is missing, so the selector falls back to the sorting island, which yields an empty list instead of an error.", "expect": { "content_type": "html", "status": [ 200 ] }, "extract": { "embedded_json": { "attr": "props", "decode": "astro_props", "selector": "astro-island[props*='resultAds'], html:not(:has(astro-island[props*='resultAds'])) astro-island[props*='selectedSortingField']", "vars": { "listings": "resultAds[?organicAdPreview].organicAdPreview.{id: to_string(id), title: title, price_eur: to_number(replace(replace(replace(split(price || '', ' ')[0], '.', ''), ',', '.'), '€', '')), negotiable: contains(price || '', 'VB'), free: contains(price || '', 'verschenken'), price_text: price, zip: locationName, district: parentLocationName, posted_date: contains(sortingDate || '', '.') && join('-', reverse(split(sortingDate, '.'))) || `null`, posted_relative: starts_with(sortingDate || '', 'Heute') && 'today' || (starts_with(sortingDate || '', 'Gestern') && 'yesterday' || `null`), posted_time: contains(sortingDate || '', ',') && trim(split(sortingDate, ',')[1]) || `null`, seller_type: posterType && lower(posterType) || `null`, promoted: topAd == `true`, shipping: shippingAvailableValue != '' && shippingAvailableValue != `null`, url: join('', ['https://www.kleinanzeigen.de', seoLink]), image_url: imageList[0].xLargeUrl, description: description && replace(replace(replace(replace(replace(replace(description, '"', '\"'), ''', '\\''), ''', '\\''), '/', '/'), '<', '<'), '&', '&') || `null`} || `[]`" } }, "html": { "heading": { "selector": "h1" } } }, "id": "search", "parse": "html", "request": { "headers": { "Accept": "text/html" }, "method": "GET", "url": "/s-sortierung:{{params.sort}}/preis:{{params.min_price}}:{{params.max_price}}/seite:{{params.page}}/{{params.query | urlencode}}/k0l{{steps.location.id}}r{{params.radius_km}}" } } ], "task": "Search classified listings by keyword, location and price range", "tos": { "notes": "Kleinanzeigen's terms forbid automated mass retrieval of listing data. This recipe runs one user-initiated search at a time in the user's own browser, at human pace. Do not loop over pages in bulk or store listings. Seller contact goes through the separate message-seller recipe, which needs the user's login and explicit Allow.", "reviewed": false }, "verify": { "checks": [ "length(output.listings) > `0`", "output.location == 'Berlin'", "output.total > `0`", "length(output.listings[?price_eur != `null` && (price_eur < `50` || price_eur > `300`) && !promoted]) == `0`", "starts_with(output.listings[0].url || '', 'https://www.kleinanzeigen.de/s-anzeige/')" ], "example_params": { "location": "Berlin", "max_price": 300, "min_price": 50, "query": "fahrrad" }, "max_ms": 6000 }, "version": 1 }