Where our products rank on bol.com — organic & sponsored, per search term and category · measurement period 9 jun – 21 sep (105 measurement days) · sorted by monthly revenue
— organic — sponsored · dotted line = top-10 threshold · rank axis reversed (higher = better) · Δ vs. previous measurement
| Product | Listing | Organic | Sponsored | Impressions |
|---|---|---|---|---|
| World Travel Adapter | “universele reisstekker voor nepal met usb c” | 1 | — | 9 |
| XK01 - Black | “opvouwbaar toetsenbord” | 4 | — | 8 |
| XKM01 - Black | “opvouwbaar toetsenbord” | 5 | — | 6 |
| World Travel Adapter | Reisaccessoires | 7 | 4 | 52 |
| World Travel Adapter | “reisstekker” | 8 | 1 | 21 |
| World Travel Adapter | “wereldstekker” | 10 | — | 33 |
| SC Butterfly Cushion Black | “donut kussen” | 11 | — | 9 |
| Shiatsu Massagekussen PRO | “rugmassage apparaten” | 14 | — | 9 |
| Portable Monitor 16 Inch | “pc scherm” | 17 | — | 6 |
| Stretchband | “weerstandband” | 19 | — | 8 |
| EM11 NL Mouse Black | “ergonomische muis” | 20 | — | 10 |
| Headphone Charging Station for AirPods Max 2024 & 2020 | Docking stations | 21 | — | 12 |
| EM11 NL Mouse Black | “draadloze muis” | 22 | — | 21 |
| Shiatsu Massagekussen PRO | “nekmassage apparaat” | 23 | — | 14 |
| Shiatsu Massagekussen PRO | “massagekussen” | 25 | — | 8 |
| SC Butterfly Cushion Black | Stoelkussens | 30 | — | 7 |
| SC Butterfly Cushion Black | Zitkussens | 33 | — | 6 |
| XK01 - Black | “draadloos toetsenbord” | 36 | — | 7 |
| Shiatsu Massagekussen PRO | “stressbal” | 36 | — | 12 |
| Stressball | Fopartikelen | 41 | — | 13 |
| Portable Monitor 13 Inch | Portable monitoren | 45 | — | 9 |
| Portable Monitor 13 Inch | “portable monitor” | 47 | — | 6 |
| XK01 - Black | “toetsenbord” | 48 | — | 8 |
| Mini Massage Gun PRO | “massage gun” | 48 | — | 6 |
| Shiatsu Massagekussen PRO | “massage” | 48 | — | 9 |
| EM11 NL Mouse Black | Muizen | 49 | 63 | 17 |
| World Travel Adapter | Reisbagage & Reisaccessoires | 49 | 4 | 17 |
| Stretchband | Weerstandsbanden | 58 | — | 8 |
| EM11 NL Mouse Black | “muis” | 59 | — | 12 |
| Shiatsu Massagekussen PRO | Massageapparaten | 66 | — | 24 |
| XK01 - Black | Toetsenborden | 77 | — | 13 |
| Stressball | “stressbal” | 79 | — | 8 |
| XKM01 - Black | “toetsenbord en muis draadloos” | — | 41 | 6 |
| SC Butterfly Cushion Black | “stuitkussen” | — | 13 | 7 |
| Vibrating Massage Ball | Massagebal | — | 14 | 22 |
| Vibrating Massage Ball | “lacrosse bal” | — | 2 | 8 |
| Vibrating Massage Ball | “massage ballen” | — | 9 | 9 |
| Vibrating Massage Ball | “triggerpoint bal” | — | 15 | 6 |
| Vibrating Massage Ball | “voetmassage roller” | — | 41 | 12 |
| Vibrating Duo Massage Ball | Massagebal | — | 23 | 22 |
| Vibrating Duo Massage Ball | “lacrosse bal massage” | — | 12 | 6 |
| World Travel Adapter | Wereldstekkers | — | 4 | 150 |
| Portable Monitor 16 Inch | Monitoren dagelijks gebruik | — | 2 | 9 |
| Portable Monitor 16 Inch | Portable monitoren | — | 27 | 10 |
| Packing Cubes Set of 8 | “koffer organizer set” | — | 9 | 8 |
| Packing Cubes Set of 4 | “koffer organizer set” | — | 8 | 8 |
| World Travel Adapter PRO | Wereldstekkers | — | 2 | 10 |
was → now within the window · now = latest measurement in range · ads ✓ = was also sponsored
Scripts: dashboard/bol-rank-pull.mjs (fetch + history + payload) and dashboard/bol-rank-render.mjs (this HTML). Revenue sorting and brand come from ~/.gandalf/dashboard-data.json → product_net.rows (monthly revenue per EAN, written by refresh.mjs) and PIM products.brand.
| Endpoint | GET https://api.bol.com/retailer/insights/product-ranks?ean=…&period=DAY&number-of-periods=1&date=YYYY-MM-DD |
|---|---|
| Auth | client-credentials: POST https://login.bol.com/token with Authorization: Basic $BOL_CLIENT_BASE64 (stored in ~/.gandalf/.env) → Bearer token (~5 min valid) |
| Headers | Accept: application/vnd.retailer.v10+json and Accept-Language: nl-NL — without that last one this endpoint returns HTTP 406 (undici/Node-fetch default is *) |
| Response | ranks[] with per listing rank, impressions, wasSponsored, and searchTerm or categoryId. We aggregate per (term|category): organic = min(non-sponsored ranks), sponsored = min(sponsored), impressions summed. |
| Category names | GET /products/categories (1 req/min!) → taxonomy flattened, cached in ~/.gandalf/.bol-cat-names.json (TTL 30 d) |
--backfill N).| Column | Meaning |
|---|---|
date | the MEASURED day (not the run day) — daily measures yesterday |
ean · product | product (name from product-names.json, fallback PIM) |
rank_type · rank_key | search + search term, or category + categoryId |
organic_rank · sponsored_rank | best organic / sponsored position that day (empty = none) |
impressions | sum of impressions on that listing that day |
node bol-rank-pull.mjs | daily: measures yesterday + self-healing + HTML + dash-bolrank |
node bol-rank-pull.mjs --backfill 30 | fetch the last N days (max 60) — fills history/trends |
node bol-rank-pull.mjs --render-only | only HTML + payload from existing CSV (no API calls) |
node bol-rank-pull.mjs --limit 2 | smoke test with 2 EANs, writes nothing |
{checked_at, last_date, ref_date, days, products:[{ean, name, best, terms:[{key, type, cur, was7, delta, imp, spo}], cats:[…]}], invisible:[{ean,name}]} — read it with sqlite3 ~/.gandalf/metrics.sqlite "SELECT payload FROM report_cache WHERE key='dash-bolrank'". New cache keys must be added to the KEEP_EXACT whitelist in dashboard/refresh.mjs (±line 610), otherwise they never reach the master dashboard.
Thresholds (constants at the top of the pull): top-10 boundary · movement = Δ≥2 (search term) / Δ≥3 (category) · "disappeared" = ≥5 prior impressions. Logs: ~/.gandalf/logs/bol-rank.log.
generated 2026-09-22 06:40 · refresh: node dashboard/bol-rank-pull.mjs