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

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

28

Total users

13

Monthly active users

3 days ago

Last modified

Share

bol.com Scraper

Scrape products from bol.com, the largest online store in the Netherlands and Belgium. Search by keyword with price, rating, condition and sort filters, or paste product and result URLs. Every record carries the title, price, list price and discount, brand, EAN, images, condition, delivery estimate, rating with full review distribution, individual reviews, all offers with seller name and rating, and refurbished and second-hand prices.

Why This Scraper?

  • One product record carries price, list price, discount, currency, brand, category path, condition, delivery, rating summary, image and seller.
  • Turn on full details to add the complete specification list (incl. EAN), the full description, every product image, the full review list with star distribution, seller rating, product weight, and refurbished and second-hand offers.
  • Search-mode filters for price band, minimum rating, condition, sponsored-only and in-stock-only, plus six sort orders, narrow results before anything is collected.
  • URL mode accepts both product pages and result pages.
  • One finite cap (Max items) keeps the run bounded; page depth is unlimited by default.
  • Optional export of each product to Notion, Airtable, Linear or Apify through MCP connectors, in addition to the dataset.

Data You Get

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

FieldExample
productId9300000000000
titleExample 15.6 Inch Laptop - 16GB RAM - 512GB SSD
brandExampleBrand
price329.5
list_price399
discount_percentage17
currencyEUR
conditionnew
ean0000000000000
categoryWindows laptops
categoryHierarchy["Computer", "Laptops", "Windows laptops"]
rating4.3
reviewCount15
ratingDistribution{"fiveStar": 11, "fourStar": 0, "threeStar": 2, "twoStar": 1, "oneStar": 1}
imagehttps://media.example.com/0000/image-550x461.jpg
availabilityIn stock
deliveryDelivered by tomorrow
seller{"id": "0000000", "name": "Example Store", "rating": 8.1}
weight2.2 kg
sponsoredfalse
urlhttps://www.bol.com/nl/nl/p/example-laptop/9300000000000/

How to Use

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
}

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
}

Input Parameters

ParameterTypeDescription
modeselectsearch (keyword + filters) or url (paste product or result URLs).
searchTermsarrayKeywords to search. Search mode only.
sortByselectBest match, Most popular, Price low to high, Price high to low, Highest rated, or Newest. Applies in both search and URL mode.
minPriceintegerKeep products at or above this price (EUR). Applies in both search and URL mode.
maxPriceintegerKeep products at or below this price (EUR). Applies in both search and URL mode.
minRatingintegerKeep products with an average rating at or above this value (1-5). Applies in both search and URL mode.
conditionselectAny, New, Second-hand, or Refurbished. Applies in both search and URL mode.
sponsoredOnlybooleanKeep only sponsored (advertised) products. Applies in both search and URL mode.
inStockOnlybooleanKeep only products with a buyable offer. Applies in both search and URL mode.
specialsCategoryselectOptional. Add aanbiedingen (bol.com's storewide deals page) or outlet (bol.com's clearance page) as an extra source alongside your search keywords. Off by default.
urlsarrayProduct or result URLs to scrape. URL mode only; filter fields are ignored.
fetchDetailsbooleanAdds full specifications, EAN, description, all images, full reviews, seller rating, weight and refurbished offers.
maxReviewsintegerMaximum individual reviews captured per product when details are on.
maxPagesintegerSafety bound on result pages per keyword. Empty or 0 = unlimited; does not cap product count.
maxListingsintegerMaximum products for the whole run. The single finite cap. 0 = unlimited. Default 20.
resumeFromRunIdstringContinue one specific interrupted or previous large crawl; skips products already collected by that run/dataset. See Resume & recurring updates.
incrementalModebooleanRecurring/scheduled monitoring: returns only NEW/UPDATED/REAPPEARED products against the actor's own remembered state for this search. Off by default.
stateKeystringOptional. Name or share an incremental-mode monitoring campaign. Auto-derived from the search/URL/filter setup when left empty.
emitUnchangedbooleanIncremental mode only. Also return (and bill for) products with no change since the last run. Off by default.
emitExpiredbooleanIncremental mode only. Also return (and bill for) products no longer found after a complete scan. Off by default.
proxyobjectProxy configuration. Keep Apify Proxy enabled with a Netherlands exit.
residentialCountriesarrayPreferred exit countries. Defaults to NL then BE, DE, FR, GB.
backupProxyUrlstringOptional backup proxy gateway for plans without full Apify Proxy access.
maxResidentialRequestsintegerCost guard limiting requests per run before switching to the backup gateway. 0 = unlimited. Default 5000.
trafficBudgetMbintegerSoft transfer budget in MB; switches to the backup gateway when exceeded. 0 = unlimited. Default 1500.
preferDatacenterbooleanCost-saving connection preference. Off by default.
autoDowngradeProxybooleanCost-saving connection preference. On by default.
mcpConnectorsarrayOptional connected apps (Notion, Airtable, Linear, Apify) to also receive each product.
notionParentPageUrlstringWhen a Notion connector is selected, create one page per product under this parent page.
maxNotifyListingsintegerOptional cap on how many products are pushed to the selected connectors.

