Widgets Guide
Use ready-to-ship recommendation carousels in both vanilla JavaScript and React. Install from npm (npm install @recomnext/carousel or npm install @recomnext/react-carousel). Installation constitutes acceptance of the SDK License Agreement. This guide covers initialization, parameters, rendering, and tracking.
Widget Types
Choose the widget package based on your frontend stack:
| Package | Use Case | Initialization | Best For |
|---|---|---|---|
| @recomnext/carousel | Vanilla JS / static pages | Auto-discovery + constructor | Landing pages, CMS, no-framework apps |
| @recomnext/react-carousel | React apps | React component props | SPA product pages, custom card rendering |
Vanilla Widget: Quick Start
The vanilla widget auto-initializes every element with data-recomnext-carousel on page load. You only need HTML data attributes and the widget script.
<div
data-recomnext-carousel
data-base-url="https://api.example.com"
data-tenant-id="demo-ecommerce"
data-logic="similar-products"
data-item-id="prod-001"
data-scenario="pdp-similar"
data-count="8"
data-return-properties="true"
data-included-properties="attributes.name,attributes.price,attributes.image,category"
data-title="You Might Also Like"
data-item-url="/products/{itemId}"
></div>
<script src="/assets/recomnext-carousel.js"></script>Vanilla Widget Parameters
| Name | Required | Type | Details |
|---|---|---|---|
| data-base-url | Yes | string | Engine API base URL (example: https://api.example.com). |
| data-tenant-id | Yes | string | Tenant identifier sent in X-Tenant-Id header. |
| data-logic | No | user-to-item | item-to-item | similar-products | recently-viewed | items-to-items | Recommendation logic. Default is user-to-item. |
| data-item-id | Conditional | string | Required for item-to-item and similar-products. |
| data-item-ids | Conditional | string | Comma-separated item IDs for items-to-items. |
| data-user-id | No | string | Explicit user ID. Falls back to generated session ID. |
| data-scenario | No | string | Scenario slug to apply custom filters, boosters, and constraints. |
| data-count | No | number | Number of items to fetch. Default is 8. |
| data-return-properties | No | true | false | Projection toggle. Default true. false requests lean identity-only payload. |
| data-included-properties | No | comma-separated string | Exact raw item paths (for example attributes.name,attributes.image). |
| data-title | No | string | Section heading shown above the carousel. |
| data-item-url | No | string | Card URL template. Uses {itemId}. Default is /products/{itemId}. |
| data-public-token | No | string | Public signing token for browser request signing when enabled. |
Vanilla Widget: Programmatic Initialization
Use constructor-based initialization for dynamic pages, custom lifecycle handling, or SPA route transitions.
import { RecomnextCarousel } from '@recomnext/carousel';
const el = document.getElementById('recs');
const carousel = new RecomnextCarousel(el, {
baseUrl: 'http://localhost:3000',
tenantId: 'demo-ecommerce',
logic: 'user-to-item',
userId: 'user-123',
count: 8,
returnProperties: true,
includedProperties: ['attributes.name', 'attributes.price', 'attributes.image', 'category'],
title: 'Recommended For You',
scenario: 'homepage-for-you',
});
// On route teardown:
carousel.destroy();React Widget: Quick Start
In React apps, use the RecomnextCarousel component and pass logic-specific props.
import { RecomnextCarousel } from '@recomnext/react-carousel';
export function ProductRecommendations({ productId }: { productId: string }) {
return (
<RecomnextCarousel
baseUrl="/api"
tenantId="demo-ecommerce"
logic="similar-products"
itemId={productId}
scenario="pdp-similar"
count={8}
returnProperties={true}
includedProperties={['attributes.name', 'attributes.price', 'attributes.image', 'category']}
title="Similar Products"
onItemClick={(item) => {
window.location.href = '/products/' + item.itemId;
}}
/>
);
}React Widget Props
| Name | Required | Type | Details |
|---|---|---|---|
| baseUrl | Yes | string | Engine API base URL. |
| tenantId | Yes | string | Tenant ID sent with each request. |
| logic | Yes | LogicType | Recommendation logic: user-to-item, item-to-item, similar-products, recently-viewed, or items-to-items. |
| itemId | Conditional | string | Required for item-to-item and similar-products. |
| itemIds | Conditional | string[] | Required for items-to-items. |
| userId | No | string | User identifier. Session ID fallback if omitted. |
| scenario | No | string | Scenario slug for recommendation configuration. |
| count | No | number | Number of items to request. Default is 8. |
| returnProperties | No | boolean | Projection toggle. Default true. false returns lean identity-only payload. |
| includedProperties | No | string[] | Exact raw item paths to include (for example attributes.name). |
| title | No | string | Widget title shown above cards. |
| className | No | string | Container class for custom styling. |
| style | No | CSSProperties | Inline style object for container. |
| renderItem | No | (item, index) => ReactNode | Custom card renderer. |
| onItemClick | No | (item) => void | Callback fired when a card is clicked. |
| onImpression | No | (items) => void | Callback fired for newly visible cards. |
| publicToken | No | string | Public signing token for browser request signing when enabled. |
Strict-HMAC Projection Contract
Projection placement must match request signing scope exactly.
GET (user-to-item, item-to-item, similar-products, recently-viewed): - returnProperties + includedProperties go in query and are included in the signed URL. POST (items-to-items): - returnProperties + includedProperties go in JSON body only. - Query stays scenario/user context only. If placement and signature scope differ, the engine rejects the request.
Customization Examples
Custom React Card Renderer
<RecomnextCarousel
baseUrl="/api"
tenantId="demo-ecommerce"
logic="user-to-item"
count={10}
title="Top Picks"
renderItem={(item) => (
<a
href={'/products/' + item.itemId}
style={{
display: 'block',
width: 220,
borderRadius: 12,
border: '1px solid #eee',
textDecoration: 'none',
color: '#111',
overflow: 'hidden',
}}
>
{item.image && <img src={item.image} alt={item.name} style={{ width: '100%', aspectRatio: '1', objectFit: 'cover' }} />}
<div style={{ padding: 12 }}>
<p style={{ margin: 0, fontWeight: 600 }}>{item.name}</p>
<p style={{ margin: '4px 0 0', color: '#666', fontSize: 12 }}>{item.category}</p>
</div>
</a>
)}
/>Vanilla Widget with Multiple Carousels
<div data-recomnext-carousel data-base-url="https://api.example.com" data-tenant-id="demo-ecommerce" data-logic="user-to-item" data-user-id="user-123" data-scenario="homepage-for-you" data-title="For You" ></div> <div data-recomnext-carousel data-base-url="https://api.example.com" data-tenant-id="demo-ecommerce" data-logic="recently-viewed" data-user-id="user-123" data-title="Recently Viewed" ></div>
How Rendering Works
- Widget injects scoped carousel styles once and renders a loading skeleton immediately.
- Recommendations are fetched using the selected logic and optional scenario.
- Response items are mapped into card data fields:
itemId,name,category,price,image,url. - Lean/projection payloads are supported; widgets tolerate missing
attributes, image, category, and price without throwing. - Cards render in a horizontal track with snap scrolling for touch and desktop trackpads.
- If no items are returned, the widget renders an empty state message.
- Each card includes
data-item-idfor analytics tracking and custom hooks.
Projection Behavior Guide
| Mode | Recommended Usage | Widget Output |
|---|---|---|
| Default full payload | Leave projection props unset | Full cards with name/image/category/price when catalog data has them |
| Selective projection | Set returnProperties=true with includedProperties paths | Cards render only requested fields plus identity |
| Lean mode | Set returnProperties=false intentionally | Minimal identity-driven cards; missing metadata is rendered safely |
Tracking and Analytics
Widgets track both click interactions and impressions automatically.
| Signal | Trigger | Endpoint | Payload Highlights |
|---|---|---|---|
| Card click | User clicks/taps a card | /ingestion/interactions | userId, itemId, type=view, timestamp |
| Impression | Card reaches >= 50% visibility | /ingestion/impressions | userId, itemIds[], scenarioSlug, timestamp |
Logic Selection Guide
| Logic Type | Input Needed | Typical Placement |
|---|---|---|
| user-to-item | userId (or session) | Home feed, account dashboard |
| item-to-item | itemId | Product detail page: related products |
| similar-products | itemId | Product detail page: semantic similarity |
| recently-viewed | userId (or session) | Home page continuation, cart page |
| items-to-items | itemIds[] | Cart page cross-sell or checkout upsell |
Troubleshooting
- No cards rendered: verify
baseUrl,tenantId, and logic-specific inputs (itemIdoritemIds). - Empty recommendations: ensure catalog and interactions are ingested and the selected scenario is valid.
- Only ID links show (no name/image/price): check if
returnProperties=falseis enabled or ifincludedPropertiespaths do not match raw item paths from/catalog/items. - HTTP 400 on recommendations: verify
includedPropertieshas no unsafe segments (for example__proto__,constructor) and stays within GET path/length limits. - Broken links: check
data-item-urlor custom click navigation handlers. - No impression events: confirm cards are in viewport and browser supports
IntersectionObserver. - 401/403 errors: verify tenant auth setup and pass
publicTokenwhen browser signing is required.
Next Steps
After adding widgets, continue with:
- Quick Start — run the local stack and seed test data.
- nextQL Guide — build filter and booster expressions for scenarios.
- API Reference — inspect recommendation and ingestion endpoint contracts.
- SDK Docs — integrate typed Browser and Node clients.
