# bol.com Scraper — Seller Leads (VAT, KvK, Email) & Products (`memo23/bol-com-seller-leads-scraper`) Actor

Scrape bol.com (NL + BE) seller leads and products, pure HTTP. Each seller: legal company name, VAT number (NL and BE), KvK / KBO number, registered address and seller score, plus an optional verified email. Search, category, seller or product URLs. JSON/CSV.

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

## Pricing

from $4.00 / 1,000 result rows

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

## bol.com Scraper — Seller Leads (VAT, KvK, Email) & Products

Turn **[bol.com](https://www.bol.com)**, the largest marketplace in the Netherlands and Belgium, into a **B2B lead list**. For every shop selling on bol.com the actor returns the company behind it: **legal company name, VAT number (Dutch and Belgian), KvK / KBO registration number, registered address and seller score**, plus an optional **verified contact email** found from the company's own website. Search by keyword, browse any category, or paste seller and product URLs. Set the output to products (or both) for product rows too: price, RRP, rating, sellers, and the EAN when you pass product URLs.

Pure HTTP, **no browser**, so it's fast and cheap per lead.

#### How it works

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

### Why use this bol.com scraper

- 🏢 **The company, not just the shop name.** bol.com shop names hide the real business ("PB Luxury NL" is *ParfumBudget B.V.*). You get the legal name, **VAT number**, **KvK** (NL) or **KBO ondernemingsnummer** (BE) and the registered address, straight from bol.com's own EU trader information.
- 🇳🇱🇧🇪 **Netherlands and Belgium.** Dutch VAT (`NL…B01`) and Belgian VAT (`BE0…` and the newer `BE1…`) are both captured in one `vatNumber` column. Run the Dutch store, the Belgian store, or both.
- ✉️ **Verified emails, not guesses.** bol.com shows no seller email, only a contact form. With *Find seller emails* on, the actor finds each company's own website and reads the email from its contact / terms pages. An email is delivered **only when that site also shows the company's KvK / VAT number or exact legal name**, with the source pages included. Two exceptions: an email the seller printed on its own bol.com shop page is delivered as printed, and when a shop's site can't be read without a browser, an address on that exact domain is accepted if the shop is named after the domain and the legal name contains it (shop "ParfumDeo.nl", company "ParfumDeo.nl B.V."). When the site prints its own addresses, those are the ones delivered; an address found elsewhere (search results, directories) is kept only if the site prints it too, or when the site shows no address at all.
- 👥 **Every seller of a product.** Listing pages show the buy-box and cheapest seller; optionally open each product's price overview to collect **all** shops offering it.
- 🧹 **One row per company.** Many companies run a separate NL and BE shop under one VAT. Seller leads are de-duplicated by VAT, with every shop id and name kept.
- 💸 **Pay per result, from $0.004 per row.** No proxy setup, no browser.

### Overview

bol.com has tens of thousands of third-party sellers. Under the EU Digital Services Act, bol.com publishes each business seller's trader details on its shop page. This actor collects the sellers behind any search, category or product, reads those trader details, groups shops into companies, and (optionally) finds each company's contact email.

It's built for **B2B lead generation, supplier sourcing, brand protection, reseller mapping and marketplace research** in the Benelux.

### Supported inputs

| Input | Example | What you get |
|---|---|---|
| **Search query** | `parfum` | Sellers of the matching products (bol.com shows up to 10 pages, ~240 products; set `maxItemsPerQuery` to 240 to get them all) |
| **Category URL** | `https://www.bol.com/nl/nl/l/damesparfums/12429/` | Sellers across the category (up to 500 pages, ~12,000 products, as far as `maxItemsPerQuery` allows) |
| **Seller profile URL** | `https://www.bol.com/nl/nl/v/bestbeautylux/1819543/` | That seller's company details |
| **Seller storefront URL** | `https://www.bol.com/nl/nl/w/alle-artikelen-bestbeautylux/1819543/` | That seller's products (up to `maxItemsPerQuery`) and the competing sellers on them |
| **Product URL** | `https://www.bol.com/nl/nl/p/…/9200000005228252/` (or `…/prijsoverzicht/…/9200000005228252/`) | The product (incl. EAN) and its sellers |

Dutch (`/nl/nl/`) and Belgian (`/be/nl/`, `/be/fr/`) URLs both work. Mix them freely.

Not supported:

- ❌ URLs outside bol.com
- ❌ bol.com home, brand or cart pages (only `/l/`, `/s/`, `/w/`, `/v/`, `/p/` and `/prijsoverzicht/` URLs are read)
- ❌ Start URL lists loaded from a file or link (`requestsFromUrl`); paste the URLs directly
- ❌ Anything behind a bol.com login

### Use cases

- **B2B lead generation**: build a list of Dutch and Belgian online sellers in your niche with company name, VAT, KvK and a verified email.
- **Supplier and wholesale outreach**: find the webshops selling a product category and contact the companies behind them.
- **Brand protection / MAP monitoring**: see which companies resell your brand on bol.com, under which shop names.
- **Marketplace research**: map how crowded a category is, who the top sellers are, and their seller scores.
- **Sales intelligence**: enrich your CRM with the legal entity behind a bol.com shop.

### How it works

1. **Collect sellers.** The actor walks your searches, categories and URLs and reads the seller of every product (buy-box and cheapest offer; optionally every offer from the price overview).
2. **Read the trader details.** For each unique shop it opens the shop page and reads bol.com's trader information: legal name, VAT, KvK / KBO, registered address, seller score, reviews, product count.
3. **Group into companies.** Shops sharing a VAT number become one company row.
4. **Find emails (optional).** It reads each company's own website (a site the seller links on its bol.com page, or the webshop a shop is named after; when those give no email, an AI web search looks for the site), reads the contact / terms pages, and keeps an email only when the site confirms the company's KvK / VAT / legal name.
5. **Output.** One row per seller company, one row per product, or both.

When a run has a row limit (`maxSellers`, a max cost per run, or the Free plan's 100 rows), the actor stops crawling once it has found enough shops to fill it. If those shops turn out to be fewer companies than needed (NL and BE shops of one company merge into one row), it goes back and crawls further.

### Input configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | array | — (Console prefill `["parfum"]`) | Keywords to search on bol.com. |
| `startUrls` | array | `[]` | Category, search, seller, storefront or product URLs. |
| `outputMode` | select | `sellers` | `sellers` (one row per company), `products` (one row per product) or `both`. |
| `store` | select | `nl` | Store for search queries: `nl`, `be` or `both`. |
| `maxItemsPerQuery` | integer | `100` (Console prefill `20`) | Products scanned per query / URL. More products = more sellers. |
| `maxSellers` | integer | `0` | Cap on seller rows (0 = all found). In `sellers` mode it also caps the paid email searches. It doesn't limit product rows, and in `products` / `both` mode each product row's buy-box company can be searched too. |
| `allSellersPerProduct` | boolean | `false` | Collect every seller of each product, not just buy-box + cheapest. |
| `enrichEmails` | boolean | `false` | Find each company's verified contact email and phone (paid Apify plans only; see [Pricing](#pricing)). |
| `sortBy` | select | `relevance` | `relevance`, `popularity`, `price-asc`, `price-desc`, `rating`, `newest`. |
| `minPrice` / `maxPrice` | integer | — | Price range in EUR. |
| `concurrency` | integer | `10` | Parallel page fetches (1–50; 3 on the Free plan). |

A start URL that already has its own sort or price filter keeps it.

#### Example input: seller leads with emails

```json
{
  "startUrls": [{ "url": "https://www.bol.com/nl/nl/l/damesparfums/12429/" }],
  "maxItemsPerQuery": 500,
  "outputMode": "sellers",
  "allSellersPerProduct": true,
  "enrichEmails": true
}
```

#### Example input: products with their sellers' VAT

```json
{
  "searchQueries": ["koffiebonen"],
  "store": "both",
  "outputMode": "products",
  "maxItemsPerQuery": 100
}
```

### Output overview

Each row has a `rowType`: `seller` (one per company) or `product` (one per product). Seller rows carry the full company block; product rows carry the product plus its buy-box seller's company, VAT and contact as top-level columns, and the list of all known sellers. In `both` mode the seller rows come first.

Emails and phones are only filled in with *Find seller emails* on. Without it those fields stay empty and nothing is charged for them.

#### Output sample: seller lead

```json
{
  "rowType": "seller",
  "companyName": "Best Beauty Lux B.V.",
  "vatNumber": "NL866201646B01",
  "vatCountry": "NL",
  "registrationNumber": "92875521",
  "registrationType": "KvK",
  "countryOfOrigin": "NL",
  "addressLine": "Rondeboslaan 35, 9936BJ Farmsum, NL",
  "address": { "street": "Rondeboslaan", "houseNumber": "35", "houseNumberExtension": null, "postalCode": "9936BJ", "city": "Farmsum", "country": "NL" },
  "sellerEmail": "info@bestbeautylux.nl",
  "sellerPhone": "+31 (0)854019224",
  "sellerWebsite": "https://bestbeautylux.nl",
  "emails": ["info@bestbeautylux.nl"],
  "emailSources": ["https://bestbeautylux.nl", "https://drimble.nl/bedrijf/farmsum/000058452869/best-beauty-lux-bv.html"],
  "emailSearched": false,
  "shopName": "BestBeautyLux",
  "sellerUrl": "https://www.bol.com/nl/nl/v/bestbeautylux/1819543/",
  "storefrontUrl": "https://www.bol.com/nl/nl/w/alle-artikelen-bestbeautylux/1819543/",
  "rating": 8.9,
  "reviewCount": 1166,
  "productCount": 5410,
  "activeSince": "2024-07-30T12:00:09.198139",
  "shopCount": 1,
  "retailerIds": ["1819543"],
  "shopNames": ["BestBeautyLux"],
  "discoveredVia": ["parfum"],
  "sampleProducts": [{ "productId": "9300000127460781", "title": "Lattafa Khamrah - Eau de Parfum - 100 ml", "url": "https://www.bol.com/nl/nl/p/…/9300000127460781/" }],
  "profileFetchedAt": "2026-09-23T14:02:11.512Z",
  "scrapedAt": "2026-09-24T09:15:40.118Z"
}
```

A Belgian seller looks the same, with `"vatNumber": "BE0805155230"`, `"registrationType": "KBO"` and a Belgian address.

#### Output sample: product

```json
{
  "rowType": "product",
  "productId": "9200000005228252",
  "title": "Hugo Boss Bottled 100 ml - Eau de Toilette - Herenparfum",
  "brand": "Hugo Boss",
  "ean": "0737052351100",
  "price": 48.25,
  "referencePrice": 119,
  "referencePriceLabel": "Adviesprijs",
  "rating": 4.6,
  "reviewCount": 746,
  "offerCount": 13,
  "seller": { "retailerId": "1742626", "shopName": "aayanshoppingmart", "isBol": false, "sellerUrl": "https://www.bol.com/nl/nl/v/aayanshoppingmart/1742626/" },
  "companyName": "BEX TRADE BV",
  "vatNumber": "BE1035393737",
  "sellers": [
    { "retailerId": "1742626", "shopName": "aayanshoppingmart", "price": 48.25, "condition": "New", "companyName": "BEX TRADE BV", "vatNumber": "BE1035393737" },
    { "retailerId": "1555285", "shopName": "PB Luxury NL", "price": 52.99, "condition": "New", "companyName": "ParfumBudget B.V.", "vatNumber": "NL864184293B01" }
  ],
  "sellerCount": 2
}
```

Here `sellers` holds the buy-box and cheapest seller from the listing, and `sellerCount` is its length. `offerCount` is the number of new offers on the product. With *Collect every seller of each product* on, `sellers` holds every shop offering it.

### Key output fields

| Field | Description |
|---|---|
| `rowType` | `seller` or `product`. |
| `companyName` | Legal company name ("Handelsnaam") behind the shop. |
| **`vatNumber`** | VAT number as published: Dutch `NL#########B##`, Belgian `BE0#########` / `BE1#########`, or another EU format. |
| `vatCountry` | First two letters of the VAT number. |
| `registrationNumber` · `registrationType` | KvK number (NL), KBO ondernemingsnummer (BE) or other trade register. |
| `countryOfOrigin` | Country the seller is registered in. |
| `address` · `addressLine` | Registered address, structured and as one line. |
| `sellerEmail` · `sellerPhone` · `sellerWebsite` | Primary contact. Email and phone only with *Find seller emails* on; the website is filled in when known. |
| `emails` · `phones` · `emailSources` | All contacts found, and the pages that confirmed them (the company's own site first; empty for an email printed on the bol.com shop page). |
| `emailSearched` | `true` when the paid AI email search ran for this company in this run (see [Pricing](#pricing)). On product rows it's about the buy-box seller's company. A company is charged once, even when it's on several rows. |
| `shopName` · `sellerUrl` · `storefrontUrl` · `logo` | The bol.com shop. |
| `rating` · `reviewCount` · `productCount` · `activeSince` | Seller score (0–10), reviews, assortment size, active since. |
| `ratingReviewCount` · `positiveReviewsPercentage` · `topRetailer` | Reviews the score is based on, share of positive reviews, bol.com top-seller badge. |
| `shopCount` · `retailerIds` · `shopNames` · `shops` | All bol.com shops run by this company. |
| `discoveredVia` · `sampleProducts` | Which searches or URLs found the shop, and up to 5 of its products. |
| `profileFetchedAt` | When the shop's bol.com details were read. Shop details are reused for up to 30 days, so this can be earlier than `scrapedAt`. |
| `productId` · `title` · `brand` · `price` · `referencePrice` · `ean` | Product fields (product rows). |
| `url` · `image` · `currency` · `referencePriceLabel` · `rating` · `delivery` · `sponsored` · `categories` | More product fields (the product `rating` is 0–5 stars). |
| `offersUrl` · `offerCount` | Price-overview page and number of new offers. |
| `seller` · `sellers` · `sellerCount` | Buy-box seller and every known seller of the product. |
| `sellerCompany` | The buy-box seller's company block with address (product rows). |
| `store` · `source` · `sourceUrl` · `scrapedAt` | Store (`nl` / `be`), the input that found the row, and scrape time. |

### Pricing

Pay per event:

| Event | Price | When it's charged |
|---|---|---|
| Actor start | $0.005 | Once per run (runs are capped at 1 GB memory, so always one start). |
| Result row | $0.004 | Every dataset row: one seller company or one product. |
| Published email | $0.05 | Once per seller company when a verified email is delivered. |
| Published phone | $0.03 | Once per seller company when a phone number is delivered. |
| Seller email search | $0.10 | Once per seller company when the AI web search runs, found or not. |

Emails, phones and the email search only apply with *Find seller emails* on. The free steps come first: the actor reads a site the seller links on its bol.com page, or the webshop a shop is named after (like "Haarshop.nl"), at no extra cost. When that gives no verified email (there is no such site, or the site shows none), the search runs and is charged. At most 300 searches run per run.

Search results are kept per bol.com shop for 30 days, so a shop whose company was searched in that time isn't searched, or charged for a search, again. The exceptions are a company's other shop (say its BE shop, when the NL shop was the one searched), a search that failed partway, and results from before an update to the email search. Those are searched, and charged, again.

Example: 100 seller leads with emails on, where 60 needed the AI search, 45 got an email and 30 a phone: $0.005 + 100 × $0.004 + 60 × $0.10 + 45 × $0.05 + 30 × $0.03 = **about $9.56**. The same 100 leads without emails: $0.405.

If you set a maximum cost per run, the rows and their email / phone charges are paid for first; companies that don't fit in what's left skip the search. The run stops cleanly when the budget is used up, and the end of the log (and the run's status message) says what was charged.

### FAQ

**Where does the VAT number come from?** From bol.com itself. Under the EU Digital Services Act bol.com publishes each business seller's legal name, VAT, registration number and address on its shop page. The actor reads that, so VAT and KvK are available for practically every business seller.

**What do Dutch and Belgian VAT numbers look like?** Dutch: NL + 9 digits + B + 2 digits (`NL866201646B01`). Belgian: BE + 10 digits starting with 0 or 1 (`BE0805155230`, the newer `BE1035393737`). Both land in the same `vatNumber` column as bol.com shows them, without spaces, and `vatCountry` holds the first two letters. Store the column as text, not a number, or the leading 0 is lost.

**What's the difference between KvK and KBO?** KvK (Kamer van Koophandel) is the Dutch trade register; a KvK number has 8 digits. KBO (Kruispuntbank van Ondernemingen) is the Belgian one; the ondernemingsnummer has 10 digits starting with 0 or 1, and a Belgian VAT number is the same digits with BE in front. `registrationNumber` holds the number and `registrationType` says which register it is: `KvK`, `KBO`, or `Trade register` for sellers from other countries.

**Why do some sellers have no email?** bol.com never shows seller emails, so emails come from each company's own website. Some small sellers have no website, some sites only offer a contact form, and some sites load their contact details in a way that can't be read without a browser. In testing, roughly 40–50% of seller companies got a verified email. An address that can't be tied to the company's KvK / VAT / legal name or its own domain is dropped. A run does at most 300 AI searches, and if you set a maximum cost per run, the rows and their email / phone charges are paid for first, so companies that don't fit skip the search. They aren't marked as "no email"; the next run searches them.

**Why are there fewer sellers than products?** Many products are sold by bol.com itself (not a lead, so skipped), and popular shops appear across many products. Turn on *Collect every seller of each product* to find the shops behind every offer, not just the buy-box. This matters most in categories bol.com sells itself, such as electronics and toys.

**Why is `ean` empty on some product rows?** Listing pages don't include the EAN; product pages do. Pass product URLs to get EANs.

**How many products per search?** bol.com shows at most 10 pages (~240 products) per search. Category URLs go up to 500 pages (~12,000 products), so use categories (or price ranges) for bigger coverage.

**Is there a Free plan limit?** Yes. On Apify's Free plan a run returns at most 100 rows (and reads at most 100 products per query), uses up to 3 parallel fetches, and ignores *Find seller emails*. Paid plans have no row cap.

**Do I need a proxy?** No. The actor handles bol.com's blocking itself.

**What is billed, and when?** $0.005 per run, $0.004 per row. With *Find seller emails* on, also $0.05 per company with a delivered email, $0.03 per company with a delivered phone, and $0.10 per company the AI web search runs for, found or not. See [Pricing](#pricing).

### Support

Questions, a field you'd like added, or a change on bol.com to report? Open an issue on the actor's **Issues** tab or email **muhameddidovic@gmail.com**. Response within 24 hours.

### Additional services

Need scheduled lead lists, a push to your CRM or database, extra fields, or another marketplace? Reach out and it can be tailored.

### Explore more scrapers

Looking for sellers on other marketplaces? See the rest of the [memo23 actor collection](https://apify.com/memo23) on the Apify Store, including the [Allegro.pl Scraper](https://apify.com/memo23/allegro-scraper) with Polish seller leads (NIP, company, email).

### 🤖 For AI Agents & LLM Apps

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

**Purpose:** Collects the companies selling on bol.com (NL + BE) from searches, categories, seller or product URLs. It returns legal name, VAT, KvK / KBO number, registered address, seller score and optionally a verified email, one row per company, plus product rows if requested.

**Minimal input:**

```json
{
  "searchQueries": ["parfum"],
  "maxItemsPerQuery": 20
}
```

Seller leads with emails: `{ "startUrls": [{ "url": "https://www.bol.com/nl/nl/l/damesparfums/12429/" }], "outputMode": "sellers", "allSellersPerProduct": true, "enrichEmails": true }`.

**Output:** seller rows (`rowType: "seller"`): companyName, vatNumber, vatCountry, registrationNumber, registrationType, countryOfOrigin, address, addressLine, sellerEmail, sellerPhone, sellerWebsite, emails, phones, emailSources, emailSearched, shopName, sellerUrl, storefrontUrl, rating, ratingReviewCount, reviewCount, positiveReviewsPercentage, topRetailer, productCount, activeSince, logo, shopCount, retailerIds, shopNames, shops, discoveredVia, sampleProducts, profileFetchedAt, scrapedAt. Product rows (`rowType: "product"`): productId, url, title, brand, ean, price, currency, referencePrice, referencePriceLabel, rating, reviewCount, image, delivery, sponsored, categories, offersUrl, offerCount, seller, companyName, vatNumber, vatCountry, registrationNumber, registrationType, countryOfOrigin, addressLine, sellerEmail, sellerPhone, sellerWebsite, sellerCompany, emailSearched, sellers, sellerCount, source, sourceUrl, store, scrapedAt.

**Behaviors an agent should know:**

- `outputMode`: `sellers` (default, one row per company de-duplicated by VAT), `products`, or `both` (distinguish by `rowType`; seller rows first).
- Search is capped by bol.com at 10 pages (~240 products); category URLs reach 500 pages. More products scanned = more sellers found.
- `allSellersPerProduct: true` collects every seller of each product (slower, more leads).
- `enrichEmails: true` adds verified emails and phones for part of the companies (partial coverage); emails are never guessed. With it off, email and phone fields stay empty.
- `maxSellers` caps seller rows. In `sellers` mode that also caps the paid email searches; in `products` and `both` modes each product row's buy-box company is searched as well, so cap those runs with `maxItemsPerQuery` or a max cost per run.
- Products sold by bol.com itself (`seller.isBol: true`) carry no company data.
- Billing (pay per event): $0.005 per run start, $0.004 per row, $0.05 per company with a delivered email, $0.03 per company with a delivered phone. With `enrichEmails`, also $0.10 per company the AI web search runs for, found or not (at most 300 per run; free site reads are not billed). `enrichEmails` works on paid Apify plans only; Free-plan runs are capped at 100 rows.

### ⚠️ Disclaimer

This actor extracts **publicly available** information from bol.com: product data and the business-seller details that bol.com publishes under EU trader-transparency rules (Digital Services Act), plus contact details that sellers publish on their own public websites. It does not log in or bypass paywalls. Business contact data can still be personal data under the GDPR (for example a sole trader's email), so you are responsible for having a lawful basis and using it compliantly, especially for outreach, alongside bol.com's Terms of Service. This tool is intended for legitimate purposes such as B2B lead generation, supplier sourcing, brand protection and market research.

### SEO Keywords

bol.com scraper, bol.com seller scraper, bol.com seller leads, bol.com sellers list, bol.com verkopers lijst, bol.com VAT number, BTW-nummer bol.com verkoper, bol.com KvK, KBO nummer, ondernemingsnummer, bol.com verkoper, bol.com leads, bol.com lead generation, bol.com B2B leads, bol.com email scraper, bol.com company data, bol.com retailer scraper, bol.com product scraper, bol.com API, scrape bol.com, Netherlands marketplace sellers, Belgium marketplace sellers, Dutch webshop leads, Benelux B2B leads, KvK scraper, BTW nummer, Apify bol.com.

# Actor input Schema

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

Keywords to search on bol.com. Each keyword runs its own crawl. bol.com shows at most 10 pages (~240 products) per search, so for bigger coverage use category URLs.

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

Direct bol.com URLs, mixed freely: category (bol.com/nl/nl/l/…), search (…/s/?searchtext=…), seller profile (…/v/…), seller storefront with all its products (…/w/…) or product (…/p/… or its price overview …/prijsoverzicht/…). Netherlands (/nl/nl/) and Belgium (/be/nl/, /be/fr/) both work. Category URLs go up to 500 pages (~12,000 products). A page=N parameter is respected as the start page. Paste the URLs directly; lists loaded from a file or link aren't supported.

## `outputMode` (type: `string`):

Seller leads: one row per seller company (deduplicated by VAT, since one company often runs a separate NL and BE shop). Products: one row per product, with its seller's company, VAT and contact attached. Both: product rows and seller rows in one dataset (tell them apart by rowType).

## `store` (type: `string`):

Which bol.com store the search queries run on. Start URLs always use the store in their own URL.

## `maxItemsPerQuery` (type: `integer`):

How many products to scan per search query or listing URL. Every product names the shops selling it, so more products means more seller leads.

## `maxSellers` (type: `integer`):

Maximum seller rows in the output (0 = every seller found). Only the first N companies are output and, with Find seller emails on, searched for an email; the crawl stops once it has found enough shops. Doesn't limit product rows: in Products or Both mode, each product row's buy-box company is searched too. On Apify's Free plan a run returns up to 100 rows.

## `allSellersPerProduct` (type: `boolean`):

Listing pages show the buy-box seller and the cheapest seller of each product. Turn this on to also open every product's price overview and collect ALL shops offering it. More leads, but one or two extra requests per product (slower).

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

bol.com shows no seller email, only a contact form. With this on, the actor looks for each company's own website and reads the email and phone from its contact or terms pages. An email is delivered only when that site also shows the company's KvK / VAT number or legal name (see the README for the few exceptions). Coverage is partial: in testing, roughly 40–50% of seller companies. Billing: $0.05 per company that gets an email and $0.03 per company that gets a phone. The free steps come first (a site linked on the seller's bol.com page, or a shop named after its webshop like "Haarshop.nl"). When they give no verified email, an AI web search looks for the company's site: $0.10 per company searched, whether it finds an email or not. At most 300 searches per run; set a max cost per run to cap it. In Products or Both mode, each product row's buy-box seller is covered too, whatever maxSellers is. With this off, no email or phone is delivered or charged. Paid Apify plans only; on the Free plan this setting is ignored.

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

Order of search, category and seller-storefront results. A start URL that already has its own sort keeps it.

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

Only products at or above this price. A start URL that already has a price filter keeps it.

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

Only products at or below this price. A start URL that already has a price filter keeps it.

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

How many pages to fetch in parallel (1–50; 3 on the Free plan).

## Actor input object example

```json
{
  "searchQueries": [
    "parfum"
  ],
  "startUrls": [],
  "outputMode": "sellers",
  "store": "nl",
  "maxItemsPerQuery": 20,
  "maxSellers": 0,
  "allSellersPerProduct": false,
  "enrichEmails": false,
  "sortBy": "relevance",
  "concurrency": 10
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `sellers` (type: `string`):

No description

## `products` (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": [
        "parfum"
    ],
    "startUrls": [],
    "maxItemsPerQuery": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/bol-com-seller-leads-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": ["parfum"],
    "startUrls": [],
    "maxItemsPerQuery": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/bol-com-seller-leads-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": [
    "parfum"
  ],
  "startUrls": [],
  "maxItemsPerQuery": 20
}' |
apify call memo23/bol-com-seller-leads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/bol-com-seller-leads-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/G506e12CBk4eq6VaS/builds/KvmzzfPiYP40HGW33/openapi.json
