SDK

NPM Version NPM Downloads

Start Here

This page explains how to integrate @froomle/frontend-sdk from first setup to advanced usage. It covers both declarative integrations (data-froomle-* placeholders) and programmatic integrations (JS/TS API calls and React bindings).

Use this page as a map:

Choose an Integration Pattern

Mode Integration style Use when

Declarative

HTML attribute-centric (data-froomle-*)

You want SDK-driven DOM population from placeholders. Works for plain HTML and SSR templates (including JSP-generated markup).

Declarative

JS/TS bootstrap + HTML attributes

You initialize SDK in JS/TS (setEnvironment, setPageVisit, …​), while recommendation blocks are still mapped with data-froomle-*.

Programmatic

JS/TS API-centric

You fetch recommendations directly in code with getRecommendations or proxyReco and render your own UI.

Programmatic

Component-centric (React bindings)

You use @froomle/frontend-sdk/react (useCreateReco, FroomleReco, FroomleOrder, …​) to compose recommendation UI in React.

JSP + TS is the same integration model as JS/TS bootstrap + HTML attributes. The main difference is only where markup is rendered (server template vs client template generation).

Event Tracking by Implementation Choice

Implementation choice Auto event tracking What you need to do

Declarative (data-froomle-*)

Yes

The SDK auto-tracks standard recommendation impressions/clicks for rendered blocks.

React bindings (@froomle/frontend-sdk/react)

Yes (when using SDK React rendering primitives)

Use SDK components/hooks for standard tracking behavior. For fully custom rendering, send events manually with sendEvent(…​).

Programmatic (JS/TS API)

No

Send events manually with sendEvent(…​) and follow Tracking events.

Learning Path: Beginner to Advanced

Use this sequence if you are new to the SDK:

  1. Start with one script tag and one recommendation placeholder.

  2. Add detail-page context (context_item) for article/product pages.

  3. Add filters and list variables for targeting.

  4. Add consent, identity, and histories.

  5. Move to module-based setup (npm import) for production frontend integration.

  6. Use programmatic APIs when you need direct request/render control.

  7. Use React bindings when recommendations are composed from React components.

Beginner Flow (First Working Integration)

Minimum concept:

  1. Configure environment and page visit.

  2. Add one recommendation placeholder with field mappings.

  3. Set consent.

  4. Verify /recommendations/requests in browser network logs.

If these four steps work, the rest of the SDK features are incremental extensions (filters, context item, histories, ordering, programmatic calls, React helpers).

Install and Run

Script-Tag Setup (No Build Tool)

Recommended starter (default defer mode):

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
  }, { once: true })
</script>
<script
  defer
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="your_env"
  data-froomle-page-visit="home"
></script>

Use froomle:before-init for settings that must be present on the first recommendation request.

Runtime Scope Guide

Use this quick map to choose the correct sections for your integration runtime:

Runtime Sections to use Notes

Script-tag/global (froomle.global.js)

Script-Tag Setup, Script Loading and Initialization Modes, Script-tag Whitelist

Uses HTML script attributes and init hooks (froomle:before-init, froomle:init).

Module/import (JS/TS bundles)

Module Setup, Core Configuration, Programmatic API (JS/TS)

Use imported setters (setEnvironment, setPageVisit, setConsent, …​).

React bindings

Module Setup, React Bindings, Core Configuration

React apps use module/import setup. Script-tag init hooks do not apply.

Shared (all runtimes)

Core Configuration, Recommendations in Markup, Programmatic API (JS/TS)

Setting semantics are shared across runtimes. Only bootstrap/initialization entrypoint differs.

Script Loading and Initialization Modes (Global Script Tag)

Default for script-tag integrations: use defer.

This section applies to global/script-tag usage (froomle.global.js). For React and other module/import integrations, use module setup (setEnvironment, setPageVisit, setConsent) and ignore script loading modes.

Mode Use when Key requirement

defer (default)

Most websites and CMS templates.

Register first-request JS setters in froomle:before-init; use froomle:init or window.FroomleFrontendSdkReady for post-init code.

blocking

Legacy pages that require strict synchronous script order.

Keep the SDK tag without defer/async; if first-request values are set from JS, still register froomle:before-init before the SDK tag.

async

Startup order with other scripts is not strict.

Use froomle:before-init for first-request values and froomle:init/window.FroomleFrontendSdkReady for post-init logic.

Event-driven

Complex frontends with multiple modules/microfrontends.

Use froomle:before-init for pre-init settings and froomle:init for post-init orchestration; keep the ready promise as late-safe fallback.

