# Kaufland Seller Contact Scraper — Emails, Phone, VAT (`memo23/kaufland-sellers-scraper`) Actor

Turn any Kaufland search, product or shop URL into a lead list of the third-party sellers — legal name, address, VAT, phone and email from the impressum. Germany, Austria, Czechia, Slovakia, Poland, France and Italy. Every offer, not just the buy-box. Pure HTTP. JSON/CSV.

- **URL**: https://apify.com/memo23/kaufland-sellers-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 seller scrapeds

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

## Kaufland Seller Contact Scraper — Emails, Phone, VAT

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/logo-kaufland-sellers.png" alt="Kaufland Seller Contact Scraper" width="160" />
</p>

Turn any Kaufland.de keyword, product page or shop URL into a clean list of the **third-party sellers** behind those products — with the legal name, address, VAT, phone and email Kaufland publishes on each seller's impressum.

One unique seller row per shop. Every competing offer, not just the buy-box. Pure HTTP, no browser. JSON or CSV.

### Why Use This Scraper?

- **Companies, not products.** Most Kaufland scrapers return catalog rows. This one returns the businesses selling them — the people you actually want to reach.
- **Every offer, not just the buy-box.** The product offers API returns all competing sellers in one call. The on-site "Weitere Angebote ansehen" button is UI only.
- **Impressum-grade contact.** German TMG / DSA listing: legal business name, address, email, phone, VAT and trade-register number when the seller published them.
- **Emails deobfuscated.** Kaufland prefixes published emails with a zero-width character plus a decoy letter. This actor strips that so you get `info@shop.de`, not `jinfo@shop.de`.
- **Same shape as the Amazon seller actor.** Keyword or URL in, one row per unique seller out. Mix search queries with product, shop and impressum URLs in one run.
- **Opt-in email enrichment.** For the few shops whose impressum has no email, resolve the legal name to a company website and scan it for a contact address.

### Overview

Built for B2B lead generation, supplier discovery, brand-protection and competitor research on Kaufland **Germany, Austria, Czechia, Slovakia, Poland, France and Italy**. Search queries use the `country` input. A pasted URL uses the country in its host.

The dataset is **seller-shaped**. A search query, a product URL or a shop URL all resolve to unique seller rows — never one row per product and never one row per offer. If the same shop appears on three COSRX products, you get one row and `sourceProductIds` lists every product that led there.

This is not a product scraper. Titles, prices, EAN and stock are not in the output.

### Supported Inputs

#### URL types

| URL type | Pattern | Example |
|---|---|---|
| Search results | `/s/?search_value=` | `https://www.kaufland.de/s/?search_value=cosrx` |
| Product page | `/product/{id}/` | `https://www.kaufland.de/product/407375906/` |
| Shop storefront | `/shops/{name}/` | `https://www.kaufland.de/shops/Smartpanther/` |
| Seller impressum | `/shops/{name}/profile/?id_seller=` | `https://www.kaufland.de/shops/ROYALUXY/profile/?id_seller=84822966&type=imprint` |

#### Copy-pasteable startUrls

```json
{
  "startUrls": [
    { "url": "https://www.kaufland.de/s/?search_value=cosrx" },
    { "url": "https://www.kaufland.de/product/407375906/" },
    { "url": "https://www.kaufland.de/shops/Smartpanther/" }
  ]
}
```

#### Keyword / search mode

```json
{
  "searchQueries": ["cosrx", "phone case"],
  "maxItems": 50
}
```

`searchQueries` and `startUrls` can run together. Each source is classified by path; you do not pick a mode.

#### Unsupported inputs

- Seller cockpit / login URLs
- Shortened or redirect URLs that do not land on `kaufland.de`, `.at`, `.cz`, `.sk`, `.pl`, `.fr` or `.it`
- Product-catalog export (use a product scraper)

### Use Cases

| Audience | Use case |
|---|---|
| **Outbound / SDR teams** | Build email-and-phone lists of Kaufland.de sellers in a niche or brand. |
| **Sourcing / procurement** | Find the legal entities behind a product, with VAT and trade-register numbers. |
| **Brand protection** | Enumerate every third-party shop offering a given product id, buy-box and beyond. |
| **Marketplace intelligence** | Map who sells a brand, from which country, and under which legal name. |
| **Agencies** | Deliver a client-ready seller contact file without writing a scraper. |

### How It Works

![How the Kaufland Seller Contact Scraper works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-kaufland-sellers.png)

