# Kaufland.de Scraper - Marketplace Price, Deals & Reviews (`abotapi/kaufland-de-scraper`) Actor

Scrape Kaufland.de, Germany's hypermarket and online marketplace: keyword/category/brand search or paste links. Current price, UVP was-price and discount on Angebote deals, grocery unit price, brand, breadcrumb path, EAN, marketplace seller, variant matrix, per-category specs, and native reviews.

- **URL**: https://apify.com/abotapi/kaufland-de-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 29 total users, 5 monthly users, 84.8% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 product results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Kaufland.de Scraper: Prices, Deals, Sellers & Reviews

Kaufland.de Scraper turns Kaufland.de, Germany's hypermarket and online marketplace, into structured product data. Search by keyword, category, brand and price with the site's own filters, browse Kaufland's Angebote (deals) facet, or paste product, category and search links directly. Every record carries the current price, the strike-through UVP original price with a computed discount when an item is genuinely reduced, grocery unit price (EUR per kg/l), and, on request, full product detail and native customer reviews, then export to JSON, CSV or Excel, read it through the API, or pipe it into the apps you already use.

### Why This Scraper?

- **UVP was-price and discount, never fabricated.** When a product is reduced against its manufacturer's recommended price (UVP), the current price, the strike-through original price, and the computed discount amount and percentage come back structured. A full-price item simply returns `null` for these fields.
- **A dedicated deals mode.** `specialsOnly` scrapes Kaufland's own Angebote facet directly, store-wide or scoped to a keyword and/or category.
- **Grocery unit pricing.** EUR per kg, litre or other unit comes back as a structured value, not buried inside a price string.
- **Marketplace-aware.** Kaufland.de is a multi-seller marketplace: every listing carries the selling partner's name, and full detail adds the seller's id, return period and the number of competing offers on the same listing.
- **Rich product identity on demand.** Brand and manufacturer, full breadcrumb category path, EAN/GTIN, manufacturer part number, and flattened per-category technical specifications, which vary by product type and are never hardcoded to one vertical.
- **Complete native review history.** Overall rating, review count, and every individual review with author, date, rating, title and body text, straight from Kaufland's own review system.
- **Two ways in.** Search by keyword and/or category, or paste any product, category or search link and let pagination continue automatically. Brand, price range, deals and sort filters apply in both modes. Optionally export results into Notion, Linear, Airtable or any Apify MCP connector alongside the dataset.

### Use Cases

- **Price monitoring and repricing:** track current price, UVP discount and unit price across a category or a list of competitors' listings.
- **Deal and promotion tracking:** watch Kaufland's Angebote facet, store-wide or for a specific department, for new and ending discounts.
- **Marketplace research:** compare sellers, return periods and the number of competing offers on the same product.
- **Catalog and PIM enrichment:** pull brand, breadcrumb category path, EAN/GTIN, part number and structured specifications for product matching.
- **Reputation and review analysis:** aggregate a product's full native review history, ratings and verified-purchase flags.
- **Grocery price-per-unit comparisons:** collect structured EUR per kg/l unit pricing for basket comparisons.

### Data You Get

> Sample shape: values below are illustrative placeholders, not from a live product.