Hook Timing and Responsibilities

  • froomle:before-init: pre-init hook, fired before DOM init and before the first recommendation request.

  • froomle:init: post-init hook, fired once when SDK initialization completes.

  • window.FroomleFrontendSdkReady: sticky readiness promise for consumers that may attach after events already fired.

When to use each hook:

  1. Use froomle:before-init for settings that must be included in the first request: consent, custom variables, histories, dynamic channel, or runtime identity.

  2. Use froomle:init for code that depends on completed initialization (module orchestration, UI hooks, diagnostics).

  3. Use window.FroomleFrontendSdkReady as a reliable fallback for late-loaded bundles/modules.

Settings Matrix (Script-Tag Mode)

Use this matrix as the canonical checklist for what to configure where.

This matrix is only for script-tag/global integrations (froomle.global.js). React/module-import integrations do not use these hooks.

Setting Script tag attribute? Must be set before first request? Recommended place and usage

environment (setEnvironment)

Yes: data-froomle-env

Yes (required)

Put on SDK <script> tag.

page_visit (setPageVisit)

Yes: data-froomle-page-visit

Yes (required)

Put on SDK <script> tag.

request_domain (setRequestDomain)

Yes: data-froomle-request-domain

Yes (if custom domain is needed)

Use script tag for fixed value; use froomle:before-init if runtime-derived.

safe_request (setSafeRequest)

Yes: data-froomle-safe-request

Yes (if changed from default)

Use script tag for fixed value; use froomle:before-init for runtime decisions.

context_item / context_item_type

Yes: data-froomle-context-item, data-froomle-context-item-type

Yes (on detail pages)

Use script tag for fixed detail pages, or set in froomle:before-init.

user_id (setUserId)

Yes: data-froomle-user-id

Yes (if first request must be identified)

Fixed value: script tag. Runtime value (cookie/session): froomle:before-init.

device_id (setDeviceId)

Yes: data-froomle-device-id

Yes (if first request must carry device identity)

Fixed value: script tag. Runtime value: froomle:before-init.

channel (setChannel)

Yes: data-froomle-channel

Yes (if channel affects first request)

Fixed channel: script tag. Dynamic channel (viewport/device): froomle:before-init.

consent (setFroomleConsent / sdk.setConsent)

No

Yes (if first request must respect consent level)

Set in froomle:before-init. Script-tag alias: setFroomleConsent(level). Namespaced equivalent: event.detail.sdk.setConsent(level).

custom variables (setCustomVariable)

No

Yes, if variable must affect first request

First-request variables: froomle:before-init. Late/non-critical variables: froomle:init or window.FroomleFrontendSdkReady.

histories (addHistories)

No

Yes, if histories must influence first request

Set in froomle:before-init.

Post-init orchestration (non-settings)

N/A

No

Use froomle:init and/or window.FroomleFrontendSdkReady for UI wiring, telemetry, and late modules.

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
    sdk.setCustomVariable('section', 'homepage')
  }, { once: true })

  window.addEventListener('froomle:init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    // Post-init code
  })
</script>

defer (default)

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
    sdk.setCustomVariable('section', 'homepage')
  }, { once: true })
</script>
<script
  defer
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="your_env"
  data-froomle-page-visit="home"
></script>
<script>
  window.FroomleFrontendSdkReady.then(function () {
    // Post-init code
  })
</script>

blocking (legacy compatibility)

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
  }, { once: true })
</script>
<script
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="your_env"
  data-froomle-page-visit="home"
></script>
<script>
  window.FroomleFrontendSdkReady.then(function () {
    // Post-init code
  })
</script>

async (supported with readiness gating)

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
  }, { once: true })
</script>
<script
  async
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="your_env"
  data-froomle-page-visit="home"
></script>
<script>
  window.FroomleFrontendSdkReady.then(function () {
    // Post-init code
  })
</script>

Event-driven

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
    sdk.setCustomVariable('init_source', 'before-init')
  }, { once: true })

  window.addEventListener('froomle:init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    // Post-init code
  })
</script>
<script
  async
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="your_env"
  data-froomle-page-visit="home"
></script>
<script>
  window.FroomleFrontendSdkReady.then(function () {
    // Late-safe fallback
  })
</script>

froomle:before-init and froomle:init event payload:

Field Meaning

event.detail.sdk

SDK API object available at init time.

event.detail.mode

Init trigger mode: auto or manual.

event.detail.version

SDK version string when available.

mode values:

  • auto: the SDK started itself during script evaluation (standard behavior in script-tag usage).

  • manual: the SDK was started via init().

In normal script-tag integrations, you will usually see mode=auto.

