SDK Documentation
Published npm packages provide typed client libraries for integrating with the RecomNext engine. Installing a package constitutes acceptance of the SDK License Agreement.
SDK baseUrl for this environment
| Engine API base URL | Admin UI |
|---|---|
| https://api.proxy.vpn.recomnext.com/api | https://admin.proxy.vpn.recomnext.com |
Use the engine base URL as baseUrl in widgets and SDKs.
Browser SDK
Lightweight browser SDK focused on recommendations, real-time event tracking, and scenario attribution. Designed for client-side React, Vue, or vanilla JavaScript applications.
Installation
npm install @recomnext/browser
Setup
import { RecomnextBrowserClient } from '@recomnext/browser';
const recomnext = new RecomnextBrowserClient({
baseUrl: 'https://api.proxy.vpn.recomnext.com/api', // see environment table above
tenantId: 'my-tenant',
publicToken: 'rnx_pub_...', // when browser signing is enabled
userId: 'user-123', // optional — your stable ID
country: 'IN', // optional ISO-2 default for recommend + track*
});Unified Recommend API
// The preferred way to fetch recommendations
const response = await recomnext.recommend({
scenario: 'homepage-for-you',
count: 8,
country: 'IN', // optional — overrides the client default
returnProperties: true,
includedProperties: ['attributes.name', 'attributes.price', 'attributes.image', 'category'],
// Optional request-time overrides (omit to keep scenario values):
// filter: "'stock' > 0",
// boosters: ["boost by 1.2 where 'featured' = true"],
// rulesSlugs: ['in-stock'],
});
for (const item of response.items) {
console.log(item.itemId);
}Lean Projection Mode
// Lean mode for minimal payload transfer
const lean = await recomnext.recommend({
scenario: 'pdp-similar',
count: 10,
returnProperties: false,
});
for (const item of lean.items) {
const scoreLabel = item.score != null ? item.score.toFixed(2) : 'N/A';
console.log(item.itemId, scoreLabel);
}Signed Request Placement (publicToken)
Browser signing follows strict placement: GET recommendation routes sign projection in query, and POST items-to-items signs projection in the JSON body.
Omit projection keys for backward-compatible full payloads. Set returnProperties=false for lean identity-first payloads when your UI does not require attributes.
User identity
Pass your own user ID at init or after login. When userId is omitted, the SDK resolves or creates a browser session ID (sess_… in localStorage, key recomnext_session_id, shared across tabs). Legacy sessionStorage values migrate once on first read.
// Optional at init
const recomnext = new RecomnextBrowserClient({
baseUrl: 'https://api.proxy.vpn.recomnext.com/api',
tenantId: 'my-tenant',
userId: 'customer-42',
// Optional: pin anonymous id instead of auto-generating sess_…
// sessionId: 'sess_my-custom-bucket',
});
// Or set after you know the authenticated user
recomnext.setUserId('customer-42');
// Optional market default for recommend + track* (ISO-2; invalid/OTH → global)
recomnext.setCountry('IN');
// Recommended with widgets: configure once, signal auth (one merge, auto refetch)
RecomnextIdentity.configure({
baseUrl: 'https://api.proxy.vpn.recomnext.com/api',
tenantId: 'my-tenant',
publicToken: 'rnx_pub_…',
});
await RecomnextIdentity.setAuthenticatedUserId('customer-42');
await RecomnextIdentity.setAuthenticatedUserId(null);
// Or manual merge when coordinator is not configured
await recomnext.mergeIdentity('customer-42');
recomnext.setUserId('');
recomnext.clearSession();Widgets accept the same IDs via data-user-id or the React userId prop — see the Widgets user identity guide. When RecomnextIdentity is configured, omit widget userId and call setAuthenticatedUserId on login/logout; carousels refetch and merge is deduped across instances.mergeIdentity delegates to the coordinator when configured. When your tenant has auto user provisioning enabled (the default), the engine creates a minimal catalog user on identity merge and on the first known interaction — use upsertUsers when you need to sync attributes or bulk-import users from your IDP.
Browser SDK — event tracking
All tracking methods accept an optional scenarioSlug and optional country. Omit the slug for site-wide events (search, direct PDP, order webhooks). Provide it when the item came from a named recommendation placement. Omit country (or send OTH) to tag the event as global.
// Site-wide — no scenario
recomnext.trackView('prod-001');
recomnext.trackCart('prod-001');
recomnext.trackPurchase('prod-001');
// With placement attribution
recomnext.trackView('prod-001', 'homepage-for-you');
recomnext.trackCart('prod-001', 'pdp-related');
recomnext.trackPurchase('prod-001', 'cart-upsell');
// Per-call country override (otherwise the client default is sent)
recomnext.trackView('prod-001', { scenarioSlug: 'homepage-for-you', country: 'DE' });
recomnext.trackPurchase('prod-001', { country: 'IN' });Impression Tracking
Uses `IntersectionObserver` to automatically detect when recommendation cards become visible. Impressions are batched and flushed every 2 seconds for efficiency.
const cleanup = recomnext.trackImpressions(document.querySelector('.recs'), {
scenario: 'home-for-you',
country: 'IN', // optional — overrides the client default
itemSelector: '[data-item-id]', // CSS selector for individual item cards
threshold: 0.5, // 50% visibility required
once: true, // Only track the first time an item is seen
});
// Call cleanup when the component unmounts
cleanup();Key Methods
| Method | Description |
|---|---|
| recommend(opts) | Unified recommendation fetcher — uses scenario or logicType; opts.country overrides the client default |
| getRecommendations(userId, count, scenario?) | Legacy personalized "For You" fetcher |
| getRelatedItems(itemId, count, scenario?) | Legacy item-to-item fetcher |
| getSimilarProducts(itemId, count, scenario?) | Legacy vector-similar fetcher |
| getItemsToItems(itemIds, opts?) | Legacy cart-style fetcher (POST body supports projection keys) |
| trackView(itemId, scenarioSlug? | opts) | Log item view; opts.country overrides the client default |
| trackCart(itemId, scenarioSlug? | opts) | Log cart; same country override as trackView |
| trackPurchase(itemId, scenarioSlug? | opts) | Log purchase; same country override as trackView |
| trackImpressions(container, opts) | Start automatic impression tracking; opts.country optional |
| RecomnextIdentity.configure(opts) | Enable coordinator (merge dedupe + widget sync) |
| RecomnextIdentity.setAuthenticatedUserId(id|null) | Login/logout signal — merge once, rotate anon on logout |
| mergeIdentity(authenticatedUserId) | Link anonymous history (delegates to coordinator when configured) |
| clearSession(customId?) | Rotate anonymous localStorage session after logout |
| getAnonymousSessionId() | Read current sess_… without creating a new one |
| setUserId(newUserId) | Update the user ID for the current session |
| setCountry(code) | Default ISO-2 for recommend + track* until overridden per call |
Projection and Type Notes
| Type/Option | Details |
|---|---|
| country?: string | ISO-3166-1 alpha-2 on the client, recommend(), and track*. Missing, invalid, or OTH ranks/tags globally. |
| returnProperties?: boolean | Default true. false returns lean item payload for lower transfer cost. |
| includedProperties?: string[] | Exact raw item paths only (for example attributes.name). Field mapper aliases are not auto-resolved. |
| RecommendedItem.score?: number | Migration note: score changed from required to optional. Guard all access (item.score != null ? item.score.toFixed(2) : "N/A") to avoid runtime failures. |
| RecommendedItem.externalId | Deprecated alias in recommendation responses only. Catalog ingestion still uses externalId as the item identity key. Prefer itemId in new response consumers. |
Node.js SDK
Server-side Node.js/TypeScript SDK with built-in retry logic, timeouts, and full coverage of the engine REST API. Requires Node.js 18+ for native fetch support.
Installation
npm install @recomnext/node
Setup
import { RecomnextClient } from '@recomnext/node';
const client = new RecomnextClient({
baseUrl: 'https://api.proxy.vpn.recomnext.com/api',
tenantId: 'my-tenant',
retries: 3, // default: 3
timeout: 10000, // default: 10s
});API Namespaces
| Namespace | Description | Key Methods |
|---|---|---|
| client.ingestion | Data synchronization | upsertItems(), upsertUsers(), logInteractions(), logImpressions() |
| client.recommendations | Fetching results | recommend(), userToItem(), itemToItem(), itemsToItems(), similarProducts() |
| client.scenarios | Logic management | list(), get(), create(), update(), delete() |
| client.segmentations | Diversity config | list(), get(), create(), listSegments() |
| client.catalog | Inspecting data | listItems(), getItem(), listUsers(), getUser() |
| client.identity | User mapping | merge() |
Tenant settings APIs are currently documented in the HTTP API reference (GET/PUT /catalog/tenant-settings). The Node SDK catalog namespace does not yet expose dedicated helpers for these endpoints.
Bulk Ingestion Example
// Sync items to RecomNext
await client.ingestion.upsertItems([
{
externalId: 'prod-001', // catalog identity key (not deprecated for ingestion)
category: 'electronics',
attributes: {
name: 'Smartphone Pro',
price: 999.99,
tags: ['5g', 'high-performance']
}
}
]);
// Log batch of interactions
await client.ingestion.logInteractions([
{ userId: 'user-1', itemId: 'prod-001', type: 'view', country: 'IN' },
{ userId: 'user-2', itemId: 'prod-001', type: 'purchase', weight: 10 }
]);Recommendation Projection Example
const response = await client.recommendations.recommend({
scenario: 'pdp-similar',
itemId: 'prod-001',
count: 6,
country: 'IN', // optional ISO-2; omit for global ranking
returnProperties: true,
includedProperties: ['attributes.name', 'attributes.price', 'attributes.image', 'category'],
});
for (const item of response.items) {
const scoreLabel = item.score != null ? item.score.toFixed(3) : 'N/A';
console.log(item.itemId, scoreLabel);
}Signed Request Placement Contract
When using signing tokens, SDKs keep projection placement aligned with engine verification: GET recommendation routes sign projection in query, while POST items-to-items signs projection in the request body.
Scenario Management Example
// Create a scenario programmatically
const scenario = await client.scenarios.create({
name: 'Search Boosted Results',
slug: 'search-boosted',
logicType: 'user-to-item',
// contains/not_contains: array item attrs only (fail-closed if missing)
filter: "'allowed_countries' contains 'IN'",
boosters: ["boost by 1.5 where 'promo' = true"],
constraints: { maxPerCategory: 2 }
});
// Update an existing scenario
await client.scenarios.update('search-boosted', {
minItems: 4
});Recommendation filter / boosters are opaque nextQL strings. Use contains / not_contains only for array item attributes; use in / not_in when the filter supplies the list. Missing or non-array attrs fail closed — for denylists every item must have the array ([] = not blocked).
Filter auto-relax (query planning)
Opt-in scenario flags autoRelaxFilters / relaxEntireFilterOnEmpty (default off). Put durable clauses on the left, soft ones on the right. When relaxation applies, read filterRelaxation.droppedClauses / effectiveFilter for UX copy. Full checklist: Scenarios — Query planning for filter auto-relax.
const res = await client.recommendations.recommend({ scenario: 'pdp', itemId: 'x', count: 8 });
if (res.filterRelaxation?.droppedClauses?.length) {
console.log('Showing without:', res.filterRelaxation.droppedClauses);
}