bol.com Scraper - Products, Prices, Offers, Reviews avatar

bol.com Scraper - Products, Prices, Offers, Reviews

Pricing

from $1.00 / 1,000 product scrapeds

Go to Apify Store
bol.com Scraper - Products, Prices, Offers, Reviews

bol.com Scraper - Products, Prices, Offers, Reviews

Scrape bol.com products: title, price, list price and discount, EAN, brand, images, condition, delivery, full specifications, ratings with distribution, individual reviews, every offer with seller name and rating, and refurbished prices. Search by keyword with filters, or paste product URLs.

Pricing

from $1.00 / 1,000 product scrapeds

Rating

5.0

(1)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

2

Bookmarked

112

Total users

48

Monthly active users

4 days ago

Last modified

Share

Bol.com Scraper: Products, Prices, Offers and Reviews

Bol.com Scraper turns Bol.com, the largest online store in the Netherlands and Belgium, into a clean product data feed. Get price, list price and discount, brand, EAN, full specifications, images, condition, delivery estimate, rating with the full review distribution, individual reviews, every seller offer, and refurbished or second-hand pricing. Search by keyword with price, rating, condition and sort filters, or paste product and result-page links, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • One record, most of what you need. Every product carries price, list price, discount, currency, brand, category path, condition, delivery estimate, rating summary, image and seller without turning anything on.
  • Full detail on demand. Turn on Fetch full product details to add the complete specification list (including EAN), the full description, every product image, the full review list with star distribution, seller rating, product weight, and refurbished or second-hand offers.
  • Six filters before anything is collected. Price band, minimum rating, condition, sponsored-only and in-stock-only narrow results before they are scraped or charged, on top of six sort orders.
  • Two ways in. Search mode builds queries from keywords, or paste product and search-result URLs directly in URL mode.
  • Bol.com's own deal pages. An optional specials source adds the storewide deals page or the clearance page alongside your keywords, and each product carries real was-price, savings and promo-label fields straight from that listing.
  • One finite cap. Max items bounds a run's size and cost; page depth is unlimited unless you set it.
  • Built for schedules. Incremental mode returns only new, updated and reappeared products on repeat runs, and Resume continues one interrupted crawl without re-collecting or re-paying for what it already has.

Use Cases

  • Price trackers and deal hunters: watch prices, discounts and Bol.com's own specials pages on a recurring schedule.
  • E-commerce and marketplace analysts: compare pricing, ratings and seller performance across categories.
  • Retail catalog teams: pull full specifications, EAN codes and every product image to enrich a catalog.
  • Review and reputation research: collect the full review list and star distribution per product.
  • Resellers and price-comparison tools: track refurbished and second-hand offers alongside new-condition pricing.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
productId"9300000012345"
title"Voorbeeld Draadloze Hoofdtelefoon met Noise Cancelling, Zwart"
brand"Voorbeeldmerk"
price / currency279.0 / "EUR"
list_price / discount_percentage349.99 / 20
condition"new"
ean"0000000000000"
category / categoryHierarchy"Koptelefoons" / ["Elektronica", "Audio", "Koptelefoons"]
rating / reviewCount4.6 / 812
ratingDistribution{"fiveStar": 600, "fourStar": 150, "threeStar": 40, "twoStar": 12, "oneStar": 10}
image / imagesproduct photo URL(s)
availability / delivery"Voor 23:59 uur besteld, morgen in huis" (both carry the delivery estimate)
seller{"id": "0000000", "name": "Voorbeeldverkoper", "rating": 9.2, "topSeller": true}
weight"254 g" (when full details are on)
sponsoredfalse
offersevery selling offer: price, condition and seller (when full details are on)
specificationsfull spec list, group and name/value pairs incl. EAN (when full details are on)
reviewsindividual reviews with rating, text, nickname and verified flag (when full details are on)
isOnSpecial / savingsAmount / savingsPercent / promoLabel / specialsCategoryBol.com's own was-price, savings and promo-badge fields
has_refurbished / in_stockfalse / true
urllink to the product page

In incremental mode, every returned record also carries changeType, changedFields, firstSeenAt and lastSeenAt; these four fields are absent from a normal run.