Module Setup (JS/TS/React/JSP Bundles)

npm install @froomle/frontend-sdk

Initialize in code:

import { setEnvironment, setPageVisit, setConsent } from '@froomle/frontend-sdk'

setEnvironment('your_env')
setPageVisit('home')
setConsent(2)

Use the consent setter name that matches how the SDK is loaded:

Runtime mode Consent call

Script-tag/global (froomle.global.js)

setFroomleConsent(level)
or window.FroomleFrontendSdk.setConsent(level)

Module/import (npm install @froomle/frontend-sdk)

setConsent(level) from import { setConsent } …​

Local Development

For static HTML files, avoid file:// and run a local server:

python3 -m http.server 8080

For module projects, run your framework/bundler dev command (for example npm run dev or npm run serve).

Core Configuration

This section defines setting semantics shared across runtimes. For script-tag timing and hook placement (what must be set before the first request), use Script Loading and Initialization Modes and Supported Inputs by Location. React follows module/import setup and does not use script-tag init hooks.

Setter Reference and Defaults

Setting Default Script-tag attribute Typical use

setEnvironment(env)

null

data-froomle-env

Always set to your environment.

setPageVisit(pageType)

null

data-froomle-page-visit

Always set for recommendation requests.

setConsent(level)

0

(none)

In module/import setups, use setConsent(level). In script-tag/global setups, use setFroomleConsent(level).

setDeviceId(id)

no-consent

data-froomle-device-id

Optional override when you manage device IDs yourself.

setUserId(id)

null

data-froomle-user-id

Use for stable logged-in identity.

setRequestDomain(host)

europe-west1.froomle.com

data-froomle-request-domain

Override domain (custom API domain/proxy/local setup).

setChannel(channel)

www-desktop

data-froomle-channel

Force channel or set responsive channel in runtime code.

setSafeRequest(bool)

true

data-froomle-safe-request

Set to false for non-HTTPS local/dev domains.

setContextItem(itemId)

null

data-froomle-context-item

Detail pages.

setContextItemType(type)

article

data-froomle-context-item-type

Detail pages with non-default type.

setCustomVariable(key, value)

(none)

(none)

Request-root variables and custom business data.

addHistories(histories, defaultItemType?)

empty

(none)

Add history IDs or typed history entries ({ id, item_type } or { id, itemType }).

Supported Inputs by Location

Location Runtime scope Inputs What This Is For

SDK script tag

Script-tag/global only

  • data-froomle-env

  • data-froomle-page-visit

  • data-froomle-context-item

  • data-froomle-context-item-type

  • data-froomle-request-domain

  • data-froomle-device-id

  • data-froomle-user-id

  • data-froomle-safe-request

  • data-froomle-channel

Bootstraps SDK from HTML without imports. Only this whitelist is read from the script tag.

Recommendation markup

All runtimes

  • data-froomle-reco

  • data-froomle-param-*

  • data-froomle-variable-*

  • data-froomle-reco-filter-*

  • ordering attributes: data-froomle-order-*, data-froomle-ordervalue

Declarative recommendation rendering in the DOM. Use this to map item fields into existing HTML placeholders.

JS/TS module API

Module/import runtimes

  • setEnvironment

  • setPageVisit

  • setConsent

  • setDeviceId

  • setUserId

  • setRequestDomain

  • setSafeRequest

  • setChannel

  • setContextItem

  • setContextItemType

  • setCustomVariable

  • addHistories

  • getRecommendations

  • proxyReco

  • fulfillRecommendations

  • sendEvent

Code-first integration. Use this for explicit runtime control, programmatic fetching, and manual event flows.

React bindings

React only

  • FroomleSdkInit

  • useCreateReco

  • FroomleReco

  • useReco

  • FroomleOrder

  • FroomleOrderItem

  • FroomleCustomItem

React component/hook layer on top of core SDK APIs. Use this when recommendations are composed directly in React components.

Programmatic Method Quick Reference

Method Purpose

getRecommendations(lists)

Fetch recommendation lists directly in code.

proxyReco(request)

Queue a recommendation request and get a promise-like recommendation handle.

fulfillRecommendations()

Flush queued proxy requests in one batched API call.

sendEvent(actionItem, actionItemType, eventType?, extras?)

Send explicit tracking events for custom/programmatic rendering flows.

TypeScript Types and Interfaces

The SDK publishes declaration files via package exports:

  • @froomle/frontend-sdkdist/index.d.ts

  • @froomle/frontend-sdk/reactdist/react.d.ts

Typical TS imports:

