RecomNext
FeaturesHow it WorksWhy RecomNextResourcesGet Started

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.

@recomnext/carousel
@recomnext/react-carousel

Widget Types

Choose the widget package based on your frontend stack:

PackageUse CaseInitializationBest For
@recomnext/carouselVanilla JS / static pagesAuto-discovery + constructorLanding pages, CMS, no-framework apps
@recomnext/react-carouselReact appsReact component propsSPA 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
NameRequiredTypeDetails
data-base-urlYesstringEngine API base URL (example: https://api.example.com).
data-tenant-idYesstringTenant identifier sent in X-Tenant-Id header.
data-logicNouser-to-item | item-to-item | similar-products | recently-viewed | items-to-itemsRecommendation logic. Default is user-to-item.
data-item-idConditionalstringRequired for item-to-item and similar-products.
data-item-idsConditionalstringComma-separated item IDs for items-to-items.
data-user-idNostringExplicit user ID. Falls back to generated session ID.
data-scenarioNostringScenario slug to apply custom filters, boosters, and constraints.
data-countNonumberNumber of items to fetch. Default is 8.
data-return-propertiesNotrue | falseProjection toggle. Default true. false requests lean identity-only payload.
data-included-propertiesNocomma-separated stringExact raw item paths (for example attributes.name,attributes.image).
data-titleNostringSection heading shown above the carousel.
data-item-urlNostringCard URL template. Uses {itemId}. Default is /products/{itemId}.
data-public-tokenNostringPublic 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
NameRequiredTypeDetails
baseUrlYesstringEngine API base URL.
tenantIdYesstringTenant ID sent with each request.
logicYesLogicTypeRecommendation logic: user-to-item, item-to-item, similar-products, recently-viewed, or items-to-items.
itemIdConditionalstringRequired for item-to-item and similar-products.
itemIdsConditionalstring[]Required for items-to-items.
userIdNostringUser identifier. Session ID fallback if omitted.
scenarioNostringScenario slug for recommendation configuration.
countNonumberNumber of items to request. Default is 8.
returnPropertiesNobooleanProjection toggle. Default true. false returns lean identity-only payload.
includedPropertiesNostring[]Exact raw item paths to include (for example attributes.name).
titleNostringWidget title shown above cards.
classNameNostringContainer class for custom styling.
styleNoCSSPropertiesInline style object for container.
renderItemNo(item, index) => ReactNodeCustom card renderer.
onItemClickNo(item) => voidCallback fired when a card is clicked.
onImpressionNo(items) => voidCallback fired for newly visible cards.
publicTokenNostringPublic 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-id for analytics tracking and custom hooks.
Projection Behavior Guide
ModeRecommended UsageWidget Output
Default full payloadLeave projection props unsetFull cards with name/image/category/price when catalog data has them
Selective projectionSet returnProperties=true with includedProperties pathsCards render only requested fields plus identity
Lean modeSet returnProperties=false intentionallyMinimal identity-driven cards; missing metadata is rendered safely
Tracking and Analytics

Widgets track both click interactions and impressions automatically.

SignalTriggerEndpointPayload Highlights
Card clickUser clicks/taps a card/ingestion/interactionsuserId, itemId, type=view, timestamp
ImpressionCard reaches >= 50% visibility/ingestion/impressionsuserId, itemIds[], scenarioSlug, timestamp
Logic Selection Guide
Logic TypeInput NeededTypical Placement
user-to-itemuserId (or session)Home feed, account dashboard
item-to-itemitemIdProduct detail page: related products
similar-productsitemIdProduct detail page: semantic similarity
recently-vieweduserId (or session)Home page continuation, cart page
items-to-itemsitemIds[]Cart page cross-sell or checkout upsell
Troubleshooting
  • No cards rendered: verify baseUrl, tenantId, and logic-specific inputs (itemId or itemIds).
  • 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=false is enabled or if includedProperties paths do not match raw item paths from /catalog/items.
  • HTTP 400 on recommendations: verify includedProperties has no unsafe segments (for example __proto__, constructor) and stays within GET path/length limits.
  • Broken links: check data-item-url or 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 publicToken when 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.