Contentful Personalization & Analytics
    Preparing search index...

    Module @contentful/optimization-core - v0.0.0

    Optimization Core SDK — platform-agnostic optimization and analytics.

    Contentful Logo

    Contentful Optimization Core SDK

    Optimization Core SDK

    Guides · Reference · Contributing

    Warning

    The Optimization SDK Suite is pre-release (alpha). Breaking changes may be published at any time.

    The Optimization Core SDK encapsulates all platform-agnostic functionality and business logic. All other SDKs descend from the Core SDK.

    Table of Contents

    Install using an NPM-compatible package manager, pnpm for example:

    pnpm install @contentful/optimization-core
    

    Import either the stateful or stateless Core class, depending on the target environment; both CJS and ESM module systems are supported, ESM preferred:

    import { CoreStateful } from '@contentful/optimization-core'
    // or
    import { CoreStateless } from '@contentful/optimization-core'

    Configure and initialize the Core SDK:

    const optimization = new CoreStateful({ clientId: 'abc123' })
    // or
    const optimization = new CoreStateless({ clientId: 'abc123' })

    The CoreStateless class is intended to be used as the basis for SDKs that would run in stateless environments such as Node-based servers and server-side functions in meta-frameworks such as Next.js.

    In stateless environments, Core will not maintain any internal state, which includes user consent. These concerns should be handled by consumers to fit their specific architectural and design specifications.

    The CoreStateful class is intended to be used as the basis for SDKs that would run in stateful environments such as Web front-ends and mobile applications (via JavaScript runtime containers).

    In stateful environments, Core maintains state internally for consent, an event stream, and profile-related data that is commonly obtained from requests to the Experience API. These states are exposed externally as read-only observables.

    Important

    CoreStateful uses module-global state by design. Initialize exactly one stateful instance per JavaScript runtime and reuse it.

    Option Required? Default Description
    api No See "API Options" Unified configuration for the Experience API and Insights API endpoints
    clientId Yes N/A Shared API key for Experience API and Insights API requests
    environment No 'main' The environment identifier
    eventBuilder No See "Event Builder Options" Event builder configuration (channel/library metadata, etc.)
    fetchOptions No See "Fetch Options" Configuration for Fetch timeout and retry functionality
    logLevel No 'error' Minimum log level for the default console sink

    The following configuration options apply only in stateful environments:

    Option Required? Default Description
    allowedEventTypes No ['identify', 'page', 'screen'] Allow-listed event types permitted when consent is not set
    defaults No undefined Set of default state values applied on initialization
    getAnonymousId No undefined Function used to obtain an anonymous user identifier
    onEventBlocked No undefined Callback invoked when an event call is blocked by guards
    queuePolicy No See "Queue Policy Options" Shared queue and retry configuration for stateful delivery

    Configuration method signatures:

    • getAnonymousId: () => string | undefined
    • onEventBlocked: (event: BlockedEvent) => void
    Option Required? Default Description
    experienceBaseUrl No 'https://experience.ninetailed.co/' Base URL for the Experience API
    insightsBaseUrl No 'https://ingest.insights.ninetailed.co/' Base URL for the Insights API
    enabledFeatures No ['ip-enrichment', 'location'] Enabled features the Experience API may use for each request
    ip No undefined IP address override used by the Experience API for location analysis
    locale No 'en-US' (in API) Locale used to translate location.city and location.country
    plainText No false Sends performance-critical Experience API endpoints in plain text
    preflight No false Instructs the Experience API to aggregate a new profile state but not store it

    The following configuration option applies only in stateful environments:

    Option Required? Default Description
    beaconHandler No undefined Handler used to enqueue Insights API events via the Beacon API or equivalent

    Configuration method signatures:

    • beaconHandler: (url: string | URL, data: BatchInsightsEventArray) => boolean

    queuePolicy is available only in CoreStateful and combines shared flush retry settings with Experience API offline buffering controls.

    Configuration shape:

    {
    flush?: {
    baseBackoffMs?: number,
    maxBackoffMs?: number,
    jitterRatio?: number,
    maxConsecutiveFailures?: number,
    circuitOpenMs?: number,
    onFlushFailure?: (context: QueueFlushFailureContext) => void,
    onCircuitOpen?: (context: QueueFlushFailureContext) => void,
    onFlushRecovered?: (context: QueueFlushRecoveredContext) => void
    },
    offlineMaxEvents?: number,
    onOfflineDrop?: (context: ExperienceQueueDropContext) => void
    }

    Supporting callback payloads:

    type ExperienceQueueDropContext = {
    droppedCount: number
    droppedEvents: ExperienceEventArray
    maxEvents: number
    queuedEvents: number
    }

    type QueueFlushFailureContext = {
    consecutiveFailures: number
    queuedBatches: number
    queuedEvents: number
    retryDelayMs: number
    }

    type QueueFlushRecoveredContext = {
    consecutiveFailures: number
    }

    Notes:

    • flush applies the same retry/backoff/circuit policy to both Insights API flushing and Experience API offline replay.
    • Invalid numeric values fall back to defaults.
    • jitterRatio is clamped to [0, 1].
    • maxBackoffMs is normalized to be at least baseBackoffMs.
    • Failed flush attempts include both false responses and thrown send errors.

    Event builder options should only be supplied when building an SDK on top of Core or any of its descendent SDKs.

    Option Required? Default Description
    app No undefined The application definition used to attribute events to a specific consumer app
    channel Yes N/A The channel that identifies where events originate from (e.g. 'web', 'mobile')
    library Yes N/A The client library metadata that is attached to all events

    The channel option may contain one of the following values:

    • web
    • mobile
    • server

    The following configuration options apply only in stateful environments:

    Option Required? Default Description
    getLocale No () => 'en-US' Function used to resolve the locale for outgoing events
    getPageProperties No () => DEFAULT_PAGE_PROPERTIES Function that returns the current page properties
    getUserAgent No () => undefined Function used to obtain the current user agent string when applicable

    Configuration method signatures:

    • getLocale: () => string | undefined

    • getPageProperties:

      () => {
      path: string,
      query: Record<string, string>,
      referrer: string,
      search: string,
      title?: string,
      url: string
      }
    • getUserAgent: () => string | undefined

    Fetch options allow for configuration of a Fetch API-compatible fetch method and the retry/timeout logic integrated into the SDK's bundled API clients. Specify the fetchMethod when the host application environment does not offer a fetch method that is compatible with the standard Fetch API in its global scope.

    Option Required? Default Description
    fetchMethod No undefined Signature of a fetch method used by the API clients
    intervalTimeout No 0 Delay (in milliseconds) between retry attempts
    onFailedAttempt No undefined Callback invoked whenever a retry attempt fails
    onRequestTimeout No undefined Callback invoked when a request exceeds the configured timeout
    requestTimeout No 3000 Maximum time (in milliseconds) to wait for a response before aborting
    retries No 1 Maximum number of retry attempts

    Configuration method signatures:

    • fetchMethod: (url: string | URL, init: RequestInit) => Promise<Response>
    • onFailedAttempt and onRequestTimeout: (options: FetchMethodCallbackOptions) => void
    Note

    Core inherits the API Client retry contract: default retries intentionally apply only to HTTP 503 responses (Service Unavailable). This is deliberate and aligned with current Experience API and Insights API expectations; do not broaden retry status handling without an explicit API contract change.

    The methods in this section are available in both stateful and stateless Core classes. However, be aware that there are some minor differences in argument usage between stateful and stateless Core implementations.

    Arguments marked with an asterisk (*) are always required.

    Get the specified Custom Flag's value from the provided changes array, or from the current internal state in stateful implementations.

    Arguments:

    • name*: The name/key of the Custom Flag
    • changes: Changes array

    Returns:

    • The resolved value for the specified Custom Flag, or undefined if it cannot be found.

    Behavior notes:

    • In CoreStateful, calling getFlag(...) automatically emits a flag view event via trackFlagView.
    • In CoreStateless, getFlag(...) does not auto-emit a flag view event.
    • If full map resolution is needed for advanced use cases, use optimization.flagsResolver.resolve(changes).
    Note

    If the changes argument is omitted in stateless implementations, the method will return undefined.

    Resolve a baseline Contentful entry to an optimized variant using the provided selected optimizations, or from the current internal state in stateful implementations.

    Type arguments:

    • S: Entry skeleton type
    • M: Chain modifiers
    • L: Locale code

    Arguments:

    • entry*: The baseline entry to resolve
    • selectedOptimizations: Selected optimizations

    Returns:

    • The resolved optimized entry variant, or the supplied baseline entry if baseline is the selected variant or a variant cannot be found.
    Note

    If the selectedOptimizations argument is omitted in stateless implementations, the method will return the baseline entry.

    Resolve a "Merge Tag" to a value based on the current (or provided) profile. A "Merge Tag" is a special Rich Text fragment supported by Contentful that specifies a profile data member to be injected into the Rich Text when rendered.

    Arguments:

    • embeddedNodeEntryTarget*: The merge tag entry node to resolve
    • profile: The user profile
    Note

    If the profile argument is omitted in stateless implementations, the method will return the merge tag's fallback value.

    Only the following methods may return an OptimizationData object:

    • identify
    • page
    • screen
    • track
    • trackView (when payload.sticky is true)

    trackClick, trackHover, and trackFlagView return no data. When returned, OptimizationData contains:

    • changes: Currently used for Custom Flags
    • selectedOptimizations: Selected optimizations for the profile
    • profile: Profile associated with the evaluated events

    Identify the current profile/visitor to associate traits with a profile.

    Arguments:

    • payload*: Identify event builder arguments object, including an optional profile property with a PartialProfile value that requires only an id

    Record an Experience API page view.

    Arguments:

    • payload*: Page view event builder arguments object, including an optional profile property with a PartialProfile value that requires only an id

    Record an Experience API screen view.

    Arguments:

    • payload*: Screen view event builder arguments object, including an optional profile property with a PartialProfile value that requires only an id

    Record an Experience API custom track event.

    Arguments:

    • payload*: Track event builder arguments object, including an optional profile property with a PartialProfile value that requires only an id

    Record an Insights API entry view event. When the payload marks the entry as "sticky", an additional Experience API entry view is recorded. This method only returns OptimizationData when the entry is marked as "sticky".

    Arguments:

    • payload*: Entry view event builder arguments object, including an optional profile property with a PartialProfile value that requires only an id

    Record an Insights API entry click event.

    Returns:

    • void

    Arguments:

    • payload*: Entry click event builder arguments object

    Record an Insights API entry hover event.

    Returns:

    • void

    Arguments:

    • payload*: Entry hover event builder arguments object

    Track a feature flag view via the Insights API. This is functionally the same as a non-sticky flag view event.

    Returns:

    • void

    Arguments:

    • payload*: Flag view event builder arguments object

    Updates the user consent state.

    Arguments:

    • accept: A boolean value specifying whether the user has accepted (true) or denied (false)

    Resets all internal state except consent. This method expects no arguments and returns no value.

    Flushes queued Insights API and Experience API events. This method expects no arguments and returns a Promise<void>.

    Releases singleton ownership for stateful runtime usage. This is intended for explicit teardown paths, such as tests or hot-reload workflows. This method expects no arguments and returns no value.

    Registers a preview consumer object and exposes internal signal references used by first-party preview tooling.

    Arguments:

    • previewPanel: Required object that receives symbol-keyed signal bridge values

    Returns:

    • void

    Bridge symbols:

    • PREVIEW_PANEL_SIGNALS_SYMBOL: key used to expose internal signals
    • PREVIEW_PANEL_SIGNAL_FNS_SYMBOL: key used to expose internal signalFns

    Example:

    import {
    PREVIEW_PANEL_SIGNAL_FNS_SYMBOL,
    PREVIEW_PANEL_SIGNALS_SYMBOL,
    type PreviewPanelSignalObject,
    } from '@contentful/optimization-core'

    const previewBridge: PreviewPanelSignalObject = {}
    optimization.registerPreviewPanel(previewBridge)

    const signals = previewBridge[PREVIEW_PANEL_SIGNALS_SYMBOL]
    const signalFns = previewBridge[PREVIEW_PANEL_SIGNAL_FNS_SYMBOL]
    Important

    This method intentionally exposes mutable internal signals for preview tooling. The Web and React Native preview panels are tightly coupled by design and rely on this bridge (plus state interceptors) to apply immediate local overrides without network round-trips. This coupling is deliberate and necessary for preview functionality.

    states is available on CoreStateful and exposes signal-backed observables for runtime state.

    Available state streams:

    • consent: Current consent state (boolean | undefined)
    • blockedEventStream: Latest blocked-call metadata (BlockedEvent | undefined)
    • eventStream: Latest emitted Insights API or Experience API event (InsightsEvent | ExperienceEvent | undefined)
    • flag(name): Key-scoped flag observable (Observable<Json>)
    • canOptimize: Whether optimization selections are available (boolean; selectedOptimizations !== undefined)
    • profile: Current profile (Profile | undefined)
    • selectedOptimizations: Current selected optimizations (SelectedOptimizationArray | undefined)
    • previewPanelAttached: Preview panel attachment state (boolean)
    • previewPanelOpen: Preview panel open state (boolean)

    Each observable provides:

    • current: Deep-cloned snapshot of the latest value
    • subscribe(next): Immediately emits current, then emits future updates
    • subscribeOnce(next): Emits the first non-nullish value, then auto-unsubscribes

    current and callback payloads are deep-cloned snapshots, so local mutations do not affect Core's internal signal state.

    Update behavior:

    • blockedEventStream updates whenever a call is blocked by consent guards.
    • eventStream updates when a valid event is accepted for send/queue.
    • flag(name) updates when the resolved value for that key changes.
    • canOptimize updates whenever selectedOptimizations becomes defined or undefined.
    • consent updates from defaults and optimization.consent(...).
    • previewPanelAttached and previewPanelOpen are controlled by preview tooling and are preserved across reset().

    Example: read the latest snapshot synchronously:

    const profile = optimization.states.profile.current
    if (profile) console.log(`Current profile: ${profile.id}`)

    Example: subscribe and clean up:

    const sub = optimization.states.profile.subscribe((profile) => {
    if (!profile) return
    console.log(`Profile ${profile.id} updated`)
    })

    // later (component unmount / teardown)
    sub.unsubscribe()

    Example: wait for first available profile:

    optimization.states.profile.subscribeOnce((profile) => {
    console.log(`Profile ${profile.id} loaded`)
    })

    Interceptors may be used to read and/or modify data flowing through the Core SDK.

    • event: Intercepts an event's data before it is queued and/or emitted
    • state: Intercepts state data retrieved from an Experience API call before updating the SDK's internal state

    Example interceptor usage:

    optimization.interceptors.event((event) => {
    event.properties.timestamp = new Date().toISOString()
    })
    Warning

    Interceptors are intended to enable low-level interoperability; to simply read and react to Optimization SDK events, use the states observables.

    Classes

    CoreStateful
    CoreStateless
    EventBuilder
    InterceptorManager

    Interfaces

    BlockedEvent
    ConsentController
    ConsentGuard
    CoreApiConfig
    CoreConfig
    CoreConfigDefaults
    CoreStatefulConfig
    CoreStatelessConfig
    CoreStates
    EventBuilderConfig
    ExperienceQueueDropContext
    GuardedByOptions
    LifecycleInterceptors
    Observable
    PreviewPanelSignalObject
    QueueFlushFailureContext
    QueueFlushPolicy
    QueueFlushRecoveredContext
    QueuePolicy
    ResolvedData
    Signal
    SignalFns
    Signals
    Subscription

    Type Aliases

    BlockedEventReason
    BlockHandler
    ClickBuilderArgs
    EntryInteractionBuilderArgsBase
    EventType
    FlagViewBuilderArgs
    GuardedByFunction
    HoverBuilderArgs
    IdentifyBuilderArgs
    Interceptor
    MaybePromise
    PageViewBuilderArgs
    ScreenViewBuilderArgs
    TrackBuilderArgs
    UniversalEventBuilderArgs
    ViewBuilderArgs

    Variables

    ANONYMOUS_ID_KEY
    ANONYMOUS_ID_KEY_LEGACY
    CHANGES_CACHE_KEY
    ClickBuilderArgs
    DEBUG_FLAG_KEY
    DEFAULT_PAGE_PROPERTIES
    EntryInteractionBuilderArgsBase
    FlagsResolver
    FlagViewBuilderArgs
    HoverBuilderArgs
    IdentifyBuilderArgs
    MergeTagValueResolver
    OPTIMIZATION_CORE_SDK_NAME
    OPTIMIZATION_CORE_SDK_VERSION
    OptimizedEntryResolver
    PageViewBuilderArgs
    PREVIEW_PANEL_SIGNAL_FNS_SYMBOL
    PREVIEW_PANEL_SIGNALS_SYMBOL
    PROFILE_CACHE_KEY
    ScreenViewBuilderArgs
    SELECTED_OPTIMIZATIONS_CACHE_KEY
    signalFns
    signals
    TrackBuilderArgs
    UniversalEventBuilderArgs
    ViewBuilderArgs

    Functions

    batch
    effect
    guardedBy
    toDistinctObservable
    toObservable