import {
  addHistories,
  fulfillRecommendations,
  getRecommendations,
  proxyReco,
  sendEvent,
  setConsent,
  setDeviceId,
  setEnvironment,
  setPageVisit
} from '@froomle/frontend-sdk'
import type { RecommendationItem, Recommendations } from '@froomle/frontend-sdk'

The package exports RecommendationItem and Recommendations as types. Some helper request/input shapes are currently inferred from function signatures instead of exported as named types. The following shapes mirror current SDK declarations:

type RecoRequestShape = {
  list: string
  filters: Array<{ key: string; value: string }>
  others?: Array<{ key: string; value: unknown }>
}

type HistoryInputShape =
  | string
  | { id: string; item_type?: string | null; itemType?: string | null }

type SendEventExtrasShape = {
  [key: string]: string | number | object
}

Current signature highlights from the published declarations:

setConsent(consent: number): void
setUserId(userId: string): void
setDeviceId(deviceId: string): void
setCustomVariable(key: string, value: unknown): void

getRecommendations(lists: Array<{
  limit: number
  list_name: string
  list_size: number
  [key: string]: unknown
}>): Promise<Recommendations>

useCreateReco(req: {
  list: string
  filters: Array<{ key: string; value: string }>
  [key: string]: any
}): RecommendationItem & PromiseLike<RecommendationItem>

unknown is intentional for pass-through/custom payload values (for example setCustomVariable values and extra list keys in getRecommendations list entries). This keeps SDK typings strict without guessing backend-specific business fields.

Environment and Page Visit (Required)

Set both before requesting recommendations.

Script-tag setup:

<script
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="sample_env"
  data-froomle-page-visit="home"
></script>

Module setup:

import { setEnvironment, setPageVisit } from '@froomle/frontend-sdk'

setEnvironment('sample_env')
setPageVisit('home')

Identity: device_id and user_id

Identity usage model:

  • setUserId(…​): set when the user has a stable logged-in ID.

  • setDeviceId(…​): set only when you manage device IDs yourself (or want to unify with your own device ID).

For consent-driven identity behavior (user_id, device_id, and no-consent flows), see User identity and consent.

user_id should be a real logged-in identifier or omitted. Never set user_id to "no-consent".

If you do not set device_id, the SDK manages it automatically via froomle_device_id and generates it when consent allows tracking. For logged-in users, provide user_id; device_id can be SDK-managed or explicitly set by your own device-ID strategy.

It should never happen that one device_id is associated with multiple user_id values in the same environment.

Script-tag equivalents:

<script
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="sample_env"
  data-froomle-page-visit="home"
  data-froomle-device-id="device-123"
></script>

or

<script
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="sample_env"
  data-froomle-page-visit="home"
  data-froomle-user-id="user-456"
></script>

Identity and Storage (Cookies)

In browser/script-tag usage, the SDK persists identity and consent in first-party cookies:

  • froomle_device_id

  • froomle_user_id

  • froomle_consent

Behavior:

  • On load, the SDK reads existing cookie values and reuses them.

  • If identity is passed via script attributes or setters, the SDK updates the matching cookie.

  • Calling setFroomleConsent(…​) (or window.FroomleFrontendSdk.setConsent(…​)) updates froomle_consent.

  • When consent becomes 2 and device_id is still no-consent, the SDK generates a UUID device id and stores it.

Cookie properties in the current SDK build:

  • first-party cookie

  • path=/

  • samesite=lax

  • long-lived max-age (20 years in current implementation)

Older integrations may reference _fr_id; the current SDK implementation uses froomle_device_id.

Use setConsent(level) in modules. In script-tag integrations, setFroomleConsent(level) is the browser-global alias.

setConsent(…​) is not a bare global function in plain HTML. In script-tag pages, use setFroomleConsent(…​) or window.FroomleFrontendSdk.setConsent(…​).

setConsent(2)
// or, in plain HTML/global usage:
setFroomleConsent(2)
Level Name Recommendation requests Tracking events

0

No Tracking

Anonymous request (device_id, user_group, version set to no-consent), no user_id, no histories

Disabled

1

Analytics Only

Same anonymous request as level 0

Enabled, but anonymous identity

2

Full

Identified request (device_id, and user_id when set), histories allowed

Enabled with identified identity

Practical behavior:

  • Consent 0: popular/non-personalized behavior, no tracked events.

  • Consent 1: event tracking enabled, personalization identity still anonymous.

  • Consent 2: full personalization and identified tracking when identity is set.

Consent level Behavior

0

Requests remain anonymous, user_id and histories are excluded, and tracking events are not emitted.

1

