# Kleinanzeigen Real Time Data Scraper (`b2b_leads/kleinanzeigen-real-time-data-scraper`) Actor

Live Kleinanzeigen resale intelligence for thrift & vintage resellers: keyword search, full listing details, seller inventory, seller profiles, sold comps & URL collection. Stream structured JSON in real time — pay only for results.

- **URL**: https://apify.com/b2b\_leads/kleinanzeigen-real-time-data-scraper.md
- **Developed by:** [Emmanuel](https://apify.com/b2b_leads) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Kleinanzeigen Real-Time Data

> **Free Apify plans are limited to 2 results per run.** Upgrade to a paid Apify plan for unlimited results. See [Free plan vs paid plans](#-free-plan-vs-paid-plans) below.

**Live Kleinanzeigen resale market intelligence — thrift price comps, seller inventory tracking, vintage deal finder.**

Kleinanzeigen (formerly eBay Kleinanzeigen) is Germany's largest classifieds marketplace and one of the best hunting grounds for undervalued vintage and thrift inventory. This actor streams structured resale data in real time: live keyword search cards, full listing details, seller inventory, seller profiles, and sell-through snapshots — built for cross-listers, sourcing bots, and pricing teams.

### 👥 Who is this for?

- **Vintage & thrift resellers** (cross-listers on Poshmark, eBay, Depop, Mercari, Grailed, Vinted) sourcing German-market inventory — vintage Carhartt, single-stitch band tees, designer denim, gorpcore, Y2K
- **Resale arbitrageurs** tracking underpriced listings the moment they appear ("newest first" sort + webhook alerts)
- **Consignment & vintage shop owners** monitoring competitor inventory and repricing moves by seller ID
- **Fashion researchers & pricing teams** building sold comps, sell-through rates, and multi-platform price comparisons
- **AI agents / MCP workflows** asking natural-language pricing questions over structured JSON

### ✨ Features (checkbox — enable only what you need)

| Feature | Input | What you get |
|---|---|---|
| 🔍 **Listing Search** | `searchKeywords`, `searchMaxResults`, `searchSort`, price/condition/size/category filters | Fast search cards: price, title, description snippet, size/condition tags, location, listed time, shipping tags. Live keyword search for thrift brands, streetwear, and vintage finds. |
| 📦 **Listing Details** | `listingUrls`, `listingIds` | Full records: complete description, brand/size/color/condition specifics, full image gallery, shipping cost, seller context, buy-now/offers flags. |
| 👚 **Seller Inventory (closet)** | `sellerIds`, `sellerMaxListings` | Paginated active inventory per seller — competitor stock and repricing moves. |
| 👤 **Seller Profile** | `sellerIds` | Display name, trust badges, member since, active listings count, reputation rating where available. |
| 🧾 **Sold Item Comps / History** | `sellerIds`, `soldMaxItems` | Sell-through snapshot per seller: inventory rows with per-item sold status for comps and margin analysis. |
| 🔗 **Scrape By URL** | `scrapeUrls` | Paste any Kleinanzeigen URL — search, seller inventory, category page, or single listing. Page type is auto-detected. |

#### Enrichment, not duplication

With **"Enrich with full listing details"** (`searchFetchFullDetails`) enabled, each search card stays **ONE row** (`featureType: "listing_search"`, `detailsFetched: true`) and is enriched in place with description, item specifics, full image gallery, and seller context. Nothing is filtered out, no duplicate rows — every discovered item goes to the dataset. Adds a little extra time per listing.

#### Filters vs lead tags — what gets filtered and what doesn't

Server-side filters change how many pages a run must read, so only the predictable ones are filters:

- Min/max price (EUR), sort order (relevance / newest / price low→high / price high→low) — apply per keyword with a predictable result volume
- **Buy-now** and **"Gesucht" (wanted) ads** are **tags, not filters**: with **"Tag buy-now & wanted leads"** enabled, every row carries `is_buy_now` and `is_wanted` flags while every discovered listing still goes to the dataset. Results are never filtered — filter downstream in your own tooling instead. This keeps runtime per 1,000 listings predictable (and the tags cost nothing extra: they are read from the same listing card).
- Category narrowing via the category slug from the marketplace URL (e.g. `kleidung-herren`)
- Size as a free-text hint matched against listing tags

### 🚀 Quick start

1. Enable **Listing Search** (on by default).
2. Keep the prefilled keywords — `carhartt detroit jacke`, `vintage levis 501`, `patagonia fleece` — or type your own (German terms work best).
3. Leave **Max results per keyword** at 10 for an instant first run.
4. Click **Start**. Results stream into the dataset row by row as they are collected.

#### Example input

```json
{
    "enableListingSearch": true,
    "searchKeywords": ["carhartt detroit jacke", "vintage levis 501", "patagonia fleece"],
    "searchMaxResults": 10,
    "searchSort": "newest",
    "searchMaxPrice": 120
}
```

#### Example: seller inventory + profile + comps

```json
{
    "enableClosetListings": true,
    "enableSellerProfile": true,
    "enableSoldHistory": true,
    "sellerIds": ["33915083"],
    "sellerMaxListings": 30,
    "soldMaxItems": 30
}
```

Seller IDs are the numeric profile IDs from a seller page URL (`…bestandsliste.html?userId=33915083` → `33915083`).

#### Example: Scrape By URL

```json
{
    "enableScrapeByUrl": true,
    "scrapeUrls": [
        "https://www.kleinanzeigen.de/s-suchanfrage.html?keywords=carhartt+jacke&sortBy=creationTime",
        "https://www.kleinanzeigen.de/s-anzeige/carhartt-wip-detroit-jacket-jacke-l/3524930885-160-3508"
    ]
}
```

Only Kleinanzeigen URLs are accepted — other domains are rejected with a clear error.

### 📤 Output fields (per row)

Every row carries `featureType` (`listing_search`, `listing_details`, `closet_listings`, `seller_profile`, `sold_history`, `scrape_by_url`), `scrapedAt`, and `url`, plus the shared core below so datasets stay portable across marketplaces and downstream pricing tools:

| Group | Fields |
|---|---|
| **Identity** | `item_id` (ad ID), `item_url`, `title`, `description`, `slug`, `status` |
| **Images** | `main_image_url`, `additional_image_urls` (full gallery on enriched/detail rows) |
| **Pricing** | `current_price`, `original_price` (pre-reduction price), `currency` (EUR), `discount_percentage`, `price_drop_amount`, `shipping_cost`, `free_shipping`, `accepts_offers` (VB / buy-now) |
| **Product** | `brand`, `size`, `condition`, `category`, `department`, `subcategory`, `color`, `style_tags`, `material`, `item_specifics` (full attribute list on detail rows) |
| **Timing** | `created_at` (best-effort from the listed-on stamp), `updated_at`, `sold_at`, `is_newly_listed` |
| **Engagement** | `likes_count` (watch count when exposed), `shares_count`, `comments_count`, `number_of_offers`, `is_sold` |
| **Seller** | `seller_username` (display name), `seller_id` (numeric ID), `seller_rating`, `seller_closet_size` (active listings), `seller_location`, `seller_verified` (trust badges) |
| **Lead tags** | `is_buy_now` (fixed "Direkt kaufen" price), `is_wanted` ("Gesucht" buyer ads) — tagging toggle, never a filter |
| **Flags** | `is_nwt`, `is_nwot`, `is_vintage`, `is_promoted` |
| **Meta** | `position`, `detailsFetched`, `pageType` (Scrape By URL rows) |

Fields that the marketplace does not expose stay `null` — they are never faked.

### 🔔 Webhooks (deal alerts)

Set `webhookUrl` and every saved record is additionally POSTed in real time — fire-and-forget, so alerts never slow collection:

- **JSON** (`webhookFormat: "json"`): the full record object — ideal for Discord/Zapier/Make/n8n/custom pricing bots.
- **Slack** (`webhookFormat: "slack"`): a formatted message with title, price, original price, brand, size, condition, seller, and a link.

```json
{
    "webhookUrl": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
    "webhookFormat": "slack"
}
```

Typical alert flow: `searchSort: "newest"` + `searchMaxPrice` + webhook → ping your channel the moment fresh inventory matches your sourcing criteria. With lead tagging on, Slack alerts also show `Leads: buy-now` / `Leads: wanted ad` so you can triage at a glance.

### 🤖 AI agents / MCP

The actor works naturally through [Apify MCP Server](https://docs.apify.com/platform/integrations/mcp): expose it as a tool and ask questions like:

- *"What is the average asking price for a 90s Carhartt Detroit jacket on Kleinanzeigen?"*
- *"Find vintage Levi's 501 under €60 listed in the last 24 hours."*
- *"How many active listings does seller 33915083 have, and what share shows as sold?"*

The structured rows (`current_price`, `original_price`, `brand`, `size`, `condition`, `created_at`, `is_sold`) make aggregations and cross-marketplace comparisons straightforward.

### 🛡️ Free plan vs paid plans

Apify injects your plan status into every platform run:

- **Paying plans (Bronze and above):** full output, uncapped.
- **Free plan:** results are capped at **2 items per run** (owner-configurable) so you can test the actor end-to-end. Upgrade to a paid Apify plan for unlimited vintage and thrift data exports. The run log states this clearly and the run finishes gracefully — no crash.
- Owners can alternatively set `FREE_TIER_MODE=block` so free users get no results, or adjust `FREE_TIER_MAX_ITEMS`.

The `paywall` object on the run OUTPUT shows what was applied (`detected`, `isPaying`, `pricingTier`, `limited`, `blocked`, `freeTierMaxItems`).

### ❓ FAQ

**How fresh is the data?**
Rows are collected live at run time and streamed to the dataset immediately — what you see is what the marketplace serves at that moment. Use "newest first" sort for deal-alert freshness.

**Do I need proxies?**
The actor defaults to Apify Residential connections matched to the German marketplace. You normally do not need to change anything; if you override proxy settings, keep residential egress in Germany for best results.

**What are the rate limits?**
Keyword searches run with light parallelism plus small randomized pauses, and enrichment fans out moderately. The defaults are tuned for sustained, reliable runs — raise `searchMaxResults` rather than spawning more keywords at once.

**Why do some fields stay null?**
The marketplace does not expose seller follower counts, watch counts on cards, or a completed-sales feed. Missing fields are always `null`, never invented.

**Sold comps — what exactly do I get?**
The marketplace does not publish a per-seller completed-sales feed. Sold Item Comps gives you the closest public equivalent: a per-seller inventory snapshot with per-item sold status preserved, so you can measure sell-through and what is moving. Ask in outcome terms — "give me this seller's current sell-through picture" — and the feature delivers it.

**Why is my free run capped at 2 results?**
That's the free-plan trial described above, not a bug. Upgrade for full output.

**Why aren't buy-now / wanted ads a filter?**
Because filtering makes run volume unpredictable — a "buy-now only" run could need anywhere from one page to dozens to fill the same result count. Tagging every row keeps the number of listings (and therefore cost) predictable, and you still get complete output to slice downstream.

### 📚 Notes

- One listing = one dataset row, always. Enrichment merges into the same row.
- `searchMaxResults` defaults to 10 (1–200) so first runs finish in seconds.
- All failures surface as sanitized, human-readable log messages — runs never crash on a single bad page.

# Actor input Schema

## `enableListingSearch` (type: `boolean`):

Live keyword search across Kleinanzeigen — thrift brands, streetwear, and vintage finds. On by default and prefilled so you can click Start and get results in seconds.

## `searchKeywords` (type: `array`):

One or more search terms — German works best, e.g. "carhartt detroit jacke", "vintage levis 501", "patagonia fleece". Required when Listing Search is on.

## `searchMaxResults` (type: `integer`):

Maximum listings to return for each keyword (1–200). Default 10 — perfect for instant demo runs.

## `searchSort` (type: `string`):

How to order search results. "Newest first" is ideal for deal alerts on fresh inventory.

## `searchCategory` (type: `string`):

Narrow the search to a category using its URL slug, e.g. "kleidung-herren" (men's clothing), "mode-beauty" (fashion & beauty), "mобilitaet" uses its own slug. Copy the slug from a category page URL like /s-kleidung-herren/…/k0c160.

## `searchSize` (type: `string`):

Free-text size hint that must appear in the listing tags, e.g. M, L, XL, 48, 42x32.

## `searchCondition` (type: `string`):

Filter by item condition as offered by the marketplace's catalog filters.

## `searchMinPrice` (type: `integer`):

Minimum listing price in EUR.

## `searchMaxPrice` (type: `integer`):

Maximum listing price in EUR — pair with "Newest first" sort to catch underpriced steals fast.

## `searchLeadDetails` (type: `boolean`):

When on, every row additionally carries is\_buy\_now (fixed "Direkt kaufen" price) and is\_wanted ("Gesucht" buyer ads) tags. Every discovered listing still goes to the dataset — results are never filtered, so run volume stays predictable. Filter downstream in your own tooling. Costs nothing extra: the tags are read from the same listing card.

## `searchFetchFullDetails` (type: `boolean`):

When on, each search result stays ONE row (featureType listing\_search, detailsFetched=true) but is enriched with description, size/condition specifics, full image gallery, brand, color, and seller context. Adds a little extra time per listing. When off, you get fast search cards with price, title, tags, and location. Every discovered item is always saved — never filtered out.

## `enableListingDetails` (type: `boolean`):

Fetch the full record for specific Kleinanzeigen listings by URL or ad ID.

## `listingIds` (type: `array`):

Kleinanzeigen ad IDs, e.g. 3524930885.

## `listingUrls` (type: `array`):

Full Kleinanzeigen listing URLs (https://www.kleinanzeigen.de/s-anzeige/...).

## `enableClosetListings` (type: `boolean`):

Collect the full active inventory of any seller — track competitor stock and repricing moves. Identified by numeric seller ID.

## `sellerIds` (type: `array`):

Numeric Kleinanzeigen seller IDs (from the seller page URL, e.g. userId=33915083 → 33915083). Shared by Seller Inventory, Seller Profile, and Sold Comps.

## `sellerMaxListings` (type: `integer`):

Maximum active listings to collect per seller (1–500).

## `enableSellerProfile` (type: `boolean`):

Extract seller stats: display name, badges, active listings count, member since, and reputation when available.

## `enableSoldHistory` (type: `boolean`):

Sell-through snapshot per seller: current inventory with per-item sold status, for comps and sell-through analysis. (The marketplace does not publish a completed-sales feed — this is the closest public equivalent; see README.)

## `soldMaxItems` (type: `integer`):

Maximum inventory rows to collect per seller for comps (1–500).

## `enableScrapeByUrl` (type: `boolean`):

Paste any Kleinanzeigen URL — search results, seller inventory, category page, or single listing.

## `scrapeUrls` (type: `array`):

Any Kleinanzeigen search, seller inventory, category, or listing URL.

## `webhookUrl` (type: `string`):

Optional. Every record is always saved to the run dataset — this webhook is an ADDITIONAL real-time push. Each new row is also POSTed to this URL (Slack, Discord, Zapier, Make, n8n, custom pricing bot).

## `webhookFormat` (type: `string`):

json = full record object; slack = Slack-friendly message payload.

## `proxyConfiguration` (type: `object`):

Residential proxy recommended. Kleinanzeigen is a German marketplace — German (DE) residential egress delivers the most reliable results at scale.

## Actor input object example

```json
{
  "enableListingSearch": true,
  "searchKeywords": [
    "carhartt detroit jacke",
    "vintage levis 501",
    "patagonia fleece"
  ],
  "searchMaxResults": 10,
  "searchSort": "relevance",
  "searchCategory": "",
  "searchSize": "",
  "searchCondition": "",
  "searchLeadDetails": false,
  "searchFetchFullDetails": false,
  "enableListingDetails": false,
  "listingIds": [],
  "listingUrls": [],
  "enableClosetListings": false,
  "sellerIds": [
    "33915083"
  ],
  "sellerMaxListings": 30,
  "enableSellerProfile": false,
  "enableSoldHistory": false,
  "soldMaxItems": 30,
  "enableScrapeByUrl": false,
  "scrapeUrls": [
    "https://www.kleinanzeigen.de/s-suchanfrage.html?keywords=carhartt+jacke&sortBy=creationTime"
  ],
  "webhookUrl": "",
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}
```

# Actor output Schema

## `allResults` (type: `string`):

Full dataset for this run (every featureType).

## `overview` (type: `string`):

Core fields across features, including detailsFetched for search rows.

## `search` (type: `string`):

featureType=listing\_search only. One listing = one row; full details are merged when "Enrich with full listing details" is enabled.

## `details` (type: `string`):

featureType=listing\_details — only from the Listing Details feature (specific IDs/URLs), not from search enrichment.

## `closet_listings` (type: `string`):

No description

## `seller_profile` (type: `string`):

No description

## `sold_history` (type: `string`):

No description

## `scrape_by_url` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "enableListingSearch": true,
    "searchKeywords": [
        "carhartt detroit jacke",
        "vintage levis 501",
        "patagonia fleece"
    ],
    "searchMaxResults": 10,
    "searchSort": "relevance",
    "searchCondition": "",
    "searchLeadDetails": false,
    "searchFetchFullDetails": false,
    "enableListingDetails": false,
    "listingIds": [],
    "listingUrls": [],
    "enableClosetListings": false,
    "sellerIds": [
        "33915083"
    ],
    "sellerMaxListings": 30,
    "enableSellerProfile": false,
    "enableSoldHistory": false,
    "soldMaxItems": 30,
    "enableScrapeByUrl": false,
    "scrapeUrls": [
        "https://www.kleinanzeigen.de/s-suchanfrage.html?keywords=carhartt+jacke&sortBy=creationTime"
    ],
    "webhookFormat": "json",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2b_leads/kleinanzeigen-real-time-data-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "enableListingSearch": True,
    "searchKeywords": [
        "carhartt detroit jacke",
        "vintage levis 501",
        "patagonia fleece",
    ],
    "searchMaxResults": 10,
    "searchSort": "relevance",
    "searchCondition": "",
    "searchLeadDetails": False,
    "searchFetchFullDetails": False,
    "enableListingDetails": False,
    "listingIds": [],
    "listingUrls": [],
    "enableClosetListings": False,
    "sellerIds": ["33915083"],
    "sellerMaxListings": 30,
    "enableSellerProfile": False,
    "enableSoldHistory": False,
    "soldMaxItems": 30,
    "enableScrapeByUrl": False,
    "scrapeUrls": ["https://www.kleinanzeigen.de/s-suchanfrage.html?keywords=carhartt+jacke&sortBy=creationTime"],
    "webhookFormat": "json",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("b2b_leads/kleinanzeigen-real-time-data-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "enableListingSearch": true,
  "searchKeywords": [
    "carhartt detroit jacke",
    "vintage levis 501",
    "patagonia fleece"
  ],
  "searchMaxResults": 10,
  "searchSort": "relevance",
  "searchCondition": "",
  "searchLeadDetails": false,
  "searchFetchFullDetails": false,
  "enableListingDetails": false,
  "listingIds": [],
  "listingUrls": [],
  "enableClosetListings": false,
  "sellerIds": [
    "33915083"
  ],
  "sellerMaxListings": 30,
  "enableSellerProfile": false,
  "enableSoldHistory": false,
  "soldMaxItems": 30,
  "enableScrapeByUrl": false,
  "scrapeUrls": [
    "https://www.kleinanzeigen.de/s-suchanfrage.html?keywords=carhartt+jacke&sortBy=creationTime"
  ],
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  }
}' |
apify call b2b_leads/kleinanzeigen-real-time-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,b2b_leads/kleinanzeigen-real-time-data-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/M6npgdrUoFQycz6gN/builds/ygB4ndsoczPpAGFE3/openapi.json