1. **Input** — paste search queries and/or Kaufland.de URLs. Each URL is classified as search, product, shop or impressum.
2. **Find products** — search and shop pages yield product ids; a product URL is used as-is.
3. **Read every offer** — `GET /api/pdp-frontend/v1/{productId}/offers` returns all competing sellers in one JSON payload.
4. **Parse the impressum** — `GET /api/pdp-frontend/v1/{sellerId}/seller-info` carries `legalData.imprint`. Emails are deobfuscated.
5. **Deduplicate** — one row per unique seller. Optional website scan fills `contactEmail` only when the impressum had no email.

### Input Configuration

| Field | Type | Required | Notes |
|---|---|---|---|
| `searchQueries` | `array<string>` | no (or URLs) | Brand or keyword searches. Example: `["cosrx"]`. Run on the `country` storefront. |
| `country` | `string` | no | Storefront for the searches: `de`, `at`, `cz`, `sk`, `pl`, `fr`, `it`. Default `de`. Start URLs take their country from the host instead. |
| `startUrls` | `array<{ url }>` | no (or queries) | Search, product, shop or impressum URLs on any supported Kaufland country host, mixed freely. |
| `maxItems` | `integer` | no | Max sellers per search query / start URL. Two searches at `50` return up to `100` total. Prefill `50`. Products to inspect are auto-derived; total spend is bounded by the run's max-charge limit. |
| `enrichEmails` | `boolean` | no | Opt-in website scan for shops with no impressum email. Default `false`. |
| `qualifyByPayment` | `boolean` | no | Requires `enrichEmails`. Flags sites that take payments online. Default `false`. |
| `concurrency` | `integer` | no | Parallel fetches, `1`–`20`. Default `8`; clamped to the run's memory. |

Need at least one of `searchQueries` or `startUrls`.

#### Common scenarios

**1. Brand keyword → seller leads**

```json
{
  "searchQueries": ["cosrx"],
  "maxItems": 50,
  "enrichEmails": false
}
```

**2. Every seller on one product**

```json
{
  "startUrls": [{ "url": "https://www.kaufland.de/product/407375906/" }],
  "maxItems": 25
}
```

**3. Mixed URLs + enrichment**

```json
{
  "startUrls": [
    { "url": "https://www.kaufland.de/s/?search_value=cosrx" },
    { "url": "https://www.kaufland.de/shops/Smartpanther/" }
  ],
  "maxItems": 80,
  "enrichEmails": true
}
```

### Output Overview

Each dataset item is **one unique Kaufland.de seller**. Search, product and shop starts all emit this same row shape.

- **Identity** — seller id, shop name, storefront URL, impressum URL
- **Legal** — business name, address, country, VAT, trade-register number, full imprint text
- **Contact** — published email (deobfuscated) and phone when the impressum has them
- **Provenance** — source product ids and the URL that discovered the seller
- **Optional enrichment** — `contactEmail` / `contactWebsite` when `enrichEmails` is on and the impressum had no email

Sparse fields stay `null` when the seller did not publish them. That is a gap on Kaufland, not a dropped parse.

### Output Samples

#### Product start (`/product/407375906/`)

```jsonc
{
  "sellerId": "48748000",
  "marketplace": "kaufland.de",
  "sellerUrl": "https://www.kaufland.de/shops/medpak_shop/profile/?id_seller=48748000&type=imprint",
  "sellerName": "medpak_shop",
  "storefrontUrl": "https://www.kaufland.de/shops/medpak_shop/",
  "isBusinessSeller": true,
  "businessName": "NMM sp. z o.o.",
  "registrationNumber": "0000982292",
  "vatNumber": "PL6762621979",
  "phoneNumber": "+48 123120554",
  "email": "info@medpak.shop",
  "businessAddress": "Bocheńska 3/17",
  "addressCountryCode": "PL",
  "sourceProductIds": ["407375906"],
  "sourceUrl": "https://www.kaufland.de/product/407375906/",
  "scrapedAt": "2026-09-21T12:24:44.496Z",
  "contactEmail": "info@medpak.shop"
}
```

#### Search start (`cosrx`)

Same seller shape. `sourceUrl` is the search page; `sourceProductIds` lists the product(s) that surfaced the shop.

```jsonc
{
  "sellerId": "76996843",
  "marketplace": "kaufland.de",
  "sellerName": "Smartpanther",
  "businessName": "Eduard Dutt",
  "email": "info@smartpanther.de",
  "phoneNumber": "+49 97816372",
  "vatNumber": "DE301628081",
  "businessAddress": "Rose-Ausländer-Str. 2",
  "addressCountryCode": "DE",
  "sourceProductIds": ["509191334"],
  "sourceUrl": "https://www.kaufland.de/s/?search_value=cosrx"
}
```

### Key Output Fields

#### Identity