Requests remain anonymous and omit histories; tracking events are emitted with anonymous identity.

2

Requests may include full identity and histories; tracking events are emitted with identified identity.

Detail Context and Page Tracking

For detail pages, set context item (and optional type):

import { setContextItem, setContextItemType, setPageVisit } from '@froomle/frontend-sdk'

setPageVisit('article_detail')
setContextItem('sample_item_id_2')
setContextItemType('article')

Script-tag equivalent:

<script
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="sample_env"
  data-froomle-page-visit="article_detail"
  data-froomle-context-item="sample_item_id_2"
  data-froomle-context-item-type="article"
></script>

Behavior notes:

  • context_item_type is optional; when omitted and context_item is set, SDK defaults it to article.

  • The same context (context_item / context_item_type) is used for recommendation requests and detail tracking.

  • When context_item_type is omitted, detail_pageview.action_item_type also defaults to article.

  • When context_item is present, SDK emits detail_pageview for the page and suppresses the generic page_visit event.

Request Domain, Channel, and Transport

Use these when needed:

  • setRequestDomain('your.domain')

  • setSafeRequest(false) for non-HTTPS/local environments

  • setChannel('www-desktop' | 'www-mobile')

Responsive channel example:

import { setChannel } from '@froomle/frontend-sdk'

const channel = window.matchMedia('(max-width: 767px)').matches
  ? 'www-mobile'
  : 'www-desktop'
setChannel(channel)

Minimum Initialization

Minimal module-based setup:

import { setEnvironment, setPageVisit, setConsent } from '@froomle/frontend-sdk'

setEnvironment('sample_env')
setPageVisit('home')
setConsent(2)

Minimal plain HTML setup:

<script>
  window.addEventListener('froomle:before-init', function (event) {
    var sdk = event.detail && event.detail.sdk
    if (!sdk) return
    sdk.setConsent(2)
  }, { once: true })
</script>
<script
  defer
  src="https://cdn.jsdelivr.net/npm/@froomle/frontend-sdk@latest/dist/froomle.global.js"
  data-froomle-env="sample_env"
  data-froomle-page-visit="home"
></script>

Recommendations in Markup

Recommendation Placeholder

data-froomle-reco marks a recommendation template. Each placeholder card usually maps fields with data-froomle-param-*.

How binding works:

  1. SDK requests items for each list.

  2. Each placeholder marked with data-froomle-reco receives one returned item.

  3. data-froomle-param-* attributes map item fields into DOM attributes/text.

  4. Filled nodes receive internal metadata attributes used for tracking.

<article class="reco-card" data-froomle-reco="recommended_for_you">
  <a data-froomle-param-href="uri" href="#">
    <img data-froomle-param-src="images[0]" data-froomle-param-alt="title" alt="" />
    <h3 data-froomle-param-inner="title">Loading recommendation...</h3>
  </a>
</article>

Use multiple placeholder blocks to control count (for example, 12 placeholders ⇒ up to 12 returned items).

Dynamic Injection and Refill

The SDK observes DOM mutations after initial load.

This means:

  • New nodes injected with data-froomle-reco can be auto-filled after page load.

  • Existing nodes can be refilled when you clear metadata and toggle data-froomle-reco.

Refill rule in current runtime:

  • A target is eligible when both data-froomle-request-id and data-froomle-id are missing or empty.

  • To force refill, clear those attributes, then remove/re-set data-froomle-reco.

Recommendation Parameters: data-froomle-param-*

Common mappings:

  • data-froomle-param-href="uri"

  • data-froomle-param-src="images[0]"

  • data-froomle-param-alt="title"

  • data-froomle-param-inner="title"

Nested fields are supported, for example:

<span data-froomle-param-inner="item_attributes.fq_item_id"></span>

Expression mode is also supported by prefixing with =:

  • data-froomle-param-src="=photoUrl | replace('X,','NWB,') | replace('X.','NWB.')"

  • data-froomle-param-href="=uri | append('?from=reco')"

For composed values (for example srcset), use template placeholders:

  • data-froomle-param-srcset="\${photoUrl | replace('X,','NWB,')}, \${photoUrl | replace('X,','NWBR,')} 2x"

Scope:

  • This transform syntax is for declarative HTML mapping (data-froomle-param-*).

  • It is not executed inside framework prop systems (React/Vue directives).

  • In React, apply transforms in your component code and render final values in JSX.

Supported transforms:

  • replace(from, to)

  • prepend(value)

  • append(value)

  • default(value) (used when current value is empty)

  • trim

  • lower

  • upper

  • urlencode

