One config-driven script that renders product recommendations inside a brand's own card design and carousel. It copies a real product card from the page, fills it with recommendation data and starts the store's own slider library on it, so the widget looks like part of the site.
~12klines of core
60commits, sole author
3carousel libraries handled
2render modes: clone, native
Dec 2025to Jul 2026
Try it
Watch the engine adopt a store's design
Press "Run engine", then switch the host theme and run it again. Click a recommended card to see the attribution event.
The interactive engine needs JavaScript. It shows an invented storefront with its own product slider and an engine panel that clones the store's card, fills it with recommendations and starts a carousel, step by step.
Strategies and products are synthetic. In production the recommendation data comes from a backend service; the engine's job is rendering, runtime and integration.
Problem
Brands said our recommendation widgets didn't look like their site.
The first version built its own HTML strings and ran its own slider and CSS. Every brand wanted its own card: different image ratios, badges, price layouts, fonts. Matching each one by hand meant writing CSS per brand and fixing it again whenever the brand redesigned.
My role
I designed and wrote the engine as the only author: widget architecture, runtime and integration, plus the documentation site with a config-only setup guide. The recommendation strategies (top sellers, similar, bought together, personalised and others) are computed by the backend; I consume them.
Clone mode for Slick, Owl and Swiper, with an isolated root per widget and a full destroy()
Native mode with its own UI, skeleton loading and keyboard support, used when cloning is not possible
Scenario routing by page type and visitor, with fallbacks
View, click and conversion attribution
Architecture
What happens on page load
Read configBrand file sets placement, reference slider, labels, carousel type and scenarios.
Pick a scenarioPage type and visitor decide the strategy and its fallbacks.
Recommendation APIExisting service returns products for the strategy.
Clone and fillCopy a host card, strip runtime state, fill with data and labels.
Mount and trackStart the host's carousel on an isolated root, bind attribution.
Violet tint: parts I wrote.
Engineering decisions
What was hard and what I did
Clone a card without breaking the page
A live slider card carries carousel classes, inline transforms, ids and listeners. The engine deep-clones a reference card, strips that state, fills it, and mounts it in its own root. The host's sliders are never touched, and destroy() removes everything it added.
Three carousel libraries, one adapter
Slick, Owl and Swiper each want different markup and options. An adapter layer builds the right structure and options for whichever library the store already loads, so no extra slider is shipped.
Scenarios with fallbacks
A matrix keyed by page type (home, category, product, cart) and visitor (known after five product views, or guest) picks a strategy and its fallbacks. Cart pages merge several strategies without duplicates. Category pages read the breadcrumb and retry with the parent category when a level is empty.
Attribution that survives the click
Clicks carry recommendation parameters, and conversions are reported through a hook. A later fix set campaign attribution as soon as the widget loads, not only on click, so the campaign source is kept for seven days.
Fast and stable on heavy pages
Work runs in idle time, re-renders after DOM changes are debounced, the number of cards rendered before the carousel starts is capped, and a skeleton keeps layout shift at zero on category pages.
Config, not code, per brand
A new brand is one config file: placement selectors, reference slider and card, custom labels for badges and images, carousel options, custom CSS. A docs site with search explains every key, so setup does not need me.
Have a problem worth solving?Let's make it reliable