# Kaufland Scraper — French Marketplace Products & Prices (`studio-amba/kaufland-fr-scraper`) Actor

Scrape products from the Kaufland.fr marketplace: names, prices (EUR), sellers, brands, EAN codes, ratings, images and categories. Search by keyword, category or product URLs. No login, no cookies.

- **URL**: https://apify.com/studio-amba/kaufland-fr-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 result scrapeds

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.fr Scraper

Scrape product data from the [Kaufland.fr](https://www.kaufland.fr) marketplace,
the French storefront of the Schwarz Group online marketplace (formerly
real.de) with products from Kaufland direct sales and thousands of third-party
sellers.

Search by keyword, pull a whole category, or hand it a list of product URLs. Get
back clean, structured records with prices in EUR, sellers, brands, EAN codes,
ratings, images and categories. Turn on two optional flags to also get every
competing offer on a product and the contact details each seller publishes in
its imprint (legal name, address, email, phone, VAT id). No login, no cookies.

### Why use this actor?

Kaufland runs one marketplace platform across eight European countries
(Germany, Austria, Czechia, Slovakia, Poland, Italy, France and the
Netherlands) and its French catalogue changes constantly across thousands of
independent sellers. This actor turns any keyword or category into a structured
product feed you can drop into a spreadsheet, a pricing tool, or a database.

Typical users: brands tracking how their products are priced and sold across
marketplace sellers, retailers doing competitive price monitoring, resellers
sourcing products, analysts building assortment or market-share reports, and
sales teams building lists of marketplace sellers with their published contact
details.

### What you get

- **Real marketplace prices** in EUR as numbers (not strings), plus price per
  unit (e.g. `20.98 EUR/1kg`) and strike-through / RRP where a product is on sale.
- **Seller name and seller id** for every item, or `Kaufland` for direct sales.
- **Brand, EAN, category, ratings and review counts** with high field coverage,
  because the data comes straight from Kaufland's own product API, not scraped
  HTML.
- **All product images** in full resolution.
- **Every competing offer** on a product (`fetchOffers`): price, shipping cost,
  delivery window, fulfilment type and the seller behind each offer.
- **Seller contact details** (`fetchSellerDetails`): the legal name, legal form,
  address, email, phone, fax, VAT id, register court and register number from
  the imprint each seller publishes on Kaufland, plus the seller's country.
- **No login and no cookies**. Nothing to configure beyond a keyword.

### How to scrape Kaufland.fr data

1. Add the actor to your Apify account.
2. Enter a **Search Query** (a French keyword like 'café', 'ordinateur portable', 'casque audio'), or a
   **Category ID**, or paste **Product URLs**.
3. Set **Max Results** to how many products you want.
4. Optional: turn on **Fetch all competing offers** and/or **Fetch seller
   contact details**. Both are off by default; see the sections below.
5. Run it. Download the results as JSON, CSV, Excel or feed them to an API.

Kaufland.fr sits behind Cloudflare and DataDome, so the actor routes its
requests through the [Bright Data](https://brightdata.com) Web Unlocker, which
solves the bot challenge and returns the data. You do not need your own Bright
Data account. We supply the key and the actor runs without it. The
`brightDataApiKey` input exists only if you would rather bill Bright Data usage
to your own account.

### Input

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `searchQuery` | String | No | Keyword to search the marketplace (default: `café`). Products are discovered by keyword and enriched with full data. |
| `categoryId` | Integer | No | A numeric Kaufland category id to pull instead of a keyword. Category ids appear in the `category` data of any scraped product. |
| `productUrls` | Array | No | One or more `https://www.kaufland.fr/product/<id>/` URLs to scrape directly (max 1000). |
| `maxResults` | Integer | No | Maximum number of products to return (default: 100). |
| `fetchOffers` | Boolean | No | **Off by default.** When off, a product row carries only the buy-box price and seller, not the other sellers' offers. On: adds `offers[]` with every competing offer. |
| `fetchSellerDetails` | Boolean | No | **Off by default.** When off, `seller` is only a display name. On: adds `sellerDetails` with the seller's published contact record (and one per offer seller when `fetchOffers` is also on). |
| `oneRowPerOffer` | Boolean | No | Off by default. On: one row per offer instead of one row per product (implies `fetchOffers`). |
| `maxOffersPerProduct` | Integer | No | Cap on competing offers per product (default 100, max 1000). |
| `brightDataApiKey` | String | No | Optional. Your own Bright Data Web Unlocker key, if you want the usage billed to your account. Leave empty to use ours. |
| `proxyConfiguration` | Object | No | Apify proxy settings for auxiliary requests. |

Leave everything empty and the actor runs a default `café` search, so an empty
input `{}` still returns data.

### Output

Each product row contains:

| Field | Type | Example |
|-------|------|---------|
| `name` | String | `"Café moulu DEK Intenso 6 x 250 g - Lavazza"` |
| `brand` | String | `"Lavazza"` |
| `price` | Number | `37.38` |
| `currency` | String | `"EUR"` |
| `originalPrice` | Number | Strike-through price (null if not on sale) |
| `pricePerUnit` | String | `"24.92 EUR/1kg"` |
| `discount` | String | `"-15%"` (null if not on sale) |
| `ean` | String | `"5905811988330"` |
| `sku` | String | Kaufland offer id of the buy-box offer |
| `productId` | String | `"537930269"` |
| `seller` | String | `"Schronisko_Bukowina"` |
| `sellerId` | String | `"90235878"` |
| `sellerCompanyName` | String | Registered company name of the buy-box seller |
| `inStock` | Boolean | `true`, `false`, or `null` when Kaufland does not say |
| `rating` | Number | `4.86` |
| `reviewCount` | Integer | `7` |
| `url` | String | `"https://www.kaufland.fr/product/537930269/"` |
| `imageUrl` | String | Primary product image URL |
| `imageUrls` | Array | All product image URLs |
| `category` | String | `"Cafés moulus"` |
| `scrapedAt` | String | ISO 8601 timestamp |

#### Competing offers (`fetchOffers`)

With `fetchOffers` on, each row also carries `offerCount` and `offers[]`. One
offer looks like this:

| Field | Type | Example |
|-------|------|---------|
| `offerId` | String | `"388274035566"` |
| `price` | Number | `13.59` |
| `currency` | String | `"EUR"` |
| `shipping` | Number | `3.99` (0 = free shipping) |
| `totalPrice` | Number | `17.58` (price + shipping) |
| `pricePerUnit` | String | `"135.90 EUR/1l"` |
| `condition` | String | `"new"` or `"used"` |
| `deliveryTime` | String | Delivery window as shown on the site |
| `deliveryFrom` / `deliveryTo` | String | Delivery window as ISO timestamps |
| `fulfillmentType` | String | `"seller"` (shipped by the seller) or Kaufland fulfilment |
| `sellerId` / `sellerName` | String | The seller behind the offer |
| `sellerShopUrl` | String | The seller's shop page on Kaufland |
| `isDirectSeller` | Boolean | `true` when the offer is sold by Kaufland itself |
| `returnPeriod` | String | ISO 8601 duration, e.g. `"P30D"` |
| `sellerDetails` | Object | The seller's contact record (only with `fetchSellerDetails`) |

With `oneRowPerOffer` on, the actor emits one row per offer instead: the product
fields plus a single `offer` object, and `sellerDetails` for that offer's seller.

#### Seller contact details (`fetchSellerDetails`)

With `fetchSellerDetails` on, each row carries `sellerDetails` for the buy-box
seller (and every offer carries its own `sellerDetails` when `fetchOffers` is
also on). The record is parsed from the imprint each seller publishes on
Kaufland:

| Field | Type | Example |
|-------|------|---------|
| `sellerId` | String | `"76996843"` |
| `sellerName` | String | `"Smartpanther"` |
| `legalName` | String | `"Smartpanther GmbH"` |
| `legalForm` | String | `"GmbH"` |
| `representatives` | String | Managing directors / authorised representatives |
| `address` | String | `"Rose-Ausländer-Str. 2, 74523 Schwäbisch Hall"` |
| `email` | String | `"info@smartpanther.de"` |
| `phone` | String | `"+49 97816372"` |
| `fax` | String | Fax number when published |
| `vatId` | String | `"DE301628081"` (validated country prefix + digits; null when the seller publishes no valid VAT id) |
| `registerCourt` | String | Commercial register / court |
| `registerNumber` | String | `"HRB 87821"` |
| `sellerCountry` | String | ISO code of the seller's country, e.g. `"DE"`, `"PL"`, `"CZ"` |
| `sellerCountryName` | String | Country name as Kaufland shows it |
| `sellerSince` | String | Seller since, when Kaufland publishes it |
| `shopUrl` | String | The seller's shop page on Kaufland |
| `imprintText` | String | The full imprint as plain text, for anything the fields above do not cover |

Every field is nullable. A seller with a thin imprint gives a thin record. On
the runs behind this listing, email and phone were filled on most sellers and
the VAT id on most sellers with a valid EU number; expect fill rates below 100%
and check `imprintText` for anything the parser left null.

Note that sellers are often foreign to the storefront: a Polish or Czech seller
listing on Kaufland.fr publishes a Polish or Czech address. Use `sellerCountry`
to filter.

### Example output

A real row from a live run with `fetchOffers` and `fetchSellerDetails` on
(offers trimmed to two):

```json
{
  "name": "Café moulu DEK Intenso 6 x 250 g - Lavazza",
  "brand": "Lavazza",
  "price": 37.38,
  "currency": "EUR",
  "pricePerUnit": "24.92 EUR/1kg",
  "ean": "5905811988330",
  "sku": "392646001965",
  "productId": "537930269",
  "seller": "Schronisko_Bukowina",
  "sellerId": "90235878",
  "sellerCompanyName": "Salon Smaków sp. z.o.o.",
  "inStock": true,
  "rating": 5,
  "reviewCount": 1,
  "url": "https://www.kaufland.fr/product/537930269/",
  "imageUrl": "https://media.cdn.kaufland.de/product-images/original/d04d1dfb5b8552b1d4ffccc29a691010.jpg",
  "category": "Cafés moulus",
  "offerCount": 1,
  "offers": [
    {
      "offerId": "392646001965",
      "price": 37.38,
      "currency": "EUR",
      "shipping": 4.99,
      "totalPrice": 42.37,
      "pricePerUnit": "24.92 EUR/1kg",
      "condition": "new",
      "deliveryTime": "Mi. 23. - Mo. 28. September",
      "deliveryFrom": "2026-09-23T00:00:01+02:00",
      "deliveryTo": "2026-09-28T23:59:59+02:00",
      "fulfillmentType": "seller",
      "sellerId": "90235878",
      "sellerName": "Schronisko_Bukowina",
      "sellerShopUrl": "https://www.kaufland.fr/shops/Schronisko_Bukowina/",
      "isDirectSeller": false,
      "returnPeriod": "P14D",
      "sellerDetails": {
        "sellerId": "90235878",
        "sellerName": "Schronisko_Bukowina",
        "legalName": "Salon Smaków",
        "legalForm": "SALON SMAKÓW SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
        "address": "ul. Jurgów 256/4, 34-532 Jurgów",
        "email": "sklep@schroniskobukowina.pl",
        "phone": "+48 455450048",
        "vatId": "PL7361726147",
        "registerCourt": null,
        "registerNumber": null,
        "sellerCountry": "PL"
      }
    }
  ],
  "sellerDetails": {
    "sellerId": "90235878",
    "sellerName": "Schronisko_Bukowina",
    "legalName": "Salon Smaków",
    "legalForm": "SALON SMAKÓW SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
    "address": "ul. Jurgów 256/4, 34-532 Jurgów",
    "email": "sklep@schroniskobukowina.pl",
    "phone": "+48 455450048",
    "vatId": "PL7361726147",
    "registerCourt": null,
    "registerNumber": null,
    "sellerCountry": "PL"
  },
  "scrapedAt": "2026-09-21T18:07:02.857Z"
}
```

### How it works

Kaufland's own keyword search endpoints are blocked to automated access, so the
actor works from Kaufland's public product API:

1. **Enumeration.** A keyword search finds matching product ids across the
   marketplace; a category id or a list of product URLs skips straight to known
   products.
2. **Data.** Product ids are sent in batches of 50 to Kaufland's product-tiles
   API, which returns clean JSON (prices, sellers, brands, EAN codes, ratings
   and images) with very high field coverage.
3. **Offers** (optional). One request per product returns every competing offer
   with its seller.
4. **Seller details** (optional). One request per distinct seller returns the
   published imprint, which is parsed per label into the contact fields.
   Kaufland obfuscates the published email addresses; the actor decodes them.

Long runs are migration-safe: products already written are not fetched again
after a restart, and seller records are cached within the run.

### Cost estimate

Per result cost (actor start fee plus per-result fee) depends on your plan and is shown on this
page. Bright Data usage on our key is included. Requests per product, measured
on live runs:

- **Product rows only** (default): about 0.05 requests per product (one
  search request per ~20 products plus one product-tiles request per 50).
  A run of 1,000 products is roughly 70 requests.
- **`fetchOffers`**: +1 request per product (+1 per additional 100 offers).
- **`fetchSellerDetails`**: +1 request per distinct seller. With both flags on,
  a product with 3 competing offers costs about 4 requests. Runs with both flags
  on 100 products take 10-20 minutes.
- **`oneRowPerOffer`**: the number of result rows equals the number of offers, so
  a product with 20 offers is 20 billable results.

A run's usage cost only settles after the run reports SUCCEEDED; a cost read
mid-run from a partial dataset is far too low. Size your runs with
`maxResults` and `maxOffersPerProduct`.

### Limitations

- Kaufland.fr is behind Cloudflare and DataDome; the actor reaches it through the
  Bright Data Web Unlocker (our key by default).
- Keyword search relevance and coverage depend on what is indexed publicly, so a
  keyword run returns the most relevant products rather than a guaranteed
  exhaustive list. Use `categoryId` for category-scoped pulls.
- `originalPrice` and `discount` are only present when a product is actually on
  sale.
- Seller contact fields come from what each seller publishes. The parser reads
  the imprint labels in the storefront language; a seller who fills the imprint
  unusually gets null fields (the raw text is always in `imprintText`). Kaufland
  obfuscates published email addresses and may change how; the decoding is
  tested but is the part most likely to need maintenance.
- Seller imprint data is published by the sellers under EU platform rules. You
  are responsible for using it lawfully (GDPR applies to sole traders' data).
- Data is scraped from the public marketplace and may change without notice.
  Respect the website's terms of service and use responsibly.

### Related scrapers

The same actor exists for every Kaufland marketplace country:

- [Kaufland.de Scraper](https://apify.com/studio-amba/kaufland-de-scraper) — kaufland.de German marketplace
- [Kaufland.at Scraper](https://apify.com/studio-amba/kaufland-at-scraper) — kaufland.at Austrian marketplace
- [Kaufland.cz Scraper](https://apify.com/studio-amba/kaufland-cz-scraper) — kaufland.cz Czech marketplace
- [Kaufland.sk Scraper](https://apify.com/studio-amba/kaufland-sk-scraper) — kaufland.sk Slovak marketplace
- [Kaufland.pl Scraper](https://apify.com/studio-amba/kaufland-pl-scraper) — kaufland.pl Polish marketplace
- [Kaufland.it Scraper](https://apify.com/studio-amba/kaufland-it-scraper) — kaufland.it Italian marketplace
- [Kaufland.nl Scraper](https://apify.com/studio-amba/kaufland-nl-scraper) — kaufland.nl Dutch marketplace

### Need this data on a schedule, or a custom version?

We run this scraper as a managed service for businesses: scheduled runs,
deduplication, delta detection, and delivery to your inbox, Google Sheets,
or API, maintenance included. We can also build a custom version with your
exact fields and filters, or combine multiple sources into one feed.

See [studioamba.dev/services](https://studioamba.dev/services/) or email
<hello@studioamba.dev> for a free data sample.
We maintain 300+ European web scrapers and answer within one business day.

# Actor input Schema

## `searchQuery` (type: `string`):

Keyword to search the Kaufland.fr marketplace (e.g., 'café', 'ordinateur portable', 'casque audio'). Products are discovered by keyword and enriched with the full product data.

## `categoryId` (type: `integer`):

Optional. A numeric Kaufland category id to pull products for instead of a keyword search (e.g., 5921). Category ids appear in the 'category.id' field of any scraped product.

## `productUrls` (type: `array`):

Optional. One or more Kaufland product URLs to scrape directly (https://www.kaufland.fr/product/537930269/). Up to 1000 URLs per run.

## `maxResults` (type: `integer`):

Maximum number of products to return.

## `fetchOffers` (type: `boolean`):

Off by default. When off, each product row carries only the buy-box price and seller; the other sellers' offers are NOT included. Turn on to add `offers[]` with every competing offer on the product (price, shipping, delivery window, fulfilment type, seller). Adds about 1 extra request per product (1 per 100 offers), so runs take longer and cost more per product.

## `fetchSellerDetails` (type: `boolean`):

Off by default. When off, `seller` is only the seller's display name. Turn on to add `sellerDetails` with the legal name, legal form, address, email, phone, VAT id and commercial-register data from the imprint each seller publishes on Kaufland (for the buy-box seller, and for every offer's seller when fetchOffers is also on). Adds 1 extra request per distinct seller; sellers are cached within a run. Fields a seller does not publish stay null.

## `oneRowPerOffer` (type: `boolean`):

Off by default (one row per product, with the competing offers nested in `offers[]`). Turn on to output one row per offer instead: the product fields plus a single `offer` object, and `sellerDetails` for that offer's seller when fetchSellerDetails is on. Implies fetchOffers. A product with no offers still produces one row with `offer: null`.

## `maxOffersPerProduct` (type: `integer`):

Cap on the number of competing offers collected per product when fetchOffers is on. Kaufland returns up to 100 offers per request.

## `brightDataApiKey` (type: `string`):

Optional. Your own Bright Data Web Unlocker key. You do not need one: we supply the key and the actor runs without it. Set this only if you want Bright Data usage billed to your own account. Falls back to the BRIGHT\_DATA\_API\_KEY environment variable.

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

Proxy settings. Kaufland access itself goes through the Bright Data Web Unlocker; this proxy is used for any auxiliary requests.

## Actor input object example

```json
{
  "searchQuery": "café",
  "maxResults": 20,
  "fetchOffers": false,
  "fetchSellerDetails": false,
  "oneRowPerOffer": false,
  "maxOffersPerProduct": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}
```

# Actor output Schema

## `results` (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 = {
    "searchQuery": "café",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "FR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/kaufland-fr-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 = {
    "searchQuery": "café",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "FR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/kaufland-fr-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 '{
  "searchQuery": "café",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}' |
apify call studio-amba/kaufland-fr-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/kaufland-fr-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/gx5n3ALtWPsjpSTAk/builds/ESfU4av9wF2eivJH2/openapi.json