What is supported:

  • Field access (including nested paths)

  • Transform chains with the supported transform set

  • Template interpolation with \${…​} for composed attributes (srcset, combined labels, etc.)

What is not supported:

  • Running custom code from attribute strings

  • if/else, loops, or arbitrary scripting in markup

  • Regex/backreference syntax in transforms

Filters and Variables

Use list-level filters and variables in markup:

  • data-froomle-reco-filter-*: list filters (sent as arrays by SDK for HTML usage)

  • data-froomle-variable-*: list variables

<article
  data-froomle-reco="sample_list_name"
  data-froomle-reco-filter-race_types="MotoGP"
  data-froomle-reco-filter-article_type="News"
  data-froomle-variable-slot="1"
>
  <h3 data-froomle-param-inner="title"></h3>
</article>

List merging behavior:

  • Blocks with same list_name, same filters, and same list variables can be merged into one request.

  • Add a differentiator such as data-froomle-variable-slot to keep blocks separate.

Request-root variables must be set in JS/TS, not via markup:

import { setCustomVariable } from '@froomle/frontend-sdk'

setCustomVariable('section', '12345')

Type note: setCustomVariable is typed as setCustomVariable(key: string, value: unknown). Use application-side narrowing when you read values back in your own code.

Item IDs and Histories

Tag content items with IDs when possible:

<article class="news-card" data-froomle-id="sample_item_id_1">
  ...
</article>

This improves analytics/event attribution and helps history handling.

Inject histories (simple IDs):

import { addHistories } from '@froomle/frontend-sdk'

addHistories([
  'sample_item_id_1',
  'sample_item_id_2'
])

addHistories([…​]) generates histories.pageviews. For string IDs, item_type defaults to article.

Inject typed histories when explicit item_type is needed:

import { addHistories } from '@froomle/frontend-sdk'

addHistories([
  { id: 'sample_item_id_1', item_type: 'article' },
  { id: 'sample_item_id_2', item_type: 'video' },
  { id: 'sample_item_id_3', itemType: 'podcast' } // `itemType` alias is supported
], 'article') // fallback item_type for entries without explicit type

Behavior note:

  • addHistories(…​) appends entries to histories.pageviews in outgoing recommendation requests.

  • For string entries, SDK uses defaultItemType (or article when omitted).

  • For object entries, SDK uses item_type or itemType; if missing, it falls back to defaultItemType (or article).

  • setCustomVariable('histories', …​) still writes the raw histories field directly. If both are used, the explicit custom histories value is applied.

  • This is separate from context_item_type (used for detail context and detail_pageview), which defaults to article when omitted.

Ordering Sections

Use ordering when you want to reorder existing blocks from recommendation signals.

Ordering Container

<div data-froomle-order-categories="recommended_for_you">
  ...
</div>

categories is the field to order by. recommended_for_you is the list used for ordering.

Elements To Order

Children that participate in ordering need data-froomle-ordervalue:

<div data-froomle-order-categories="recommended_for_you">
  <section data-froomle-ordervalue="Sports">Sports block</section>
  <section data-froomle-ordervalue="Politique">Politics block</section>
  <section data-froomle-ordervalue="Monde">World block</section>
</div>

Programmatic API (JS/TS)

Use programmatic mode when markup placeholders are not enough. Typical cases:

  • You want to fetch recommendations before rendering UI.

  • You want explicit batching control across multiple requests.

  • You render custom UI and must send events manually.

No data-froomle-* placeholders are required in this mode.

How it works:

  1. Configure SDK state (setEnvironment, setPageVisit, consent, identity).

  2. Request recommendation items (getRecommendations or proxy flow).

  3. Render with your own UI code.

  4. Track events explicitly with sendEvent when required by your reporting setup.

getRecommendations

import { getRecommendations } from '@froomle/frontend-sdk'

const response = await getRecommendations([
  {
    list_name: 'recommended_for_you',
    limit: 4,
    list_size: 4
  }
])

const items = response.items()

Type note: list entries are typed with required limit, list_name, and list_size, plus optional additional keys typed as [key: string]: unknown.

Response item shape:

  • response.items() returns RecommendationItem[].

  • Each RecommendationItem always includes:

    • Id: string

    • RequestId: string

    • UserGroup: string

  • Content fields are model/backend-dependent and are accessed via item.get(key). There is no single fixed payload schema for these dynamic keys.

for (const item of response.items()) {
  const id = item.Id
  const requestId = item.RequestId
  const userGroup = item.UserGroup

  // Dynamic payload fields depend on your recommendation setup.
  const title = item.get('title')
  const uri = item.get('uri')
  const image = item.get('image') ?? item.get('images')?.[0]
}