How to Use

  1. Pick a mode: search (keyword and filters) or url (paste product or result-page links).
  2. In search mode, add one or more keywords and, optionally, narrow with the price, rating, condition, sponsored and in-stock filters and a sort order. In URL mode, paste Bol.com product or result-page links; the same filters still apply.
  3. Turn on Fetch full product details to add specifications, EAN, full reviews, seller rating, weight and refurbished offers, and set Max items to bound the run.
  4. Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.

Search by keyword with a price ceiling:

{
"mode": "search",
"searchTerms": ["laptop"],
"sortBy": "price_asc",
"maxPrice": 400,
"maxListings": 50
}

Search with full product detail enrichment:

{
"mode": "search",
"searchTerms": ["koffiezetapparaat"],
"fetchDetails": true,
"maxReviews": 20,
"minRating": 4,
"maxListings": 30
}

Bol.com's own deals page as an extra source:

{
"mode": "search",
"searchTerms": [],
"specialsCategory": "aanbiedingen",
"maxListings": 50
}

Scrape pasted URLs (product pages and result pages):

{
"mode": "url",
"urls": [
"https://www.bol.com/nl/nl/p/example-laptop/9300000000000/",
"https://www.bol.com/nl/nl/s/?searchtext=boek"
],
"maxListings": 100
}

Supported URL shapes

In URL mode, leaving urls untouched now scrapes one example of each shape below (earlier versions scraped nothing). Set your own list to scrape only what you need.

URL shapeExampleResult
Keyword searchhttps://www.bol.com/nl/nl/s/?searchtext=laptoplisted products
Search, page N.../s/?searchtext=laptop&page=2starts at that page (never marks products EXPIRED)
Search, sorted.../s/?searchtext=laptop&sort=price&sortOrder=asc&page=2sort read from the URL
Search slughttps://www.bol.com/nl/nl/s/laptop/keyword taken from the slug
Search data linkhttps://www.bol.com/nl/nl/s/.data?searchtext=laptop&page=1same as keyword search
Producthttps://www.bol.com/nl/nl/p/<slug>/<id>/full detail record, matched on the numeric id
Product with tracking parameters.../<id>/?bltgh=abc&promo=xsame as product
Categoryhttps://www.bol.com/nl/nl/l/laptops/4770/listed products
Brandhttps://www.bol.com/nl/nl/b/acemagic/607284936/listed products
Dealshttps://www.bol.com/nl/nl/l/alle-artikelen-aanbiedingen/58334/listed products
Outlethttps://www.bol.com/nl/nl/ra/outlet/392102/ (also ?page=2)listed products
Older search linkhttps://www.bol.com/nl/s/zoekresultaten.html?searchtext=laptopkeyword read from the link
Mobile hosthttps://m.bol.com/nl/nl/s/?searchtext=laptoptreated as www.bol.com