Export to your apps (MCP connectors)

Optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector once under Apify then Settings then Integrations, select it in mcpConnectors, and each scraped product is also sent to that app as a condensed, human-readable summary. The full record always stays in the dataset. Supported connectors: Notion, Linear, Airtable and Apify. Leave mcpConnectors empty to write only to the dataset.

Specials & Was-Price

Set specialsCategory to add one of bol.com's own promo browse pages as an extra source for the run, alongside (or instead of) your search keywords:

  • aanbiedingen - bol.com's storewide deals page.
  • outlet - bol.com's clearance page.
{
"mode": "search",
"searchTerms": [],
"specialsCategory": "aanbiedingen",
"maxListings": 50
}

Every product, whether it came from a keyword search, a specials category, or a pasted URL, carries these fields:

FieldExampleNotes
isOnSpecialtrueTrue when bol.com marks the product with a genuine price reduction or an active promo label.
originalPrice74.99The pre-discount ("van") price. Only set when bol.com's own reference price is actually above the current selling price - never estimated or fabricated. null when there is no real reduction.
savingsAmount16.00originalPrice - price. null when there is no real reduction.
savingsPercent21bol.com's own reported discount percentage. null when there is no real reduction.
promoLabel"deal"bol.com's own promo badge text, e.g. "deal", "Bliksemdeal", "tot 30% stapelkorting". null when absent.
specialsCategory"aanbiedingen"Which specials category the product came from. null for keyword-search and URL-mode results.

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

{
"productId": "9300000000000",
"title": "Example Robot Vacuum Cleaner",
"price": 89.99,
"list_price": 109,
"discount_percentage": 17,
"isOnSpecial": true,
"originalPrice": 109,
"savingsAmount": 19.01,
"savingsPercent": 17,
"promoLabel": "deal",
"specialsCategory": "aanbiedingen"
}

These six fields are purely additive: they never change, gate, or null out price, list_price, discount_percentage, or any other existing field, and they cost nothing extra to collect - the data already comes from the same listing page the actor fetches for every run.

Output Example

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

{
"productId": "9300000000000",
"title": "Example 15.6 Inch Laptop - 16GB RAM - 512GB SSD - Windows 11",
"brand": "ExampleBrand",
"price": 329.5,
"list_price": 399,
"discount_percentage": 17,
"currency": "EUR",
"condition": "new",
"ean": "0000000000000",
"category": "Windows laptops",
"categoryHierarchy": ["Computer", "Laptops", "Windows laptops"],
"rating": 4.3,
"reviewCount": 15,
"ratingDistribution": {"fiveStar": 11, "fourStar": 0, "threeStar": 2, "twoStar": 1, "oneStar": 1},
"reviews": [
{"rating": 5, "title": "Great value", "text": "Fast and quiet.", "nickname": "Jane Doe", "location": "Amsterdam", "verified": true}
],
"image": "https://media.example.com/0000/image-550x461.jpg",
"images": ["https://media.example.com/0000/image-550x461.jpg"],
"availability": "In stock",
"delivery": "Delivered by tomorrow",
"offers": [
{"price": 329.5, "currency": "EUR", "condition": "new", "seller": {"id": "0000000", "name": "Example Store", "rating": 8.1}}
],
"seller": {"id": "0000000", "name": "Example Store", "rating": 8.1, "topSeller": false},
"specifications": [
{"group": "General", "name": "Type computer processor", "value": "Example N-series processor"},
{"group": "General", "name": "EAN", "value": "0000000000000"}
],
"description": "Example laptop for study, work and home use.",
"weight": "2.2 kg",
"weightGrams": 2200,
"sponsored": false,
"has_refurbished": false,
"in_stock": true,
"products_found": 300001,
"search_query": "laptop",
"country": "NL",
"url": "https://www.bol.com/nl/nl/p/example-laptop/9300000000000/",
"scrapedAt": "2026-01-01T00:00:00+00:00"
}