- `sellerId`, `sellerName`, `marketplace` (`kaufland.de`, `.at`, `.cz`, `.sk`, `.pl`, `.fr` or `.it`)
- `storefrontUrl`, `sellerUrl` (impressum), `isBusinessSeller`

#### Legal / impressum

- `businessName`, `businessAddress`, `addressLines`, `addressCountryCode`
- `vatNumber`, `registrationNumber`, `imprint`

#### Contact

- `email` — published impressum email, deobfuscated
- `phoneNumber` — published impressum phone
- `contactEmail` / `contactWebsite` — filled by opt-in enrichment, or a copy of `email` when one was already on the page

#### Provenance

- `sourceProductIds`, `sourceUrl`, `scrapedAt`

### Pricing

Pay-per-event. A seller row is always billed. Email and phone are extra, and only when that field is actually present.

| Event | When | Price |
|---|---|---|
| Actor start | Once per GB of run memory | $0.005 |
| Seller scraped | Every unique seller row | $0.004 |
| Published email | Impressum contains an email | $0.002 |
| Published phone | Impressum contains a phone | $0.002 |
| Enriched email | Opt-in website scan found an email the impressum lacked | $0.002 |

A seller with email + phone costs $0.008. A seller with neither contact field costs $0.004. Published Kaufland emails are never billed as enrichment.

### FAQ

#### Which Kaufland URLs are supported?

`www.kaufland.{de,at,cz,sk,pl,fr,it}` search (`/s/?search_value=`), product (`/product/{id}/`), shop (`/shops/{name}/`) and impressum (`/profile/?id_seller=`) URLs. Login pages are skipped.

#### Do I get product rows or seller rows?

Seller rows only. A product URL still emits one row per unique shop offering that product.

#### Will every seller have an email and a phone?

Most commercial shops publish both. Some impressums only have a name and address. VAT is also optional — a few EU sellers leave it off the page. Empty fields are not billed.

#### Does "view more sellers" need a browser?

No. The offers API returns the full competing-seller list.

#### What does a shop URL actually scrape?

The shop is resolved to its seller id. Listings on that shop can also surface competing offer merchants, the same way a product page does. Cap the run with `maxItems` if you only want the shop itself.

#### Are emails already on Kaufland charged as enrichment?

No. Impressum emails bill as `seller-email`. The `contact-email` event fires only when enrichment is on and the website scan finds an address the impressum lacked.

#### Other Kaufland countries?

Yes. `country` selects the storefront for search queries: `de`, `at`, `cz`, `sk`, `pl`, `fr`, `it`. A start URL ignores that field and uses its own host.

#### Can I mix search queries and URLs?

Yes. Each source is classified on its own.

### Support

Found a bug or need a field added? Open an issue on the actor's [Issues tab](https://apify.com/memo23/kaufland-sellers-scraper/issues).

### Additional Services