| Field | Example |
| --- | --- |
| `productId` | `500000001` |
| `title` | `"Sample Coffee Machine, 1200W, Black"` |
| `url` | `"https://www.kaufland.de/product/500000001/"` |
| `image` | `"https://media.cdn.kaufland.de/product-images/400x400/sample.webp"` |
| `price` / `currency` | `54.95` / `"EUR"` |
| `originalPrice` | `79.90` (UVP was-price, `null` off deal) |
| `discountAmount` / `discountPercent` | `24.95` / `31.2` |
| `isOnSpecial` | `true` |
| `unitPrice` | `{"value": 54.95, "unit": "1kg"}` |
| `promoLabel` | `"Hammer-Preis"` (voucher or best-price badge) |
| `seller` | `"Sample-Handel"` (name only in listing, full object with `fetchDetails`) |
| `rating` / `reviewCount` | `4.7` / `331` |
| `brand` *(fetchDetails)* | `"Sample Brand"` |
| `breadcrumb` *(fetchDetails)* | `["Startseite", "Küche & Haushalt", "Haushaltsgeräte", "Kaffeevollautomaten"]` |
| `ean` / `gtin` / `mpn` *(fetchDetails)* | `"4000000000001"` / `"4000000000001"` / `"SC-1200-BK"` |
| `specifications` *(fetchDetails)* | `{"Gewicht": "3.5 kg", "Lautstärke": "65 dB", "Fernbedienung": "Ja"}` |
| `variants` *(fetchDetails)* | `[{"title": "Schwarz", "url": "https://..."}, {"title": "Weiß", "url": "https://..."}]` |
| `otherOffersInfo` *(fetchDetails)* | `{"totalNewOffers": 5, "totalUsedOffers": 3, "lowestPrice": 49.99}` |
| `voucher` *(fetchDetails)* | `{"discountAmount": 5, "discountType": "fixed", "endsAt": "2026-10-05"}` |
| `energyLabel` *(fetchDetails)* | `{"class": "A", "imageUrl": "https://..."}` |
| `reviews.averageRating` / `reviews.totalReviewCount` *(fetchReviews)* | `4.7` / `331` |
| `reviews.items[]` *(fetchReviews)* | `[{"reviewId": 7000001, "author": "hm-1234567890", "rating": 5, "date": "23.06.2026", "title": "Sample review title", "body": "Sample review text.", "text": "Sample review text.", "productId": "100000001", "productUrl": "https://www.kaufland.de/product/100000001/", "isVerifiedPurchase": true, "score": 5.9339, "translation": null}]` |

Search and category results already carry price, UVP was-price and discount, unit price, promo badge and rating without any toggle. Turning on **Fetch full product detail** adds brand, breadcrumb, EAN/GTIN, part number, flattened specifications, energy label, media gallery, the per-variant matrix and the full seller object; turning on **Fetch reviews** adds the native review history. Pasting a single product link always returns the full-detail fields, since there is no search result to fall back on, whether or not `fetchDetails` is switched on.

### How to Use