When incrementalMode is on, every returned record additionally carries changeType (NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED), changedFields (list of field names that differ from the last run — empty for NEW/REAPPEARED/UNCHANGED), firstSeenAt, and lastSeenAt. These four fields are absent in a normal (non-incremental) run.

Resume & recurring updates

There are two different things here — pick the one that matches what you're doing:

NeedUse
A crawl stopped and should continueresumeFromRunId
Run the same search every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave both off

Resume (resumeFromRunId) continues one specific interrupted or previous large crawl: paste a run ID or dataset ID and this run skips products already collected there, returning only the remaining new products.

Incremental mode (incrementalMode) is for a schedule (for example, daily): the actor remembers the previous run of the same search by itself, so you never paste a run ID. The first run returns everything as NEW. Later runs return only NEW, UPDATED, and REAPPEARED products by default — duplicates and unchanged products are suppressed (and not charged, even though their detail page may still be fetched to check for changes). Turn on emitUnchanged or emitExpired only when you also want those rows returned (and billed for). State is isolated per mode/search-terms/URLs/specials-category and filter/sort/detail setup automatically; set stateKey to name or deliberately share a monitoring campaign. maxListings and maxPages never affect which state a run reads — tightening or loosening either keeps the same baseline.

Every emitted product carries an EAN when detail is on, but incremental mode's own identity key is the bol.com product ID (the productId field, stable regardless of fetchDetails).

Scheduled-run example — same search, run daily:

Day 1 (first run ever for this search):

{ "mode": "search", "searchTerms": ["koffiezetapparaat"], "incrementalMode": true }

→ every product comes back with "changeType": "NEW".

Day 2 (the schedule fires again, identical input):

{ "mode": "search", "searchTerms": ["koffiezetapparaat"], "incrementalMode": true }

→ products whose price/rating/availability/etc. changed come back as "changeType": "UPDATED" with changedFields listing what changed, brand-new products come back as "changeType": "NEW", products that vanished and came back come back as "changeType": "REAPPEARED" — and products that are still there, unchanged, are not returned at all (suppressed, not charged) unless emitUnchanged is on. A previously-tracked product no longer found after a complete scan of the search (not capped by Max items, not a Resume run) is returned as "changeType": "EXPIRED" only when emitExpired is on.

Two fields are stripped when deciding UPDATED vs UNCHANGED and never make the actor over-report changes: scrapedAt/scraped_at (stamped fresh on every run), and the token order inside multi-value specifications[].value rows (e.g. "Laptop opties") — bol.com renders the same set of attribute chips in a different order between fetches; the fields you actually see are unaffected, only the change-detection comparison ignores the reordering. A field that goes missing on one fetch and returns on the next (or vice versa) is also never treated as a change — only a genuine value-to-different-value transition is.

Plan Requirement

bol.com serves shoppers in the Netherlands and Benelux, so keep Apify Proxy enabled with a Netherlands exit for the most complete results. The residentialCountries field lets you set the preferred exit countries (NL then BE, DE, FR, GB by default). If your plan does not include full Apify Proxy access, set a backupProxyUrl and the actor uses that gateway instead.

For predictable cost the run honours a per-run request cap (maxResidentialRequests) and a soft transfer budget (trafficBudgetMb); once either is reached it uses the backup gateway. The preferDatacenter and autoDowngradeProxy toggles are cost-saving connection preferences.