Error handling:

  • getRecommendations(…​) returns a promise and rejects on request/HTTP/response-parse failures.

  • Handle with try/catch (or .catch(…​)) in programmatic flows.

try {
  const response = await getRecommendations([
    { list_name: 'recommended_for_you', limit: 4, list_size: 4 }
  ])
  // use response
} catch (error) {
  // network / HTTP / parse failure
}

Need full request payload rules (required fields, list structure, histories, batching)? See Recommendation requests.

proxyReco + fulfillRecommendations

Queue multiple requests first, then resolve in one batch call.

import { proxyReco, fulfillRecommendations } from '@froomle/frontend-sdk'

const first = proxyReco({ list: 'recommended_for_you', filters: [] })
const second = proxyReco({ list: 'recommended_for_you', filters: [] })

await fulfillRecommendations()
const [itemA, itemB] = await Promise.all([first, second])

Error handling:

  • proxyReco(…​) returns a promise-like recommendation handle; it does not resolve to null.

  • Each proxy resolves to a RecommendationItem or rejects.

  • Rejection cases include:

    • batch request failure in fulfillRecommendations()

    • fewer returned items than queued requests (No recommendation available)

const first = proxyReco({ list: 'recommended_for_you', filters: [] })
const second = proxyReco({ list: 'recommended_for_you', filters: [] })

try {
  await fulfillRecommendations()
} catch (error) {
  // batch request failed; queued proxies reject
}

const results = await Promise.allSettled([first, second])

sendEvent

Use manual event tracking when you need explicit control.

import { sendEvent } from '@froomle/frontend-sdk'

sendEvent('sample_item_id_1', 'article', 'impression', {
  list_name: 'recommended_for_you',
  request_id: 'req-id',
  user_id: 'user-456'
})

Need the full event contract (event types, required fields, and delivery guidance)? See Tracking events.

  • sendEvent auto-populates base fields from SDK runtime state: event_type, action_item, action_item_type, page_type, channel, device_id, and (when available) user_group.

  • extras is merged last. Use it to add fields such as list_name, request_id, user_id, or to intentionally override default fields (for example page_type / channel) in custom flows.

  • Script-tag attributes are bootstrap inputs for SDK state; they are not per-event arguments to sendEvent(…​).

  • For programmatic integrations, event payloads and event types must follow Tracking events.

extras requirement guide:

Field in extras Requirement

list_name, request_id

For recommendation-related events (impression, click_on_recommendation), treat these as required for reliable attribution/reporting. For non-recommendation events, they are optional.

user_group

Required for recommendation-related events. The SDK auto-populates it when available from runtime/DOM state; pass it explicitly in custom flows when that state is unavailable.

user_id

Optional per call. Include when the user is identified and consent allows tracking. sendEvent(…​) does not auto-add user_id.

page_type, channel, device_id

Optional overrides only. The SDK already sets these from runtime state.

React Bindings

React helpers are exposed from @froomle/frontend-sdk/react. Use this layer when your recommendation blocks are React components instead of DOM templates with data-froomle-*.

Mental model:

  1. Configure SDK once in main.jsx.

  2. Wrap the app with FroomleSdkInit.

  3. Create recommendation handles with useCreateReco.

  4. Render with FroomleReco / useReco.

  5. Add advanced composition with FroomleOrder and FroomleCustomItem.

import React from 'react'
import ReactDom from 'react-dom/client'
import { setEnvironment, setPageVisit, setConsent } from '@froomle/frontend-sdk'
import { FroomleSdkInit } from '@froomle/frontend-sdk/react'
import App from './App'

setEnvironment('sample_env')
setPageVisit('home')
setConsent(2)

ReactDom.createRoot(document.getElementById('root')).render(
  <FroomleSdkInit>
    <App />
  </FroomleSdkInit>
)

Core React primitives:

  • useCreateReco({ list, filters })

  • FroomleReco

  • useReco

  • FroomleOrder and FroomleOrderItem

  • FroomleCustomItem

React Component Behavior

useCreateReco

useCreateReco(…​) returns a recommendation handle, not just a settled item.

Return value:

  • Type: RecommendationItem & PromiseLike<RecommendationItem>.

  • You pass this handle to <FroomleReco reco={…​}>.

  • The same handle also exposes recommendation fields (for example reco.uri) once resolved.

  • Dynamic keys can always be read with reco.get('field_name').

Practical guidance:

  • If you want the clearest render flow, read recommendation fields via useReco() inside a FroomleReco subtree.

  • Direct field access on the handle is supported, but those fields are empty until the reco resolves.