Any other bol.com link is skipped with a warning in the log.

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/bol-com-scraper").call(run_input={"mode": "search", "searchTerms": ["laptop"], "maxListings": 20})
for product in client.dataset(run["defaultDatasetId"]).iterate_items():
print(product["title"], product["price"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/bol-com-scraper').call({ mode: 'search', searchTerms: ['laptop'], maxListings: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Bol.com's specials pages and was-price fields

Set specialsCategory to aanbiedingen (Bol.com's storewide deals page) or outlet (its clearance page) to add that page as an extra product source alongside, or instead of, your search keywords. Every product, whichever source it came from, carries isOnSpecial, originalPrice, savingsAmount, savingsPercent and promoLabel: these are only ever set from Bol.com's own reference price and promo badge on the listing, never estimated. originalPrice, savingsAmount and savingsPercent are null when there is no real reduction, promoLabel is null when there is no badge, and isOnSpecial is true when either is present. They never change or gate any other field, and they add no extra cost since the data comes from the same listing page the actor already fetches.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one specific interrupted run: paste its run or dataset ID and this run skips products already collected there, so you don't pay twice.
  • Incremental mode (incrementalMode) is for scheduled runs of the same search. The actor remembers the previous run itself, so you never paste an ID. The first run returns everything as NEW; later runs return only NEW, UPDATED (with changedFields) and REAPPEARED products by default, while unchanged products are suppressed and not billed unless emitUnchanged is on. EXPIRED products (previously tracked, no longer found) are only produced after a run that scanned the whole search, and only with emitExpired on. stateKey names or shares one monitoring campaign; leave it empty and the actor derives a key from the search and filter setup automatically.
  • What counts as a change. A product is UPDATED when a tracked field moves: price, list price, discount, availability and delivery, condition, title, offers, seller, specifications, description or categories. Reviews and every rating or review counter, the rotating image host, URL tracking parameters and the order of offers never make a product UPDATED; they stay in the output. Add more field names to ignoreFieldsForChanges (title: "Ignore fields when detecting changes (incremental mode only)") to exclude them too. Changing that list does not trigger a one-time wave of UPDATED rows.
  • EXPIRED is never produced from a partial scope: a pasted result URL that starts at ?page=2 or later, a run stopped by Max items or Max pages, or a failed page.
  • Turning on Incremental mode together with Resume is only allowed to bootstrap a search's very first incremental baseline. Once that search already has saved incremental state, combining the two stops the run with a message asking you to drop Resume or pick a different stateKey.

Output views

The dataset has four views in the Apify Console: Products (core listing fields), Product details (specifications, EAN, offers, images; filled when Fetch full product details is on), Reviews (one row per review, unwound from each product) and Changes (incremental) (change type, changed fields and timestamps).

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each product, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify β†’ Settings β†’ Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Export to your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (keyword and filters) or url (paste product or result URLs).
searchTermsarray[]Keywords to search. Search mode only.
specialsCategorystring""Optional: add aanbiedingen (storewide deals page) or outlet (clearance page) as an extra source alongside your search keywords. Off by default.
sortBystringrelevancerelevance, popularity, price_asc, price_desc, rating, or newest. Applies in both search and URL mode.
minPriceinteger(none)Keep products at or above this price (EUR).
maxPriceinteger(none)Keep products at or below this price (EUR).
minRatinginteger(none)Keep products with an average rating at or above this value (1-5).
conditionstringanyany, new, secondhand, or refurbished. Keeps only products whose best offer matches.
sponsoredOnlybooleanfalseKeep only sponsored (advertised) products.
inStockOnlybooleanfalseKeep only products with a buyable offer.
productIdsarray[]Look up specific products directly: bol.com product ids (16 digits), EAN/GTIN barcodes (8, 12, 13 or 14 digits), or product page URLs. Works in either mode and alongside keywords; each entry returns one product. A bol.com id opens that exact product page and returns nothing if it no longer exists; an EAN returns the top search hit for that barcode. A bol.com id or product URL always returns full detail fields; the detail enrichment event is billed for it only when Fetch full product details is on.
includeSponsoredbooleantrueKeep sponsored (advertised) listings. Turn off to drop them. Ignored when sponsoredOnly is on.
urlsarrayone example per shape (see below)Product, search, category, brand, deals or outlet URLs to scrape. Belgian search links (/be/nl/s/, /be/fr/s/) are scraped on the Belgian storefront with country BE; Belgian category, brand and outlet links are skipped with a warning. URL mode only; the price, rating, condition, sponsored and in-stock filters still apply. A product link always returns full detail fields; the detail enrichment event is billed for it only when Fetch full product details is on.
fetchDetailsbooleanfalseAdds full specifications (incl. EAN), full description, every image, full reviews with rating distribution, seller rating, weight, and refurbished/second-hand offers.
maxReviewsinteger30Maximum individual reviews captured per product when full details are on (maximum 1000). Bol.com's product page serves only its first slice of reviews (about 6 per product in testing; a product with 11 reviews returned 6) and exposes no way to page further, so fewer reviews than the cap may come back.
maxPagesinteger(none)Safety bound on result pages walked per keyword. Empty or 0 is unlimited; this does not cap the number of products.
totalPagesinteger(none)Same as maxPages, kept for compatibility with other bol.com scrapers. maxPages wins when both are set.
maxListingsinteger20Maximum products for the whole run. The single finite cap. 0 is unlimited.
resumeFromRunIdstring(none)Continue one previous interrupted run or crawl, skipping products it already collected.
incrementalModebooleanfalseTurn on for daily or recurring monitoring: later runs return only new, updated and reappeared products.
stateKeystring(none)Name or share an incremental-mode monitoring campaign. Auto-derived from the search and filter setup when left empty.
emitUnchangedbooleanfalseIncremental mode only. Also return, and bill for, products unchanged since the last run.
emitExpiredbooleanfalseIncremental mode only. Also return, and bill for, products no longer found after a complete scan.
ignoreFieldsForChangesarray[]Incremental mode only. Top-level field names that never make a product UPDATED or appear in changedFields (still returned in the output).
proxyobject{"useApifyProxy": true}Proxy configuration. Keep Apify Proxy enabled with a Netherlands exit for the most complete results.
residentialCountriesarray[]Preferred exit countries. Falls back to Netherlands, then Belgium, Germany, France and the United Kingdom when left empty.
backupProxyUrlstring(none)Optional backup proxy gateway used when full Apify Proxy access is unavailable on your plan.
maxResidentialRequestsinteger(none)Cost guard limiting how many requests a run may make before switching to the backup gateway. 0 is unlimited; falls back to 5000 when left empty.
trafficBudgetMbinteger(none)Soft transfer budget in MB. When exceeded, the run switches to the backup gateway. 0 is unlimited; falls back to 1500 when left empty.
preferDatacenterbooleanfalseNo effect: Bol.com refuses datacenter connections, so the actor always uses a residential connection. Kept so saved tasks keep working.
autoDowngradeProxybooleantrueNo effect: Bol.com refuses datacenter connections, so the actor always uses a residential connection. Kept so saved tasks keep working.
mcpConnectorsarray[]Optional connected apps (Notion, Linear, Airtable, Apify) to also receive each product.
notionParentPageUrlstring(none)When a Notion connector is selected, create one page per product under this parent page.
maxNotifyListingsinteger(none)Optional cap on how many products are pushed to the selected connectors. Falls back to 50 when left empty.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"productId": "9300000012345",
"title": "Voorbeeld Draadloze Hoofdtelefoon met Noise Cancelling, Zwart",
"brand": "Voorbeeldmerk",
"price": 279.0,
"list_price": 349.99,
"discount_percentage": 20,
"currency": "EUR",
"condition": "new",
"ean": "0000000000000",
"category": "Koptelefoons",
"categoryHierarchy": ["Elektronica", "Audio", "Koptelefoons"],
"rating": 4.6,
"reviewCount": 812,
"ratingDistribution": {"fiveStar": 600, "fourStar": 150, "threeStar": 40, "twoStar": 12, "oneStar": 10},
"reviews": [
{"rating": 5, "title": "Prima aankoop", "text": "Snel geleverd en werkt goed.", "nickname": "Klant2024", "location": "Nederland", "verified": true}
],
"image": "https://media.s-bol.com/0000/image-550x461.jpg",
"images": ["https://media.s-bol.com/0000/image-550x461.jpg"],
"availability": "Voor 23:59 uur besteld, morgen in huis",
"delivery": "Voor 23:59 uur besteld, morgen in huis",
"offers": [
{"price": 279.0, "currency": "EUR", "condition": "new", "seller": {"id": "0000000", "name": "Voorbeeldverkoper", "rating": 9.2, "topSeller": true}}
],
"seller": {"id": "0000000", "name": "Voorbeeldverkoper", "rating": 9.2, "topSeller": true},
"specifications": [
{"group": "Algemeen", "name": "EAN", "value": "0000000000000"},
{"group": "Algemeen", "name": "Kleur", "value": "Zwart"}
],
"description": "Voorbeeldbeschrijving van dit product voor studie, werk of thuisgebruik.",
"weight": "254 g",
"weightGrams": 254,
"sponsored": false,
"has_refurbished": false,
"in_stock": true,
"isOnSpecial": true,
"originalPrice": 349.99,
"savingsAmount": 70.99,
"savingsPercent": 20,
"promoLabel": "deal",
"specialsCategory": null,
"products_found": 4210,
"search_query": "koptelefoon",
"country": "NL",
"url": "https://www.bol.com/nl/nl/p/voorbeeld-hoofdtelefoon/9300000012345/",
"scrapedAt": "2026-01-01T00:00:00+00:00"
}

Plan Requirement

Residential proxies are required. Bol.com refuses datacenter connections outright: in testing, Apify datacenter proxies (automatic and datacenter groups) and a plain home connection all received an HTTP 403 "access blocked" page, while a Netherlands residential exit returned the full results. Keep Apify Proxy enabled and leave the connection on its default. A selected datacenter group is replaced by residential (billed to your plan), because Bol.com refuses datacenter connections; the actor uses a Netherlands residential exit first, then Belgium, Germany, France and the United Kingdom (change the order with residentialCountries). Residential exits are also uneven: an occasional exit is refused for a valid page, and the actor simply rolls to a fresh exit and retries.

Apify free plans do not include residential proxies. On a free plan the run logs this warning and continues on the backup connection (backupProxyUrl, or the fallback gateway), where some or all pages may stay unavailable:

The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs.

When pages do load through the backup, the log says: "Served over the backup connection (the default connection was unavailable)." If nothing could be read, the run ends with one of these messages instead of a silent empty result:

  • Proxy refused for the account: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid."
  • Residential unavailable, backup could not load pages: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested bol.com pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again."
  • Requests failed: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

preferDatacenter and autoDowngradeProxy have no effect, because Bol.com refuses datacenter connections. maxResidentialRequests and trafficBudgetMb bound how much a run uses before it moves to the backup gateway.

FAQ

How much does it cost?

Pay-per-event pricing; the current prices for every plan are on the Pricing tab. The events are:

EventWhen
Actor Startonce per run
Product scrapedonce per product returned to the dataset
Product detail enrichmentonce per product pushed with its detail page fetched, only when Fetch full product details is on (reviews included); pasted product URLs and bol.com ids in Product IDs always read the detail page for full fields, and with Fetch full product details off they are billed only as Product scraped

Reviews ride the detail enrichment event; there is no separate review charge. Max items caps how large any run can get.

This actor collects only publicly available product listings. You are responsible for how you use the data: follow Bol.com's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Prices and specifications are generally factual, but images, descriptions and reviews may be subject to third-party rights.

Can I get only new or changed products on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared products, and unchanged ones are not billed unless Emit unchanged is on.

What's the difference between Resume and Incremental mode?

This is the most common mix-up. Resume (resumeFromRunId) continues one specific interrupted run by skipping products it already collected. Incremental mode remembers the previous run of the same search by itself, for recurring scheduled runs, so you never paste an ID. The two can be combined only to bootstrap a search's very first incremental baseline from a resumed dataset; combining them again once that search already has saved incremental state stops the run with a message telling you to drop Resume or set a different stateKey.

Why did my run fail instead of returning an empty dataset?

A run fails when nothing could be read because of the connection: the proxy was refused for your account, residential proxies are unavailable and the backup connection could not load pages, or every request failed. The failure message is one of the three quoted under Plan Requirement, and nothing is charged for pages that never loaded. A run also fails when resumeFromRunId points to a run or dataset it cannot read, or when Incremental mode is combined with Resume while that search already has saved incremental state. A keyword that genuinely matches nothing still completes with an empty dataset and a log note.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to also push each product to Notion, Linear or Airtable.

πŸ”— Want more classifieds data?

Pair this actor with these related scrapers from the same team:

🏷️ Vinted.fr
Scrape Vinted.fr, France's C2C second-hand fashion marketplace: search with...
🏷️ Chrono24 Scraper
Scrape Chrono24 luxury watch listings by keyword, filters or URL. Extract 50+ fields...
🏷️ Daangn Scraper
Scrape Daangn (λ‹Ήκ·Ό) marketplace listings by keyword and region. Returns 35+ fields per...
🏷️ Gumtree.com Scraper
Scrape Gumtree.com classifieds across motors, property, jobs, services, pets and goods...
🏷️ 2dehands & 2ememain
Scrape classifieds from 2dehands.be and 2ememain.be by keyword, filters, or URLs. Returns...
🏷️ Wildberries Scraper
Scrape Wildberries marketplace: product search with prices (wallet vs retail), discounts...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • πŸ› οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.