Bol EAN/GTIN Price & Seller Offers API avatar

Bol EAN/GTIN Price & Seller Offers API

Pricing

from $1.80 / 1,000 results

Go to Apify Store
Bol EAN/GTIN Price & Seller Offers API

Bol EAN/GTIN Price & Seller Offers API

Bol seller offers by barcode or numeric product ID in NL and BE. Hard maximum 1000 queries per run; unknown shipping and totals remain null.

Pricing

from $1.80 / 1,000 results

Rating

0.0

(0)

Developer

PricePirate

PricePirate

Maintained by Community

Actor stats

1

Bookmarked

1

Total users

1

Monthly active users

3 days ago

Last modified

Share

Bol.com Price & Seller Offers API

Get every seller offer on Bol.com, the leading online marketplace in the Netherlands and Belgium, through a single Actor. Send a barcode (GTIN/EAN) or Bol product ID and get the full list of sellers with item price, shipping, total, currency and condition, all in one JSON structure. Up to 1,000 lookups per run, no proxies or scraping setup required.

🚀 What's new in 1.1

This release moves Bol onto our new bulk lookup infrastructure, the same backend behind our Google Shopping Actor:

  • 20× bigger batches: up to 1,000 values per run, submitted as one bulk lookup job. Account capacity for Bol grows from 50 to 1,000 outstanding lookups.
  • Every seller, new and used: each found result lists all sellers returned for the product, in Bol's order, without ranking or condition filtering.

Perfect for price-comparison sites, repricing and margin tools, price monitoring and dynamic pricing engines, Bol sellers watching competing offers, deal apps, dropshipping and product research, and AI shopping assistants targeting the Dutch and Belgian markets.

✓ 2 Ways to Look Up Bol Data

Choose whichever identifier you already have:

OperationValue formatReturns
search-by-gtinGTIN / EAN / UPC barcode with 8, 12, 13 or 14 digits and a valid check digitProduct with all returned seller offers
search-by-idBol product ID, 10–25 digits, no leading zeroProduct with all returned seller offers

✓ 2-Country Coverage

Query localized offers on both Bol marketplaces:

Netherlands (nl, default) and Belgium (be).

✓ Multi-Seller Offer Data

A found result contains everything the lookup returns for the product:

  • Product: title, product URL, Bol product ID, EAN, brand and images, when available
  • Price summary: lowest, highest and average item price, plus the number of returned offers
  • Per-seller offers: seller name, condition, currency, item price, shipping cost, total price and position in Bol's list

Note: Bol does not always state a seller's shipping cost, so the price summary uses item prices rather than totals. Compare total per offer when you need total price (price + shipping), and treat null as unknown, not free.

✓ No Scraping Headaches

We run the lookup infrastructure, so you get structured data without managing proxies or headless browsers. You do not need to poll anything either: start the Actor, wait for it to finish and read the results straight from the dataset.

💻 Input

{
"operation": "search-by-gtin",
"values": ["4006381333931", "8710103917854"],
"country": "nl"
}
  • operation (required): search-by-gtin or search-by-id. All values in a run share the same operation. The Apify input form defaults to search-by-gtin; local runs must set it explicitly.
  • values (required): 1–1,000 strings, each one lookup. The Actor trims whitespace, drops blank entries and removes duplicates, preserving first-seen order. At least one nonblank value must remain. Run the Actor again for larger lists.
  • country (optional, default nl): nl or be.

The 1,000 limit applies to the raw list, duplicates included: both the input form and the Actor reject longer lists before any lookup starts.

Barcodes need a valid check digit and cannot be repeated-digit placeholders such as 0000000000000. A 14-digit GTIN must start with 0, because Bol does not list case-level GTIN-14 codes. A malformed value becomes its own free invalid_input row; the valid values in the same run are still looked up.

💻 Output

One dataset item per trimmed, deduplicated value, in input order. This illustrative example shows one seller with unknown shipping and one with shipping included; it is not a live price quote:

