Contentful Personalization & Analytics
    Preparing search index...

    Module @contentful/optimization-web - v0.0.0

    Contentful ContentfulOptimization Web SDK.

    Exposes Web-specific utilities such as ContentfulOptimization, beaconHandler, and LocalStore. Core and transitive API exports are available from dedicated entrypoints: @contentful/optimization-web/core-sdk, @contentful/optimization-web/api-client, and @contentful/optimization-web/api-schemas.

    Contentful Logo

    Contentful Personalization & Analytics

    Optimization Web SDK

    Guides · Reference · Contributing

    Warning

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

    This SDK implements browser-specific optimization behavior on top of the Optimization Core SDK. Use it directly for non-React browser applications, framework adapters, and client-side runtimes that need consent state, anonymous ID persistence, automatic entry interaction tracking, and browser-side event delivery.

    If you are integrating a browser application, start with Getting Started, then use Integrating the Optimization Web SDK in a web app for the step-by-step flow. This README keeps the package orientation and common setup options close at hand; generated reference documentation remains the source of truth for exported API signatures.

    Table of Contents

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

    pnpm install @contentful/optimization-web
    

    Import the Optimization class; both CJS and ESM module systems are supported, ESM preferred:

    import ContentfulOptimization from '@contentful/optimization-web'
    

    Configure and initialize the Optimization Web SDK once per page runtime:

    const optimization = new ContentfulOptimization({
    clientId: 'your-client-id',
    environment: 'main',
    locale: 'en-US',
    })
    Important

    Initialize the Web SDK once per page runtime. Reuse window.contentfulOptimization or your own singleton container binding instead of creating additional instances.

    The UMD build is available for HTML pages that do not use a bundler:

    <script src="https://cdn.jsdelivr.net/npm/@contentful/optimization-web@latest/dist/contentful-optimization-web.umd.js"></script>
    <script>
    window.contentfulOptimization = new ContentfulOptimization({
    clientId: 'your-client-id',
    environment: 'main',
    locale: 'en-US',
    })
    </script>

    The optional Web Components entrypoint provides vanilla custom elements from the same package:

    import { defineContentfulOptimizationElements } from '@contentful/optimization-web/web-components'

    defineContentfulOptimizationElements()

    Importing @contentful/optimization-web/web-components is side-effect-free. Custom elements are registered only when defineContentfulOptimizationElements() runs, and the main @contentful/optimization-web entrypoint does not export or register them.

    Use <ctfl-optimization-root> once around the entries that should share one SDK instance:

    <ctfl-optimization-root client-id="your-client-id" environment="main" locale="en-US">
    <ctfl-optimized-entry id="hero-entry">
    <article>Baseline content rendered by your app</article>
    </ctfl-optimized-entry>
    </ctfl-optimization-root>

    Assign complex values as DOM properties, not string attributes:

    const root = document.querySelector('ctfl-optimization-root')
    const entry = document.querySelector('ctfl-optimized-entry')

    root.defaults = { consent: true }
    root.api = { preflight: false }
    root.trackEntryInteraction = { views: true, clicks: true }
    root.onStatesReady = (states) => {
    const subscription = states.profile.subscribe((profile) => {
    console.log(profile?.id)
    })

    return () => {
    subscription.unsubscribe()
    }
    }

    entry.baselineEntry = baselineEntry
    entry.addEventListener('ctfl-entry-resolved', (event) => {
    renderHero(event.detail.entry)
    })

    baselineEntry is property-only because Contentful entries are structured objects. For framework wrappers, assign baselineEntry, sdk, defaults, api, and callback properties after client hydration, then listen for ctfl-entry-loading, ctfl-entry-resolved, and ctfl-entry-error to render framework-owned UI. The custom element intentionally does not provide a framework-neutral render-prop API.

    For script-tag usage, load the main Web SDK UMD bundle and the separate Web Components UMD bundle:

    <script src="https://cdn.jsdelivr.net/npm/@contentful/optimization-web@latest/dist/contentful-optimization-web.umd.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@contentful/optimization-web@latest/dist/contentful-optimization-web-components.umd.js"></script>
    <script>
    ContentfulOptimizationWebComponents.defineContentfulOptimizationElements()
    </script>

    SSR output can include inert custom-element markup. On the client, call defineContentfulOptimizationElements() and assign object properties before expecting entries to resolve. A root shares SDK readiness and preview-panel live-update state with descendant entries; entries diff data-ctfl-* host attributes and clean up subscriptions on disconnect. Prefer one root per SDK instance unless a page genuinely needs separate SDK ownership.

    Use @contentful/optimization-web for browser applications that need the stateful Web runtime directly, including consent state, anonymous ID persistence, automatic entry interaction tracking, and browser-side event delivery.

    We recommend starting React applications with @contentful/optimization-react-web, which wraps this SDK with React providers, hooks, router adapters, and entry-rendering primitives.

    The Web SDK communicates with the Experience API for profile and optimization selection, and with the Insights API for event ingestion.

    Option Required? Default Description
    clientId Yes N/A Shared API key for Experience API and Insights API requests
    environment No 'main' Contentful environment identifier
    api No See API options below Experience API and Insights API endpoint and request options
    app No undefined Application metadata attached to outgoing event context
    locale No undefined SDK Experience API and default event locale
    defaults No undefined Initial state, commonly including consent, persistence consent, or profile values
    allowedEventTypes No ['identify', 'page'] Event types allowed before consent is explicitly set
    autoTrackEntryInteraction No { views: false, clicks: false, hovers: false } Opt-in automatic tracking for entry views, clicks, and hovers
    cookie No { domain: undefined, expires: 365 } Anonymous ID cookie settings
    getAnonymousId No undefined Function used to provide an anonymous ID from application-owned identity state
    queuePolicy No SDK defaults Flush retry behavior and offline queue bounds
    logLevel No 'error' Minimum log level for the default console sink
    onEventBlocked No undefined Callback invoked when consent or guard logic blocks an event

    Common api options:

    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'] Experience API features to apply to each request
    preflight No false Aggregate a new profile state without storing it
    beaconHandler No Built-in beacon integration Custom handler for enqueueing Insights API batches when needed
    plainText No false Sends performance-critical Experience API endpoints as plain text

    Common fetchOptions are fetchMethod, requestTimeout, retries, intervalTimeout, onFailedAttempt, and onRequestTimeout. Default retries intentionally apply only to HTTP 503 responses.

    Choose the application Contentful locale in your router, i18n layer, or app configuration. Pass that value directly to Contentful CDA requests. Use the top-level SDK locale when Experience API responses and event context should use the same language. See Locale handling in the Optimization SDK Suite for the full locale model.

    Use optimization.setLocale(nextLocale) when the application locale changes. The method validates the explicit input, updates optimization.locale and optimization.states.locale, and changes the default Experience API locale. It does not fetch content or refresh profile state; call page(), identify(), or CDA methods again when the app needs localized data for the new locale.

    For every option, callback payload, and exported type, use the generated Web SDK reference.

    Consent is application policy. The SDK stores event consent, blocks non-allowed events until event consent is accepted, and can track durable profile-continuity persistence consent separately. For cross-SDK consent guidance, see Consent management in the Optimization SDK Suite.

    For default-on application policies that do not render an end-user consent UI, seed accepted consent at startup:

    const optimization = new ContentfulOptimization({
    clientId: 'your-client-id',
    defaults: { consent: true },
    })
    optimization.consent(true)

    optimization.consent({ events: true, persistence: false })

    const { accepted, data } = await optimization.page({
    properties: { path: window.location.pathname },
    })

    The startup default and boolean consent calls grant or withdraw both event emission and durable profile continuity by default. Object-form consent lets events emit while keeping profile, selected optimizations, changes, and the anonymous ID session-only until persistence consent is granted.

    page(), identify(), screen(), track(), and sticky trackView() calls return an event result. { accepted: false } means consent or SDK guards blocked the event. { accepted: true, data } means the SDK accepted the event; accepted queued or offline events may not have data yet. Router integrations that need current-route deduplication can call trackCurrentPage(). Direct manual page() calls remain non-deduping event emits.

    Fetch Contentful entries in your application layer, then use the SDK to resolve the selected variant:

    const { accepted, data: optimizationData } = await optimization.page({
    properties: { path: location.pathname },
    })
    const resolvedEntry = optimization.resolveOptimizedEntry(
    baselineEntry,
    accepted ? optimizationData?.selectedOptimizations : undefined,
    )

    Fetch entries with one CDA locale in the app layer. For localized apps, configure your application locale and pass it directly before calling getEntry() or getEntries(). Do not pass all-locale CDA responses from withAllLocales or locale=*; the resolver expects direct single-locale field values. See Entry personalization and variant resolution for the entry contract and Locale handling in the Optimization SDK Suite for the broader locale model.

    Use getMergeTagValue() for Contentful Rich Text merge tags and getFlag() for Custom Flags. If a merge tag references localized profile fields such as location.city or location.country, its resolved value follows the localized profile data returned by the Experience API. The Web SDK is stateful, so reading a flag also emits flag-view tracking.

    Entry interaction tracking

    Enable automatic tracking when entry elements follow the standard data-attribute pattern:

    const optimization = new ContentfulOptimization({
    clientId: 'your-client-id',
    autoTrackEntryInteraction: { views: true, clicks: true, hovers: false },
    })

    Use manual element overrides when the DOM structure does not fit automatic observation:

    optimization.tracking.enableElement('views', element, {
    data: {
    componentId: 'entry-id',
    experienceId: 'experience-id',
    variantIndex: 0,
    },
    })

    For detection thresholds, data attributes, click and hover behavior, and manual overrides, use the Web SDK integration guide.

    The stateful Web SDK exposes observable state for UI feedback and integration glue:

    const unsubscribe = optimization.states.profile.subscribe((profile) => {
    console.log(profile?.id)
    })

    Common state streams include consent, persistenceConsent, profile, selectedOptimizations, changes, blockedEventStream, eventStream, and preview-panel state. Use the generated reference for the complete states surface.

    • Browser storage persistence is best-effort. If localStorage writes fail, the SDK continues with in-memory state and retries persistence on subsequent writes.
    • reset() clears internal state except consent and persistence consent. Use it when the active profile changes.
    • flush() drains queued Insights API and Experience API events.
    • destroy() releases listeners and singleton ownership for explicit teardown paths such as tests or hot-reload workflows.
    • Lifecycle interceptors exist for first-party SDK and preview-panel integration. Most application code does not need them directly.

    Classes

    default

    Interfaces

    CookieAttributes
    CurrentPageEmissionMetadata
    EntryClickInteractionElementOptions
    EntryHoverInteractionElementOptions
    EntryHoverInteractionStartOptions
    EntryInteractionApi
    EntryInteractionElementOptionsMap
    EntryInteractionStartOptionsMap
    EntryInteractionTracker
    EntryInteractionTrackers
    EntryViewInteractionElementOptions
    EntryViewInteractionStartOptions
    OptimizationWebConfig
    TrackCurrentPageOptions

    Type Aliases

    AutoTrackEntryInteractionOptions
    EntryElementInteraction
    EntryInteraction
    EntryInteractionElementOptions
    EntryInteractionStartOptions
    InitialCurrentPageEvent
    OptimizationTrackingApi
    OptimizationWebRuntime

    Variables

    CAN_ADD_LISTENERS
    ENTRY_SELECTOR
    HAS_MUTATION_OBSERVER
    OPTIMIZATION_WEB_SDK_NAME
    OPTIMIZATION_WEB_SDK_VERSION

    Functions

    beaconHandler
    getPageProperties
    getUserAgent