FroomleReco

FroomleReco is a wrapper component around a single recommendation handle.

Props:

  • reco: recommendation handle from useCreateReco(…​) (or equivalent).

  • children: render content.

  • Any extra props (id, className, data-*, …​) are forwarded to its wrapper element.

Runtime behavior:

  • Renders a <div> wrapper and places children inside it.

  • Does not clone or replace children.

  • Resolves reco and writes recommendation metadata on the wrapper: data-froomle-reco (when list is known), data-froomle-id, data-froomle-item-type, data-froomle-request-id, data-froomle-user-group.

  • Provides the reco value through React context for useReco().

useReco() behavior:

  • Returns the current recommendation from the nearest FroomleReco provider.

  • Throws if called outside a FroomleReco subtree.

FroomleCustomItem

FroomleCustomItem is for manually inserted editorial/custom items that should still influence recommendation history.

Props:

  • id: item id to add to histories.

  • children: rendered content.

Runtime behavior:

  • Renders children as-is in a fragment (no extra DOM wrapper).

  • Calls addHistories([id]) once per mount.

  • Does not fetch recommendations.

  • Does not inject recommendation attributes or clone children.

Example usage:

import {
  FroomleReco,
  FroomleOrder,
  FroomleOrderItem,
  FroomleCustomItem,
  useCreateReco,
  useReco
} from '@froomle/frontend-sdk/react'

function RecoLink() {
  const reco = useReco()
  return <a href={reco.get('uri')}>{reco.get('title')}</a>
}

function Example() {
  const recoHandle = useCreateReco({ list: 'recommended_for_you', filters: [] })

  return (
    <>
      <FroomleReco reco={recoHandle}>
        <RecoLink />
      </FroomleReco>

      <FroomleOrder list="recommended_for_you" category="categories">
        <FroomleOrderItem value="Sports"><section>Sports</section></FroomleOrderItem>
        <FroomleOrderItem value="Monde"><section>World</section></FroomleOrderItem>
      </FroomleOrder>

      <FroomleCustomItem id="sample_item_id_1">
        <article>Editorial item</article>
      </FroomleCustomItem>
    </>
  )
}

Advanced Integration Notes

Script-tag Whitelist

Only these attributes are read from the SDK <script> tag:

  • data-froomle-env

  • data-froomle-page-visit

  • data-froomle-context-item

  • data-froomle-context-item-type

  • data-froomle-request-domain

  • data-froomle-device-id

  • data-froomle-user-id

  • data-froomle-safe-request

  • data-froomle-channel

Everything else should be set via JS/TS setters.

Event Tracking Behavior

The SDK handles common tracking automatically for DOM-based recommendation rendering. For custom flows and programmatic rendering, use sendEvent(…​) explicitly.

If you send events manually, adhere to the standard event contract documented in Tracking events.

Practical rule:

  • If you render recommendations yourself, send impression/click events yourself.

  • Include list_name and request_id for reliable reporting attribution.

action_item_type resolution:

  • detail_pageview: uses context_item_type, defaults to article.

  • impression and click_on_recommendation: use data-froomle-item-type (or data-froomle-action-item-type) when present, otherwise default to article.

  • DOM-filled recommendation nodes automatically get data-froomle-item-type when item_type exists in the recommendation response.

Troubleshooting and Validation

When recommendations do not appear:

  • Verify setEnvironment / data-froomle-env.

  • Verify setPageVisit / data-froomle-page-visit.

  • Check list name (data-froomle-reco or programmatic request list).

  • Check field mappings (uri, images[0], title, or your schema fields).

  • Check network requests to /recommendations/requests.

  • For consent tests, run on http://localhost (cookies do not behave reliably on file://).

  • In webpack dev server setups, keep HMR/live reload disabled when debugging SDK DOM behavior.

Stack-specific checks:

  • Plain HTML: confirm SDK script loads (no CSP/CORS blocking in console).

  • TS/Webpack: confirm SDK init code runs before placeholders are rendered.

  • JSP + TS: confirm the compiled JS bundle is generated and loaded by the JSP page.

  • JSP + TS: for server 503 responses, inspect application server logs and verify JSP/web configuration.

  • Programmatic: if UI renders but events are missing, verify SDK state is initialized (setEnvironment, setPageVisit, consent), and verify sendEvent(…​) extras include required list metadata (list_name, request_id) and any custom overrides.

  • React: verify app is wrapped in FroomleSdkInit and list/filter args passed to useCreateReco are correct.

For full end-to-end sample projects, see frontend-sdk-examples.