# Bol Scraper — Netherlands Product Prices & Ratings (`logiover/bol-netherlands-product-scraper`) Actor

Scrape Bol.com, the largest online retailer in the Netherlands and Belgium. Extract product name, price in euros, product ID, description, buyer rating and review count, image and product URL across every category. No API key required.

- **URL**: https://apify.com/logiover/bol-netherlands-product-scraper.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 results

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Bol Scraper — Netherlands Product Prices & Ratings

The biggest online retailer in the Netherlands and Belgium in rows: product name, price in euros, product ID, stock availability, buyer rating and review count, description and image — across every category.

### What does the Bol Scraper do?

This Actor collects products from **Bol.com**, the largest online retailer in the Netherlands and Belgium and the price reference most Dutch shoppers check first. You give it a category path and it returns the catalogue, one row per product, about thirty to a page.

Products are read from the structured data the site publishes for search engines rather than from the rendered tiles, which keeps the parser stable when the front end changes. One thing had to be handled carefully: the category page describes **itself** in that same block, with the combined type `["ItemList","Product"]`, carrying the category name and its price range as though it were an item on sale. Left in, that lands in the export as a product called "Laptops" priced at the cheapest laptop and drags every average down. This Actor keeps only nodes that are a product and not a list.

### Who is it for?

- **Price-monitoring and repricing teams** tracking Dutch and Belgian retail prices.
- **Brands and distributors** checking how their products are listed, priced and rated.
- **Marketplace sellers** benchmarking against Bol's own listings.
- **Market researchers** measuring price distribution and rating spread in a category.
- **Comparison sites** seeding a Benelux catalogue.
- **E-commerce analysts** watching availability and discounting over time.

### Use cases

- Track prices in a category day by day to detect discounting.
- Compare your listed price against the market spread on Bol.
- Rank products by review count to find a category's bestsellers.
- Watch stock availability flip in and out to infer demand.
- Measure the relationship between rating and price in a segment.
- Build a Benelux price index for consumer electronics.
- Feed an AI agent live Dutch retail prices for shopping questions.

### Why use this Bol Scraper?

- **The category's own self-listing filtered out**, so your averages are not poisoned. See the FAQ.
- **Price, availability and product ID at 100% fill.**
- **Ratings and review counts** where buyers have left them.
- **Descriptions stripped of HTML**, so the column is readable in a spreadsheet.
- **Any category** — pass the path straight from a Bol.com URL.
- **Keyless and login-free.**

### What data can you extract?

One row per product. Anything the source left blank comes back as `null`.

| Field | Description |
| --- | --- |
| `productId` | Bol.com product ID |
| `url` | Link to the product page |
| `title` | Full product name |
| `price` | Current price |
| `currency` | Currency, normally EUR |
| `availability` | Stock status, e.g. InStock |
| `rating` | Buyer rating out of 5 |
| `reviewCount` | Number of reviews |
| `description` | Product description, plain text |
| `imageUrl` | Product image |
| `category` | The category crawled |
| `scrapedAt` | ISO timestamp of collection |

#### Sample output

```json
{
  "productId": "9300000233102407",
  "url": "https://www.bol.com/nl/nl/p/asus-vivobook-m3607ha-sh164w/9300000233102407/",
  "title": "ASUS Vivobook S16 M3607HA-SH164W - Laptop - 16 inch",
  "price": 1099,
  "currency": "EUR",
  "availability": "InStock",
  "rating": 4.5,
  "reviewCount": 2,
  "description": "Deze ASUS Vivobook S16 wordt geadviseerd voor thuisgebruik en studie.",
  "imageUrl": "https://media.s-bol.com/9KmAg0B88BvP/DRyPXg5/1200x808.jpg",
  "category": "laptops",
  "scrapedAt": "2026-08-22T09:18:59.106Z"
}
```

### How to use the Bol Scraper

#### Option A — one category

Put the category path in **Category path**, exactly as it appears in a Bol.com URL after `/nl/nl/` — for example `l/laptops/4770`. Set **Maximum results** and run.

#### Option B — several categories

Run once per category and combine the datasets. Each row carries its `category`.

#### Option C — a daily price watch

Schedule a daily run on the same category and diff `price` by `productId` to spot changes.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `categoryPath` | string | `l/laptops/4770` | Category path as it appears in a Bol.com URL |
| `maxResults` | integer | 1000 | Stop after this many products (max 50,000) |
| `proxyConfiguration` | object | NL residential | Bol.com serves Dutch exits |