Need another marketplace in the same seller-row shape, a custom export, or a scheduled monitor on a brand? I do tailored work — open an issue or reach me via the [memo23 store profile](https://apify.com/memo23).

### Explore More Scrapers

- [**Amazon Seller Contact Scraper — Emails, Phone, VAT & Ratings**](https://apify.com/memo23/amazon-sellers-scraper) — the same one-row-per-seller pipeline across 18 Amazon marketplaces
- More e-commerce, directory and lead-generation actors on the [memo23 store profile](https://apify.com/memo23)

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/kaufland-sellers-scraper`).

**Purpose:** Turns a Kaufland keyword, product page, shop URL or impressum URL into one row per unique third-party seller with the published impressum (legal name, address, VAT, phone, email) on de, at, cz, sk, pl, fr and it.

**Minimal input:**

```json
{
  "searchQueries": ["cosrx"],
  "maxItems": 25
}
```

URL mode: `{ "startUrls": [{ "url": "https://www.kaufland.de/product/407375906/" }], "maxItems": 25 }` — accepts search (`/s/?search_value=`), product (`/product/{id}/`), shop (`/shops/{name}/`) and impressum (`/profile/?id_seller=`) URLs.

**Output:** one row per unique seller — sellerId, marketplace, sellerUrl, sellerName, storefrontUrl, isBusinessSeller, businessName, registrationNumber, vatNumber, phoneNumber, email, businessAddress, addressLines, addressCountryCode, imprint, sourceProductIds, sourceUrl, scrapedAt, plus contactEmail / contactWebsite when `enrichEmails` is on.

**Behaviors an agent should know:**

- `maxItems` is per search / URL; the run total is `maxItems × number of sources`, so raise it for deeper pulls or lower it to cap spend.
- `startUrls` run in addition to `searchQueries`. Host must be a Kaufland storefront (`de`, `at`, `cz`, `sk`, `pl`, `fr`, `it`). Search queries use `country` (default `de`).
- Output is seller-shaped, not product-shaped. Duplicate shops collapse to one row.
- `enrichEmails: true` is opt-in and only fills sellers with no impressum email.
- Billing: $0.004 per seller row, $0.002 per published email, $0.002 per published phone; enrichment $0.002 only when a missing email is found off-site.
- Supported hosts: kaufland.de, .at, .cz, .sk, .pl, .fr, .it. Anything else is skipped.

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Kaufland Dienstleistung GmbH & Co. KG, Kaufland Stiftung & Co. KG, Schwarz Gruppe, or any of their subsidiaries. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available Kaufland storefront pages and public product/seller JSON — no authenticated endpoints, seller-cockpit data, or content behind a login wall. Users are responsible for ensuring their use complies with Kaufland's Terms of Service, applicable data-protection law (GDPR, ePrivacy, CCPA), and any marketing / anti-spam rules that apply to how they contact the businesses they find. You are responsible for how you use the scraped data.

### SEO Keywords

kaufland scraper, kaufland.de scraper, kaufland seller scraper, kaufland seller email, kaufland impressum scraper, kaufland marketplace sellers, kaufland contact scraper, kaufland VAT number, kaufland händler kontaktdaten, kaufland seller phone, kaufland lead generation, kaufland supplier scraper, kaufland third-party sellers, marketplace seller contact scraper, german marketplace leads, B2B seller email scraper, ecommerce seller intelligence, kaufland JSON export, kaufland CSV export

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords or brand names to search. Each keyword runs on the storefront selected in country (default de). The unique sellers behind the returned products are then scraped. Valid values: non-empty strings. Example: \["cosrx", "phone case"]. Default: none (use startUrls instead).

## `startUrls` (type: `array`):

Direct Kaufland URLs, mixed freely with search queries. Host picks the country: kaufland.de, .at, .cz, .sk, .pl, .fr or .it. Accepted: search (/s/?search\_value=…), product (/product/{id}/), shop (/shops/{name}/) or impressum (/shops/{name}/profile/?id\_seller=…). Other hosts are skipped. Example: \[{"url":"https://www.kaufland.de/product/407375906/"}]. Default: empty.

## `country` (type: `array`):

Which Kaufland storefronts the search queries run on. Pick one or more — each query is scraped on every selected country in the same run, so \["cosrx"] on \[de, at] is two searches. Start URLs ignore this — their country is taken from the URL host. Valid: de, at, cz, sk, pl, fr, it. Default: \["de"].

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

Maximum unique sellers to scrape for EACH search query, per country, or each start URL. One query on two countries with this set to 50 returns up to 100 sellers total. The actor auto-inspects enough products per search to reach this number, and each product contributes every competing seller (not just the buy-box). Total spend is still bounded by the run's max-charge limit (and a free-tier cap for free users). Valid: integer ≥ 1. Example: 50. Prefill: 50.

## `enrichEmails` (type: `boolean`):

When true, sellers whose Kaufland impressum has no email are resolved by legal business name to a company website and that site is scanned for contact emails. Best-effort; adds latency. Emails already published on Kaufland stay on the row and are never billed as enrichment. Valid: true / false. Default: false.

## `qualifyByPayment` (type: `boolean`):

Requires enrichEmails=true. Reuses the pages already fetched for email discovery and looks for payment processors / e-commerce platforms. Adds takesPayments, paymentProcessors, stripeLiveKey and paymentConfidence. Valid: true / false. Default: false.

## `concurrency` (type: `integer`):

How many pages / API calls to fetch in parallel. Automatically clamped to what the run's memory can safely hold — raise memory to go faster. Valid: integer 1–20. Example: 8. Default: 8.

## Actor input object example

```json
{
  "searchQueries": [
    "cosrx"
  ],
  "startUrls": [],
  "country": [
    "de"
  ],
  "maxItems": 50,
  "enrichEmails": false,
  "qualifyByPayment": false,
  "concurrency": 8
}
```

# 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 = {
    "searchQueries": [
        "cosrx"
    ],
    "startUrls": [],
    "country": [
        "de"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/kaufland-sellers-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 = {
    "searchQueries": ["cosrx"],
    "startUrls": [],
    "country": ["de"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/kaufland-sellers-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 '{
  "searchQueries": [
    "cosrx"
  ],
  "startUrls": [],
  "country": [
    "de"
  ],
  "maxItems": 50
}' |
apify call memo23/kaufland-sellers-scraper --silent --output-dataset

```

## MCP server setup

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