1. Pick a **mode**: `search` (keyword and/or category, with Kaufland's own filters) or `url` (paste product, category or search links).
2. In search mode, set a search keyword and/or category, then narrow with brand, price range, deals and sort. These filters also apply when you paste a category or search link in url mode.
3. Turn on **Fetch full product detail** and/or **Fetch reviews** if you need the enrichment fields, and set **Max products total** and **Max pages per search** to control run size and cost.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Basic keyword search:**

```json
{
  "mode": "search",
  "searchTerm": "kaffee",
  "maxItems": 20
}
```

**Search narrowed by category, brand and price, with deals:**

```json
{
  "mode": "search",
  "searchTerm": "kaffee",
  "category": "5921",
  "brand": "Melitta",
  "minPrice": 5,
  "maxPrice": 40,
  "specialsOnly": true,
  "sortBy": "price-asc",
  "maxItems": 30
}
```

**Category browse with full detail and review enrichment:**

```json
{
  "mode": "search",
  "category": "5801",
  "fetchDetails": true,
  "fetchReviews": true,
  "maxReviewsPerProduct": 0,
  "maxItems": 50
}
```

**Paste product, category or search links:**

```json
{
  "mode": "url",
  "urls": [
    "https://www.kaufland.de/product/496448760/",
    "https://www.kaufland.de/c/kaffeebohnen/~5801/",
    "https://www.kaufland.de/s/?search_value=kaffee&all_deals=true"
  ],
  "maxItems": 40
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/kaufland-de-scraper").call(run_input={"mode": "search", "searchTerm": "kaffee", "maxItems": 20})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(product["title"], product["price"], product["currency"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/kaufland-de-scraper').call({ mode: 'search', searchTerm: 'kaffee', maxItems: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### How Max pages and Max products total interact

**Max products total** (`maxItems`, default `20`) is a hard cap on products returned across every search, category or URL entry; values above 100000 are capped at 100000, and `0` means unlimited. **Max pages per search** (`maxPages`) has no default cap: leave it empty and the actor walks as many pages as it needs for one search, category or URL entry, still bounded by Max products total. If a storefront ever re-serves the same page of results, the actor detects the repeat and stops that search rather than paging forever, so already-collected items are always kept.

#### Link types and dataset views

In url mode you can paste three kinds of links: a product link (`/product/<id>/`), a category link (`/c/<slug>/~<id>/`) and a search link (`/s/?search_value=...`). If you leave the links field untouched, the three sample links (one search, one product, one category) are scraped, capped by Max products total. The dataset has a default products view, a details view with the full-detail fields, and a reviews view that lists each product with its nested reviews object (the dataset views cannot split a nested list into one row per review; the reviews are one list inside each product row).

Review history is capped at 500 reviews per product. When detail or reviews are requested, each product is enriched one at a time and the enrichment surcharge is charged right after that product is delivered, so you only pay for products you received.

#### Reviews-only usage and keyword filter

Set `fetchReviews` with product URLs in `urls` (url mode) to get reviews. Each review carries `text` (same as `body`), `productId` and `productUrl`. `keywordReviews` keeps only reviews whose title or text contains the keyword (case-insensitive), applied before `maxReviewsPerProduct`. Migrating from other Kaufland review tools: a `startUrlsReviews` list of product URLs is accepted as an alias for url mode with `fetchReviews` on. When only `startUrlsReviews` is sent, the shipped sample links in `urls` are ignored so only your links are scraped. Each review also carries the site's ranking `score` and, when the site provides one, a `translation` (null otherwise).

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape: the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record, not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (keyword/category with filters) or `url` (paste links). |
| `searchTerm` | string | none (prefill: `kaffee`) | Free-text keyword. Read only in search mode; ignored in url mode. |
| `category` | string | none | A Kaufland category id, e.g. `5801` (Kaffeebohnen). Read only in search mode; ignored in url mode. |
| `brand` | string | none | Only this brand/manufacturer, matched against Kaufland's own brand filter (exact match preferred, falls back to a partial match; ignored if it has no matches for this search). Applies in both search and url mode. |
| `specialsOnly` | boolean | `false` | Only Angebote (deals) items. Applies in both modes; for a pasted search-result url it's OR'd with the url's own `all_deals=true`, and for a pasted category url only this input's value is used. |
| `minPrice` | integer | none | Minimum price in EUR. Applies in both search and url mode. |
| `maxPrice` | integer | none | Maximum price in EUR. Applies in both search and url mode. |
| `sortBy` | string | `natural` | `natural`, `price-asc`, `price-desc`, `customer-reviews`, `newest-arrivals`, or `bestsellers`. Applies in both modes; a pasted url's own sort is not preserved. |
| `urls` | array | one sample search, product and category link | Product, category or search links for url mode. If you switch to url mode and leave this field untouched, those three sample links are scraped (capped by `maxItems`); clear the field or paste your own to change that. |
| `fetchDetails` | boolean | `false` | Adds brand, breadcrumb, EAN/GTIN, part number, specifications, energy label, media gallery, variant matrix and marketplace seller detail. |
| `fetchReviews` | boolean | `false` | Fetches each product's full native review history. |
| `maxReviewsPerProduct` | integer | `20` | Cap on reviews kept per product; `0` = all available, up to a ceiling of 500 per product; values above 500 are capped at 500. |
| `keywordReviews` | string | none | Keeps only reviews whose title or text contains this keyword (case-insensitive), applied before the review cap. |
| `maxPages` | integer | none (unlimited) | Cap on result pages per search/category/url entry; empty means as many pages as needed, bounded by Max products total. |
| `maxItems` | integer | `20` | Hard cap on total products returned; `0` = unlimited. |
| `proxy` | object | Residential (Germany), preset | Connection settings. A residential connection is required to reach this site. |
| `mcpConnectors` | array | none | Optional MCP connectors to also receive a summary of results. |
| `notionParentPageUrl` | string | none | Required only when a Notion connector is selected. |
| `maxNotifyListings` | integer | `50` | Cap on items sent to each connector per run. |
| `resumeFromRunId` | string | none | Run or dataset ID of an earlier run; products it already collected are skipped. |
| `incrementalMode` | boolean | `false` | Return only NEW, UPDATED and REAPPEARED products compared with the last run of the same search. |
| `stateKey` | string | auto | Names the incremental baseline; empty derives it from the search, filters and detail settings. |
| `emitUnchanged` | boolean | `false` | Also return UNCHANGED products (incremental mode only). |
| `emitExpired` | boolean | `true` | Return products no longer found after a complete scan (incremental mode only). |
| `ignoreFieldsForChanges` | array | none | Fields that must not count as a change (dotted paths allowed). `delivery.cutOffTime`, `reviews.items.score` and `reviews.items.translation` are always ignored. |

### Output Example

> Sample shape: values below are illustrative placeholders, not from a live product.

```json
{
  "productId": "500000001",
  "title": "Sample Coffee Machine, 1200W, Black",
  "url": "https://www.kaufland.de/product/500000001/",
  "image": "https://media.cdn.kaufland.de/product-images/400x400/sample.webp",
  "price": 54.95,
  "currency": "EUR",
  "originalPrice": 79.90,
  "discountAmount": 24.95,
  "discountPercent": 31.2,
  "isOnSpecial": true,
  "unitPrice": { "value": 54.95, "unit": "1kg" },
  "brand": "Sample Brand",
  "breadcrumb": ["Startseite", "Küche & Haushalt", "Haushaltsgeräte", "Kaffeevollautomaten"],
  "ean": "4000000000001",
  "gtin": "4000000000001",
  "specifications": {
    "Gewicht": "3.5 kg",
    "Lautstärke": "65 dB",
    "Fernbedienung": "Ja"
  },
  "seller": {
    "name": "Sample-Handel",
    "id": "90000001",
    "returnPeriod": "P14D"
  },
  "rating": 4.7,
  "reviewCount": 331,
  "reviews": {
    "averageRating": 4.7,
    "totalReviewCount": 331,
    "items": [
      {
        "reviewId": 7000001,
        "author": "hm-1234567890",
        "rating": 5,
        "date": "23.06.2026",
        "title": "Sample review title",
        "body": "Sample review text describing the purchase experience.",
        "text": "Sample review text describing the purchase experience.",
        "isVerifiedPurchase": true
      }
    ]
  }
}
```

### Plan Requirement

Kaufland.de blocks datacenter connections, so a residential connection is needed, which this actor selects by default (Germany). Residential access is a paid Apify feature, so a paid Apify plan is required. Without one the actor tries a backup connection and logs a notice that some pages may still be unavailable; if no page can be read the run finishes as FAILED with a message that explains why, either that the proxy connection was refused for this account (a paid plan is required), that residential proxies are unavailable on this run, or that no results page could be loaded (a connection problem, not an empty search). Check the run log for the exact message.

### FAQ

#### How much does it cost?

You pay per product returned, plus a separate surcharge, charged at most once per product, when full detail and/or review history is successfully fetched for it. This surcharge also applies to every pasted single product link, which always fetches full detail. The **Pricing** tab shows the current rates. The surcharge is charged per product right after that product is delivered (event `detail-enrichment`), so it is never charged for a product you did not receive. Use **Max products total** and **Max pages per search** to cap the cost of any run.

#### Is it legal to scrape Kaufland.de?

This actor collects only publicly available product data. You are responsible for how you use it: follow Kaufland's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Product images, brand names and review text may be subject to third-party rights.

#### Can I get only new or changed products on a schedule?

Yes. Turn on **Incremental changes for scheduled runs** (`incrementalMode`) and schedule the same search. The first run returns every product as `NEW`; later runs return only `NEW`, `UPDATED` (with `changedFields`, for example `price`) and `REAPPEARED` products. Unchanged products are suppressed and are neither returned nor charged unless you turn on `emitUnchanged`. Products that vanished from a fully scanned search come back as `EXPIRED` (`emitExpired`, on by default); this never happens when Max products or Max pages cut the scan short, or when Resume was used. Every returned row carries `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt`, and the dataset has a Changes view. Rows (including `UNCHANGED` and `EXPIRED` ones) are returned and charged like any other product row; the detail-enrichment surcharge still fires only for a delivered row that was successfully enriched. `ignoreFieldsForChanges` excludes fields (dotted paths allowed) from change detection; the per-fetch delivery cut-off countdown (`delivery.cutOffTime`) and the review ranking `score` and `translation` are always ignored. State is kept per search, filter and detail setup, or under your own `stateKey`. `resumeFromRunId` instead continues one specific interrupted run without re-returning products it already collected.

#### Why didn't my price or brand filter apply to a pasted URL?

It did, for a category or search-result link: brand, price range, deals and sort are applied server-side to every rebuilt request in both modes. Only `searchTerm` and `category` are different: those two input fields are read solely in search mode, and in url mode the equivalent values come from the pasted link itself, not from the input fields. A pasted single product link ignores all filters, since there is nothing to narrow.

#### Why did my run fail instead of returning an empty dataset?

No. If no page can be read, for example because your plan has no residential access or the connection setting was changed away from residential, the run ends as FAILED with a clear message in the log, so an empty dataset is never reported as a successful run. If the connection is lost partway through, the actor stops retrying for the rest of that run and keeps whatever was already collected; check the run log for a note about this. If the message does not explain the failure, write to <contact@abotapi.com>.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of results into Notion, Linear or Airtable.

### 🔗 Want more grocery data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🥦 <a href="https://apify.com/abotapi/rewe-de-scraper"><b>REWE.de Scraper</b></a><br>Scrape REWE Germany (rewe.de) grocery products: current price, was-price and discount...</td><td>🥦 <a href="https://apify.com/abotapi/auchan-fr-scraper"><b>Auchan France Scraper</b></a><br>Scrape Auchan.fr products: grocery, drinks, household and general merchandise. Real price...</td></tr>
<tr><td>🛒 <a href="https://apify.com/abotapi/rossmann-de-scraper"><b>ROSSMANN.de Scraper</b></a><br>Scrape ROSSMANN (rossmann.de) drugstore products: current + original strike-through price...</td><td>🥦 <a href="https://apify.com/abotapi/coles-au-scraper"><b>Coles AU Scraper</b></a><br>Scrape Coles.com.au grocery products and customer reviews. Search by keyword, browse...</td></tr>
<tr><td>🛒 <a href="https://apify.com/abotapi/obi-de-scraper"><b>OBI.de Scraper</b></a><br>Scrape OBI (obi.de) DIY/home-improvement products: current + strike-through original...</td><td>🥦 <a href="https://apify.com/abotapi/foodhero-surplus-grocery-scraper"><b>FoodHero Scraper</b></a><br>Scrape FoodHero surplus grocery deals across Canada by area, store or offer ID. Extract...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/kaufland-de-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

'search' finds products by keyword and/or category with Kaufland's own filters, including Angebote/deals items. 'url' scrapes any product, category, or search-result page URL you paste, walking pagination forward automatically.

## `searchTerm` (type: `string`):

Free-text keyword, e.g. 'kaffee' or 'klimaanlage'. Combine with Category below to narrow, or leave empty and set only Category (and/or Specials only) to browse a whole department.

## `category` (type: `string`):

A Kaufland category id, e.g. '5801' (Kaffeebohnen). Find it as the trailing number in a category page URL: kaufland.de/c/<name>/~<id>/. Narrows a keyword search, or browses the whole category when Search keyword is left empty.

## `brand` (type: `string`):

Only return products from this brand, e.g. 'Jacobs' or 'Bosch'. Matched against Kaufland's own brand filter for this search (exact match preferred, falls back to a partial match); ignored if the brand has no matching results for this search/category.

## `specialsOnly` (type: `boolean`):

Only return items currently in Kaufland's own deals facet (Angebote) -- vouchers, best-price badges, and UVP strike-through discounts. Combine with a keyword and/or category, or leave those empty to browse all current deals. Applies in both search and URL mode, but not as a plain override: for a pasted search-result url, this is OR'd with the url's own all_deals=true (turns on if either is set; a url that already carries all_deals=true can't be turned off by this input); for a pasted category url, only this input's value is used and the url's own parameters are dropped.

## `minPrice` (type: `integer`):

Only return products priced at or above this amount.

## `maxPrice` (type: `integer`):

Only return products priced at or below this amount.

## `sortBy` (type: `string`):

Order of the returned results. Applies in both search and URL mode: the input is applied to the rebuilt listing request either way, and a pasted url's own sort parameter is not preserved.

## `urls` (type: `array`):

Paste one or more Kaufland product pages (/product/<id>/), category pages (/c/<name>/~<id>/), or search-result pages (/s/?search_value=<term>). Pagination continues forward automatically from any page number already in the URL. Search keyword and Category are read from the pasted link instead of the fields above; brand, price range, Specials only and sort are still applied to category and search links. A pasted product link ignores all filters.

## `fetchDetails` (type: `boolean`):

Adds brand, full breadcrumb category path, EAN/GTIN, manufacturer part number, flattened technical specifications (varies per category), energy label, media gallery, per-variant matrix, marketplace seller detail, and competing-offer count. Current price, UVP was-price/discount, grocery unit price, and rating are already included without this toggle on search/category results.

## `fetchReviews` (type: `boolean`):

Fetch each product's full native review history: overall rating, review count, and per-review author/date/rating/title/body. Products with no reviews simply return an empty list.

## `maxReviewsPerProduct` (type: `integer`):

Cap on reviews kept per product when 'Fetch reviews' is on. 0 = all available, up to a ceiling of 500 per product; values above 500 are capped at 500.

## `keywordReviews` (type: `string`):

When 'Fetch reviews' is on, keep only reviews whose title or text contains this keyword (case-insensitive). Applied before the per-product cap. Leave empty to keep all reviews.

## `maxPages` (type: `integer`):

Stop after this many result pages per search/category/URL entry. Leave empty for as many pages as needed (bounded by Max products total).

## `maxItems` (type: `integer`):

Hard cap on total products returned across every search/category/URL entry. 0 = unlimited (still bounded by Max pages per search). Values above 100000 are capped at 100000.

## `proxy` (type: `object`):

Kaufland.de requires a residential connection, which is selected by default (Germany). Residential proxy is a paid Apify feature, so this Actor needs a paid Apify plan; free-tier runs cannot reach this site.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large pull without returning or charging for products already collected there. For recurring monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns every matching product as NEW. Later runs return only NEW, UPDATED and REAPPEARED products (a price cut, a new seller offer). Turn on Emit unchanged only when you also want unchanged rows returned. State is kept separately per search, filter and detail setup; use State key to name or share a campaign.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to derive a key automatically from the search, filters and detail settings.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. Unchanged rows are returned and charged like any other row.

## `emitExpired` (type: `boolean`):

On by default. Returns products that were present in an earlier run but are no longer found, marked EXPIRED. Only produced after a run fully scanned the tracked search (never when Max products or Max pages cut it short, or when Resume was used), and never beyond Max products.

## `ignoreFieldsForChanges` (type: `array`):

Output field names that should NOT make a product count as UPDATED, for example sellerCount or rating. Use a dotted path (for example seller.name) for a field inside a nested object. Ignored fields are still returned in the output. The per-fetch delivery cut-off countdown (delivery.cutOffTime) and the review ranking score and translation (reviews.items.score, reviews.items.translation) are always ignored.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify -> Settings -> Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "searchTerm": "kaffee",
  "specialsOnly": false,
  "sortBy": "natural",
  "urls": [
    "https://www.kaufland.de/s/?search_value=kaffee",
    "https://www.kaufland.de/product/496448760/",
    "https://www.kaufland.de/c/kaffeebohnen/~5801/"
  ],
  "fetchDetails": false,
  "fetchReviews": false,
  "maxReviewsPerProduct": 20,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": true,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

## `detail` (type: `string`):

No description

## `reviews` (type: `string`):

No description

## `changes` (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 = {
    "mode": "search",
    "searchTerm": "kaffee",
    "urls": [
        "https://www.kaufland.de/s/?search_value=kaffee",
        "https://www.kaufland.de/product/496448760/",
        "https://www.kaufland.de/c/kaffeebohnen/~5801/"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "DE"
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": true,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/kaufland-de-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 = {
    "mode": "search",
    "searchTerm": "kaffee",
    "urls": [
        "https://www.kaufland.de/s/?search_value=kaffee",
        "https://www.kaufland.de/product/496448760/",
        "https://www.kaufland.de/c/kaffeebohnen/~5801/",
    ],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "DE",
    },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": True,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/kaufland-de-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 '{
  "mode": "search",
  "searchTerm": "kaffee",
  "urls": [
    "https://www.kaufland.de/s/?search_value=kaffee",
    "https://www.kaufland.de/product/496448760/",
    "https://www.kaufland.de/c/kaffeebohnen/~5801/"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "DE"
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": true,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/kaufland-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/kaufland-de-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/eiNxLV8HALOj9Xz7u/builds/x2FqouhqKDDykyeBM/openapi.json