### Tips for best results

- **Copy the path from the URL**, including the numeric id: `bol.com/nl/nl/**l/laptops/4770**/`.
- **`productId` is your join key** across runs; the URL slug changes when a product is renamed.
- **Ratings appear on roughly six products in ten** — the ones with reviews. That is the source, not a gap.
- **Watch `availability`, not just price.** A product going out of stock often precedes a price move.
- **Deduplicate on `productId`.** Sponsored slots repeat the same product across pages.

### Integrations

Connect the dataset to Make, Zapier, Airbyte, Google Sheets, Slack, GitHub or any HTTP endpoint through Apify integrations, or schedule a run and push results into a warehouse with a webhook.

### API usage

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("logiover/bol-netherlands-product-scraper").call(run_input={
    "categoryPath": "l/laptops/4770",
    "maxResults": 3000,
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
rated = [r for r in rows if r["rating"]]
print(len(rated), "rated products, avg price €",
      round(sum(r["price"] for r in rated) / len(rated)))
```

### Use with AI agents (MCP)

The Actor is callable from the Apify MCP server, so an assistant can pull Dutch retail prices directly and answer product and pricing questions.

### FAQ

#### Do I need a Bol.com account or API key?

No. This Actor reads the public catalogue; there is nothing to register.

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

Up to 50,000 per run, about thirty per page. Pages are fetched several at a time, so several thousand rows take about a minute.

#### Where do I find the category path?

Browse to any category on Bol.com and copy everything after `/nl/nl/` — for example `l/koptelefoons/12609`.

#### Why would a category appear as a product?

Because Bol's structured data describes the category page using both the list type and the product type at once, complete with the category's name and its cheapest price. Any parser that simply collects "products" picks it up and reports "Laptops, €399" as an item. This Actor excludes nodes that are also a list, so only real products are exported.

#### Why do some products have no rating?

Because nobody has reviewed them yet. Roughly six in ten carry a rating and review count; the rest are genuinely unrated.

#### Does it cover Belgium as well?

The catalogue is shared across the Netherlands and Belgium. This Actor reads the Dutch storefront, where prices are quoted in euros for both markets.

#### Can I export to CSV or Excel?

Yes — every run's dataset exports to JSON, CSV, Excel, XML or JSONL.

#### How fresh is the data?

Each run reads the catalogue live, so prices are as current as Bol.com's own at the moment you run it.

#### Why did my run return zero products?

Almost always a category path that does not exist. Copy it exactly from a Bol.com URL, including the numeric identifier.

#### How often is the Actor updated?

It is monitored and fixed when the source changes. See the changelog for release history.

### Is it legal to scrape Bol.com?

Bol.com is a public retail catalogue and this Actor reads only its public category pages — no accounts, no logins, no personal data. Product names, prices and availability are commercial information published to be seen. As with any scraping, you remain responsible for how you use the data and for respecting the retailer's terms in your own jurisdiction.

### Related scrapers

- **Marktplaats Scraper** — Dutch second-hand marketplace.
- **Rozetka Scraper** — Ukrainian retail prices.
- **Hepsiburada Scraper** — Turkish retail prices.
- **Altex Scraper** — Romanian electronics with EU 30-day lowest price.

# Actor input Schema

## `categoryPath` (type: `string`):

Category path exactly as it appears in a Bol.com URL after /nl/nl/, e.g. l/laptops/4770, l/koptelefoons/12609.

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

Stop after this many products. Each page returns about 30.

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

Bol.com serves Dutch exits. A Dutch residential proxy is used automatically.

## Actor input object example

```json
{
  "categoryPath": "l/laptops/4770",
  "maxResults": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NL"
  }
}
```

# Actor output Schema

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

Every record collected in this run. Open the Dataset tab to browse, filter or export as JSON, CSV or Excel.

# 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 = {
    "categoryPath": "l/laptops/4770",
    "maxResults": 1000,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "NL"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/bol-netherlands-product-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 = {
    "categoryPath": "l/laptops/4770",
    "maxResults": 1000,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "NL",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/bol-netherlands-product-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 '{
  "categoryPath": "l/laptops/4770",
  "maxResults": 1000,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "NL"
  }
}' |
apify call logiover/bol-netherlands-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,logiover/bol-netherlands-product-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/otpjYxWlNcQ0Mxc6C/builds/x2myBdGpgg7JSONRB/openapi.json
