# Bol.com Product Search, Price & Stock Extractor (`dataspryva/bol-com-product-search-price-and-stock-extractor`) Actor

Searches Bol.com by keyword, category, EAN, or promotions page and returns price, rating, stock status, and seller for each product, with no login required.

- **URL**: https://apify.com/dataspryva/bol-com-product-search-price-and-stock-extractor.md
- **Developed by:** [Dataspryva](https://apify.com/dataspryva) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Bol.com Product Search, Price & Stock Extractor

Collect live product data from **Bol.com**, the largest online retailer in the Netherlands and Belgium. Search by keyword, browse a category or brand, open a product by URL, EAN barcode, or product ID, or read the current promotions feed. Every record is real data from the public shop — prices, list prices, stock, sellers, ratings, images, and optional specifications and seller offers. No login, API key, or proxy setup is needed.

### What this actor does

- **Search** one or more keywords with price, rating, condition, stock, and sponsored-product filters.
- **Browse** category, brand, series, or deals pages, with deep pagination.
- **Look up products** by direct URL, EAN-8/EAN-13, or Bol.com product ID.
- **Read promotions** from the deals hub and its category deals pages.
- **Enrich on demand:** add EAN, full description, specifications, all images, rating distribution, recent reviews, and the first page of seller offers.
- Supports the **Netherlands and Belgium** marketplaces in **Dutch and French**.
- Empty fields are omitted from each record rather than written as `null`.

### Output per product

- `productId` — Bol.com product identifier
- `ean` — EAN/GTIN barcode when the product page publishes one (details mode)
- `title`, `shortDescription`, `description`
- `brand`
- `price`, `currency`
- `listPrice` — reference price when Bol.com shows one above the current price
- `discountAmount`, `discountPercent`
- `rating`, `reviewCount`
- `ratingDistribution` — star counts when details are fetched
- `recentReviews` — up to six recent reviews when details are fetched
- `imageUrl`, `images[]`
- `productUrl`
- `seller`, `sellerId`, `sellerRating`, `soldByBol`
- `inStock`, `availability`, `condition`
- `delivery`, `deliveryDate`, `isScarce`
- `isSponsored`, `sponsor`
- `promotionLabels[]`
- `categories[]`
- `specifications` — grouped key/value specifications when details are fetched
- `offers[]`, `offerCount` — first page of seller offers, and that page's count, when offers are enabled
- `marketplace`, `language`, `sourceQuery`
- `scrapedAt` — collection timestamp

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string (select) | `search` | `search`, `productDetails`, `categoryBrowse`, or `promotions`. |
| `searchQueries` | array | `["laptop"]` | Keywords for `search`. |
| `productUrls` | array | `[]` | Product URLs, EANs, or product IDs for `productDetails`. |
| `categoryUrls` | array | `[]` | Category, brand, series, or deals URLs, or category IDs, for `categoryBrowse`. |
| `marketplace` | string (select) | `nl` | `nl` or `be`. |
| `language` | string (select) | `nl` | `nl` or `fr`. |
| `sortBy` | string (select) | `RELEVANCE` | `RELEVANCE`, `POPULARITY`, `PRICE_ASC`, `PRICE_DESC`, `RATING_ASC`, `NEW`, or `WISHLIST`. Price sorts use the emitted numeric price; `RATING_ASC` follows Bol's rating score. |
| `minPrice` | integer | – | Minimum price in EUR. |
| `maxPrice` | integer | – | Maximum price in EUR. |
| `minRating` | number | – | Minimum average rating, 0-5. |
| `condition` | string (select) | `any` | `any`, `new`, `refurbished`, or `secondhand`. |
| `inStockOnly` | boolean | `false` | Keep only products currently in stock. |
| `includeSponsored` | boolean | `true` | Keep sponsored search results. |
| `includeDetails` | boolean | `false` | Fetch product pages for EAN, description, specifications, images, and reviews. |
| `includeOffers` | boolean | `false` | Fetch the first page of seller offers for each product. |
| `maxItems` | integer | `20` | Overall product cap (1-10,000). |
| `maxPages` | integer | `0` | Page limit per query/listing; `0` uses the source's own limit. |

#### Example: search with filters

```json
{
  "mode": "search",
  "searchQueries": ["koptelefoon", "laptop"],
  "marketplace": "nl",
  "language": "nl",
  "minPrice": 50,
  "maxPrice": 300,
  "minRating": 4,
  "condition": "new",
  "inStockOnly": true,
  "sortBy": "PRICE_ASC",
  "includeDetails": true,
  "maxItems": 40
}
```

#### Example: browse a category or brand

```json
{
  "mode": "categoryBrowse",
  "categoryUrls": [
    "https://www.bol.com/nl/nl/l/laptops/4770/",
    "https://www.bol.com/be/nl/pb/hp/4997239/"
  ],
  "marketplace": "be",
  "language": "nl",
  "sortBy": "POPULARITY",
  "maxItems": 100
}
```

#### Example: product lookup by EAN or URL

```json
{
  "mode": "productDetails",
  "productUrls": ["0199251730818", "https://www.bol.com/nl/nl/p/hp-omnibook-5-16-ba1751nd-intel-core-i5-i5-1334u-laptop-406-cm-2k-16-gb-lpddr5x-sdram-1-tb-ssd-wi-fi-6-windows-11-home-zilver/9300000230842700/"],
  "includeOffers": true,
  "maxItems": 10
}
```

#### Example: current promotions

```json
{
  "mode": "promotions",
  "marketplace": "nl",
  "language": "nl",
  "maxItems": 30
}
```

### Use cases

- **Price monitoring** — track current and reference prices for a product set.
- **Assortment research** — pull a category, brand, or search niche into a clean dataset.
- **EAN catalog enrichment** — resolve barcodes to titles, brands, images, and specifications.
- **Stock and seller tracking** — see availability, delivery promises, and who is selling each item.
- **Promotion analysis** — collect the current deals feed and its category offers.

### FAQ

#### Where does the data come from?

It is read from Bol.com's publicly accessible product, search, category, and deals pages at run time. The actor is not affiliated with Bol.com.

#### Can I use it for both the Netherlands and Belgium?

Yes. Set `marketplace` to `nl` or `be`. Both Dutch and French shop languages are supported.

#### Why is `ean` missing from my search results?

Search result cards do not publish barcodes. Enable `includeDetails` to visit each product page, where the EAN is read when Bol.com publishes it.

#### How many products can one search return?

Bol.com caps a single keyword result list at 10 pages (typically 24-30 products per page, about 250-270 products). For larger runs, the actor automatically splits broad searches into narrower category slices; a category or brand page also goes much deeper.

#### Why are some fields absent from a record?

Bol.com does not publish every field for every product — for example, marketplace items may have no EAN or specifications, and new products may have no reviews yet. Absent values are omitted instead of written as null.

#### How are results sorted?

`RELEVANCE`, `POPULARITY`, `NEW`, and `WISHLIST` follow Bol.com's own ordering. `RATING_ASC` follows Bol.com's rating score, which can differ from the visible average rating. `PRICE_ASC` and `PRICE_DESC` are sorted on the emitted numeric price after duplicate products are removed.

#### Are sponsored products included?

Yes by default, with `isSponsored` and `sponsor` set. Turn `includeSponsored` off to remove them.

#### Are all seller offers returned?

Bol.com paginates its offers page. The actor returns the first page of offers for each product (currently up to 10) and `offerCount` is the count on that page, not the total across all pages.

#### How current are prices and stock?

Each run reads the live pages, so prices, delivery promises, and availability reflect the moment of collection.

#### Do I need a proxy or an account?

No. The actor connects automatically; you do not configure a proxy, cookie, login, or API key.

#### Why is the full review list not included?

Bol.com's product pages expose a rating summary and a short sample of recent reviews. The actor returns the rating distribution and up to six recent reviews when details are enabled.

# Actor input Schema

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

What to collect from Bol.com.

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

One or more keywords to search for (mode=search).

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

Bol.com product links, EAN-8/EAN-13 barcodes, or numeric product IDs (mode=productDetails).

## `categoryUrls` (type: `array`):

Bol.com listing links or numeric category IDs (mode=categoryBrowse).

## `marketplace` (type: `string`):

Which Bol.com shop to use for keyword searches and numeric category IDs.

## `language` (type: `string`):

Shop language for keyword searches and numeric category IDs.

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

Result ordering for search and browsing. Price sorts use the emitted numeric price; RATING_ASC follows Bol's rating score, not the visible average.

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

Only keep products at or above this price.

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

Only keep products at or below this price.

## `minRating` (type: `number`):

Only keep products rated at or above this value (0-5).

## `condition` (type: `string`):

Only keep products with this offer condition.

## `inStockOnly` (type: `boolean`):

Only keep products that are currently in stock.

## `includeSponsored` (type: `boolean`):

Keep sponsored (advertised) products in search and browse results.

## `includeDetails` (type: `boolean`):

Visit each product page to add EAN, full description, specifications, all images, rating distribution, and recent reviews. Slower, but more complete.

## `includeOffers` (type: `boolean`):

Add the first page of seller offers (price, shipping, condition, seller rating) for each product. Bol.com paginates offers; only the first page is returned.

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

Maximum number of products to return across the whole run.

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

Page limit per query or listing. 0 uses the source's own page limit.

## Actor input object example

```json
{
  "mode": "search",
  "searchQueries": [
    "laptop"
  ],
  "productUrls": [],
  "categoryUrls": [],
  "marketplace": "nl",
  "language": "nl",
  "sortBy": "RELEVANCE",
  "condition": "any",
  "inStockOnly": false,
  "includeSponsored": true,
  "includeDetails": false,
  "includeOffers": false,
  "maxItems": 1,
  "maxPages": 0
}
```

# Actor output Schema

## `products` (type: `string`):

Dataset containing all scraped Bol.com products.

# 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",
    "searchQueries": [
        "laptop"
    ],
    "productUrls": [],
    "categoryUrls": [],
    "marketplace": "nl",
    "language": "nl",
    "sortBy": "RELEVANCE",
    "condition": "any",
    "inStockOnly": false,
    "includeSponsored": true,
    "includeDetails": false,
    "includeOffers": false,
    "maxItems": 1,
    "maxPages": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataspryva/bol-com-product-search-price-and-stock-extractor").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",
    "searchQueries": ["laptop"],
    "productUrls": [],
    "categoryUrls": [],
    "marketplace": "nl",
    "language": "nl",
    "sortBy": "RELEVANCE",
    "condition": "any",
    "inStockOnly": False,
    "includeSponsored": True,
    "includeDetails": False,
    "includeOffers": False,
    "maxItems": 1,
    "maxPages": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("dataspryva/bol-com-product-search-price-and-stock-extractor").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",
  "searchQueries": [
    "laptop"
  ],
  "productUrls": [],
  "categoryUrls": [],
  "marketplace": "nl",
  "language": "nl",
  "sortBy": "RELEVANCE",
  "condition": "any",
  "inStockOnly": false,
  "includeSponsored": true,
  "includeDetails": false,
  "includeOffers": false,
  "maxItems": 1,
  "maxPages": 0
}' |
apify call dataspryva/bol-com-product-search-price-and-stock-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataspryva/bol-com-product-search-price-and-stock-extractor"
        }
    }
}
```

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/5o3SucGekbCXdfc83/builds/bnIPi7NeXWQiwtRsR/openapi.json