{
"query": "4006381333931",
"operation": "search-by-gtin",
"country": "nl",
"status": "found",
"result": {
"id": "9300000123456789",
"page_type": "product",
"name": "Example Product Name",
"url": "https://www.bol.com/nl/nl/p/example-product-name/9300000123456789/",
"ean": "4006381333931",
"brand": "Example Brand",
"description": null,
"image_urls": ["https://media.s-bol.com/example/product.jpg"],
"review_rating": null,
"review_count": null,
"categories": null,
"category_ids": null,
"price_min": 22.49,
"price_avg": 23.74,
"price_max": 24.99,
"offers_count": 2,
"platform_data": {
"op": "offers",
"country": "nl",
"sku": "9300000123456789",
"title": "Example Product Name"
},
"offers": [
{
"sellerId": "Example Store",
"shop_name": "Example Store",
"title": "Example Product Name",
"shop_url": null,
"shop_type": null,
"marketplace_name": "bol",
"shop_review_rating": null,
"shop_review_count": null,
"position": "1",
"condition": "new",
"currency": "EUR",
"price": 24.99,
"shipping": null,
"total": null,
"voucher": false,
"free_return": null,
"availability_text": null,
"availability_code": "unknown",
"classification": "product_page_match",
"confidence": "high",
"platform_data": {
"seller_name": "Example Store",
"price_value": 24.99,
"currency": "EUR",
"shipping_included": false,
"condition": "new"
}
},
{
"sellerId": "Second Store",
"shop_name": "Second Store",
"title": "Example Product Name",
"shop_url": null,
"shop_type": null,
"marketplace_name": "bol",
"shop_review_rating": null,
"shop_review_count": null,
"position": "2",
"condition": "used",
"currency": "EUR",
"price": 22.49,
"shipping": 0,
"total": 22.49,
"voucher": false,
"free_return": null,
"availability_text": null,
"availability_code": "unknown",
"classification": "product_page_match",
"confidence": "high",
"platform_data": {
"seller_name": "Second Store",
"price_value": 22.49,
"currency": "EUR",
"shipping_included": true,
"condition": "used"
}
}
],
"source": "bol",
"country": "nl",
"fetched_at": "2026-10-09T12:00:00.000Z"
}
}

Note: price_min, price_avg and price_max summarize item prices, not totals; the average is rounded to two decimals. shipping and total are null when Bol does not state the shipping cost. Offer positions are one-based strings that preserve Bol's order. Product metadata such as brand, images or description can be null or missing. platform_data keeps Bol-specific fields on both the product and each offer.

Export the dataset as JSON, CSV, Excel or any other Apify format; JSON keeps the nested seller offers intact. The .actor/dataset_schema.json describes every field and the Overview table. The .actor/output_schema.json links to the dataset items endpoint ({{links.apiDefaultDatasetUrl}}/items).

💻 Statuses & Errors

status is found, not_found or error.

not_found means Bol returned no matching product or offers for that value in the selected country. It is not proof that the product never existed. Errors are never turned into not_found.

not_found and error rows have result: null. Error rows also carry a stable errorCode and a sanitized message:

errorCodeMeaning
invalid_inputThe value is not a valid identifier for the selected operation, or the job input was rejected
free_limit_reachedThe value does not fit in the free plan's remaining lifetime allowance
concurrency_limit_reachedOther runs kept this account's lookup capacity full after all retries
timeoutThe lookup timed out upstream or was unfinished at the Actor's deadline
blockedThe upstream lookup reported a block
internal_errorAny other failure or an unusable result

Error rows are never charged. Even an all-error run normally finishes as SUCCEEDED with one row per value telling you what happened, so check the row statuses, run log and status message rather than the run status alone.

💰 Pricing

You pay per completed query result: each value that comes back found or not_found is charged once, after its row is delivered. Errors and timeouts are always free.

Example: a batch contains 20 queries; 10 come back found, 5 come back not_found and 5 time out. You are charged for the 15 completed results; the 5 timeouts are free.

Your run's maximum charge budget limits billing, not delivery: every completed result is still written to the dataset, even after the budget is used up. A billing failure never withholds data.

Free Apify plans include 50 lifetime Bol results per account, across all runs. This is not 50 per run, it does not reset, and it is separate from our other marketplaces. found and not_found results count toward it; errors do not. Upgrade your Apify plan to remove the cap.

If a batch is larger than your remaining allowance, the Actor looks up the first valid values that fit and returns free free_limit_reached rows for the rest, in input order. On a fresh free account, 1,000 valid values yield up to 50 lookups and 950 quota rows. Runs started at the same time share the allowance, so the number that fits can be lower. Failed lookups return their allowance for later runs, but the current run does not retry its overflow.

⏱ Timing & Timeouts

All valid values in a run go into one bulk lookup job. The status message shows live progress, polled every 15 seconds, and all results are written to the dataset once the job finishes. Results are not streamed one by one, and no specific throughput is guaranteed.

One shared 890-second budget covers waiting for capacity and processing. At the deadline the Actor fetches whatever already finished: those results still ship, and unfinished values become free timeout rows. Set the Actor timeout to 960 seconds (the default) to leave room for that final fetch and delivery.

Each Apify account can have 1,000 Bol lookups in flight at once, across all of its runs, in a pool separate from our other marketplaces. When the pool is full, the Actor waits and retries after 15, 30, 60, 120 and 240 seconds, within the run's budget. Values that still do not fit become free concurrency_limit_reached rows. To stay under the limit:

  • Run full-size batches one after another, not side by side
  • Use smaller batches if you need several runs in parallel
  • Stagger scheduled runs so they do not all start on the same minute

Avoid restarting a run: a restart submits the input again, which can duplicate rows, allowance use and charges.

Failed or timed-out requests are never billed.

📬 Contact & Support

Questions or higher limits: support@pricepirate.com