bol.com Scraper - Products, Prices, Offers, Reviews
Pricing
from $1.00 / 1,000 product scrapeds
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
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
70
Total users
29
Monthly active users
3 days ago
Last modified
Categories
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.
| Field | Example |
|---|---|
productId | "9300000012345" |
title | "Voorbeeld Draadloze Hoofdtelefoon met Noise Cancelling, Zwart" |
brand | "Voorbeeldmerk" |
price / currency | 279.0 / "EUR" |
list_price / discount_percentage | 349.99 / 20 |
condition | "new" |
ean | "0000000000000" |
category / categoryHierarchy | "Koptelefoons" / ["Elektronica", "Audio", "Koptelefoons"] |
rating / reviewCount | 4.6 / 812 |
ratingDistribution | {"fiveStar": 600, "fourStar": 150, "threeStar": 40, "twoStar": 12, "oneStar": 10} |
image / images | product 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) |
sponsored | false |
offers | every selling offer: price, condition and seller (when full details are on) |
specifications | full spec list, group and name/value pairs incl. EAN (when full details are on) |
reviews | individual reviews with rating, text, nickname and verified flag (when full details are on) |
isOnSpecial / savingsAmount / savingsPercent / promoLabel / specialsCategory | Bol.com's own was-price, savings and promo-badge fields |
has_refurbished / in_stock | false / true |
url | link 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
- Pick a mode:
search(keyword and filters) orurl(paste product or result-page links). - 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.
- 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.
- 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}
Run it from your code
Python:
from apify_client import ApifyClientclient = 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 asNEW; later runs return onlyNEW,UPDATED(withchangedFields) andREAPPEAREDproducts by default, while unchanged products are suppressed and not billed unlessemitUnchangedis on.EXPIREDproducts (previously tracked, no longer found) are only produced after a run that scanned the whole search, and only withemitExpiredon.stateKeynames or shares one monitoring campaign; leave it empty and the actor derives a key from the search and filter setup automatically. - 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.
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.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Export to your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto 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
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (keyword and filters) or url (paste product or result URLs). |
searchTerms | array | [] | Keywords to search. Search mode only. |
specialsCategory | string | "" | Optional: add aanbiedingen (storewide deals page) or outlet (clearance page) as an extra source alongside your search keywords. Off by default. |
sortBy | string | relevance | relevance, popularity, price_asc, price_desc, rating, or newest. Applies in both search and URL mode. |
minPrice | integer | (none) | Keep products at or above this price (EUR). |
maxPrice | integer | (none) | Keep products at or below this price (EUR). |
minRating | integer | (none) | Keep products with an average rating at or above this value (1-5). |
condition | string | any | any, new, secondhand, or refurbished. Keeps only products whose best offer matches. |
sponsoredOnly | boolean | false | Keep only sponsored (advertised) products. |
inStockOnly | boolean | false | Keep only products with a buyable offer. |
urls | array | [] | Product or result-page URLs to scrape. URL mode only; the price, rating, condition, sponsored and in-stock filters still apply. |
fetchDetails | boolean | false | Adds full specifications (incl. EAN), full description, every image, full reviews with rating distribution, seller rating, weight, and refurbished/second-hand offers. |
maxReviews | integer | 30 | Maximum individual reviews captured per product when full details are on. |
maxPages | integer | (none) | Safety bound on result pages walked per keyword. Empty or 0 is unlimited; this does not cap the number of products. |
maxListings | integer | 20 | Maximum products for the whole run. The single finite cap. 0 is unlimited. |
resumeFromRunId | string | (none) | Continue one previous interrupted run or crawl, skipping products it already collected. |
incrementalMode | boolean | false | Turn on for daily or recurring monitoring: later runs return only new, updated and reappeared products. |
stateKey | string | (none) | Name or share an incremental-mode monitoring campaign. Auto-derived from the search and filter setup when left empty. |
emitUnchanged | boolean | false | Incremental mode only. Also return, and bill for, products unchanged since the last run. |
emitExpired | boolean | false | Incremental mode only. Also return, and bill for, products no longer found after a complete scan. |
proxy | object | {"useApifyProxy": true} | Proxy configuration. Keep Apify Proxy enabled with a Netherlands exit for the most complete results. |
residentialCountries | array | [] | Preferred exit countries. Falls back to Netherlands, then Belgium, Germany, France and the United Kingdom when left empty. |
backupProxyUrl | string | (none) | Optional backup proxy gateway used when full Apify Proxy access is unavailable on your plan. |
maxResidentialRequests | integer | (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. |
trafficBudgetMb | integer | (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. |
preferDatacenter | boolean | false | Cost-saving connection preference. Leave off unless you know the cheaper connection works for your data. |
autoDowngradeProxy | boolean | true | Cost-saving connection preference. Prefers the cheaper connection whenever results stay complete. |
mcpConnectors | array | [] | Optional connected apps (Notion, Linear, Airtable, Apify) to also receive each product. |
notionParentPageUrl | string | (none) | When a Notion connector is selected, create one page per product under this parent page. |
maxNotifyListings | integer | (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
Bol.com serves shoppers in the Netherlands and Belgium and works best behind a Netherlands exit, so keep Apify Proxy enabled for the most complete results. The residentialCountries field sets the order of preferred exit countries (Netherlands, then Belgium, Germany, France and the United Kingdom by default). If your plan does not include full Apify Proxy access, set a backupProxyUrl and the actor switches to that gateway once its request cap (maxResidentialRequests) or transfer budget (trafficBudgetMb) is reached. The preferDatacenter and autoDowngradeProxy toggles are cost-saving connection preferences.
FAQ
How much does it cost?
This actor uses pay-per-event pricing: once per run start, once per product returned to the dataset, and once per product whose detail page is fetched when Fetch full product details is on. Search-only runs are not charged that detail event. The Pricing tab shows the current rates, and Max items caps how large any run can get.
Is it legal to scrape Bol.com?
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 only 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; both stop before anything is collected or charged, with a message describing what to fix. Every other outcome, including a keyword matching nothing or Bol.com refusing requests on a restricted connection, still completes and returns an empty dataset with a warning in the run log rather than failing, since a genuine "nothing found" result must never look like a broken run.
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... | 🏷️ Daangn Scraper From $1/1K. Scrape Daangn (당근) marketplace listings by keyword and region. Returns 35+... |
| 🏷️ 2dehands & 2ememain Scrape classifieds from 2dehands.be and 2ememain.be by keyword, filters, or URLs. Returns... | 🏷️ Vinted Multi-Country Scraper Scrape Vinted across 27 country marketplaces: keyword search with brand, price and... |
| 🏷️ Chrono24 Scraper Scrape Chrono24 luxury watch listings by keyword, filters or URL. Extract 50+ fields... | 🏷️ OLX Global From $1/1K. Fast OLX scraper across 9 countries, including Poland, Romania, Portugal... |
💬 Support & custom scrapers
- 🐞 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 abotapi@proton.me or message Telegram @abotapi.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.