Contentful Personalization & Analytics
    Preparing search index...

    Contentful Logo

    Contentful Personalization & Analytics

    React Web SDK Reference Implementation

    Readme · Guides · Reference · Contributing

    Warning

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

    Reference implementation demonstrating @contentful/optimization-react-web usage in a React SPA. This is the primary React Web reference implementation for customer-style usage of the official React framework package.

    Note

    This implementation is the React Web SDK counterpart to web-sdk_react. Where web-sdk_react builds its own React adapter layer over @contentful/optimization-web, this implementation uses the official @contentful/optimization-react-web framework package directly to match customer integration code. There is no src/optimization/ adapter directory.

    Feature SDK surface used
    Provider + initialization OptimizationRoot
    SPA page tracking ReactRouterAutoPageTracker from @contentful/optimization-react-web/router/react-router
    Entry resolution + rendering OptimizedEntry render prop
    Live updates (global) OptimizationRoot liveUpdates prop
    Live updates (per-component) OptimizedEntry liveUpdates prop
    Live updates (locked) <OptimizedEntry liveUpdates={false}>
    Merge tag rendering useMergeTagResolver().getMergeTagValue()
    Nested personalization Nested <OptimizedEntry> composition
    Consent gating sdk.consent() via useOptimizationContext()
    Identify / reset sdk.identify() / sdk.reset() via useOptimizationContext()
    Auto view/click/hover Default OptimizationRoot observers + OptimizedEntry tracking props
    Manual view tracking <OptimizedEntry trackViews={false}> + sdk.tracking.enableElement()
    Flag view tracking sdk.states.flag('boolean').subscribe()
    Analytics event stream sdk.states.eventStream.subscribe()
    Preview panel attachment Env-gated attachOptimizationPreviewPanel() call
    Offline queue / recovery Inherited from @contentful/optimization-web runtime

    This app defines one APP_LOCALE, passes it through the provider locale prop, and passes it directly to Contentful CDA entry fetches. Do not use contentful.js withAllLocales or raw CDA locale=* for entries passed to OptimizedEntry; SDK entry resolution expects direct single-locale fields such as fields.nt_experiences and fields.nt_variants. See Locale handling in the Optimization SDK Suite for the broader locale model and Entry personalization and variant resolution for the entry contract.

    • Node.js >= 20.19.0 (24.15.0 recommended to match .nvmrc)
    • pnpm

    From the repository root:

    pnpm install
    pnpm build:pkgs
    pnpm implementation:run -- react-web-sdk implementation:install
    test -f implementations/react-web-sdk/.env || cp implementations/react-web-sdk/.env.example implementations/react-web-sdk/.env

    From the repository root:

    1. Start the mock API server:
    pnpm serve:mocks
    
    1. In another terminal, start the development server:
    pnpm implementation:run -- react-web-sdk dev
    
    1. Build for production:
    pnpm implementation:run -- react-web-sdk build
    
    1. Run type checking:
    pnpm implementation:run -- react-web-sdk typecheck
    

    The equivalent implementation-directory commands are:

    pnpm dev
    pnpm build
    pnpm typecheck
    1. Install the shared Playwright browsers/system dependencies, then run this implementation's E2E wrapper from the repository root:
    pnpm --dir lib/e2e-web setup:e2e
    pnpm test:e2e:react-web-sdk
    1. Or run the shared Playwright flow step by step:
    pnpm implementation:run -- react-web-sdk serve
    

    In another terminal:

    IMPLEMENTATION=react-web-sdk pnpm --dir lib/e2e-web test
    

    When finished:

    pnpm implementation:run -- react-web-sdk serve:stop
    

    This implementation uses the shared Playwright suite from lib/e2e-web. The implementation sets IMPLEMENTATION=react-web-sdk when invoking that suite.

    Use Playwright UI or codegen when needed:

    pnpm implementation:run -- react-web-sdk test:e2e:ui
    pnpm implementation:run -- react-web-sdk test:e2e:codegen

    The setup step creates the local .env file if needed:

    test -f implementations/react-web-sdk/.env || cp implementations/react-web-sdk/.env.example implementations/react-web-sdk/.env
    

    All variables have mock-safe defaults. To use local mock endpoints (the default), no changes are needed. PUBLIC_OPTIMIZATION_ENABLE_PREVIEW_PANEL="true" attaches the browser preview panel for local and staging development runs. See .env.example for the full list.

    react-web-sdk/
    ├── src/
    │ ├── main.tsx # OptimizationRoot, preview panel attachment, createBrowserRouter
    │ ├── App.tsx # Shared layout: SDK state, entry loading, nav, AnalyticsEventDisplay
    │ ├── components/
    │ │ ├── AnalyticsEventDisplay.tsx # Live event stream panel (persists across routes)
    │ │ ├── ControlPanel.tsx # Consent, identify, reset, and conversion controls
    │ │ └── RichTextRenderer.tsx # Rich text + merge tag rendering
    │ ├── config/
    │ │ └── locale.ts # Application Contentful locale
    │ ├── contentful-generated.d.ts # Generated Contentful entry skeleton types
    │ ├── pages/
    │ │ ├── HomePage.tsx # Utility panel, live updates, entry sections
    │ │ └── PageTwoPage.tsx # Navigation + conversion tracking demo
    │ ├── sections/
    │ │ ├── ContentEntry.tsx # Auto/manual tracked entry renderer
    │ │ ├── LiveUpdatesExampleEntry.tsx # Live updates parity: default / locked / always-live
    │ │ ├── NestedContentEntry.tsx # Nested personalization wrapper
    │ │ └── NestedContentItem.tsx # Recursive nested entry via OptimizedEntry
    │ ├── services/
    │ │ └── contentfulClient.ts # Contentful CDA client
    │ ├── types/
    │ │ ├── contentful.ts # Entry type definitions
    │ │ └── env.d.ts # import.meta.env typings
    ├── index.html
    ├── .env.example
    ├── package.json
    ├── rsbuild.config.ts
    ├── tsconfig.json
    ├── AGENTS.md
    └── README.md

    This implementation uses the official React Web SDK package directly. Keep API-level usage details in the @contentful/optimization-react-web package README.

    Implementation-specific touchpoints:

    • src/main.tsx mounts OptimizationRoot, ReactRouterAutoPageTracker, route configuration, and preview-panel attachment.
    • src/sections/ContentEntry.tsx demonstrates automatic tracking props and manual view tracking.
    • src/sections/LiveUpdatesExampleEntry.tsx compares default, locked, and always-live entry resolution.
    • src/components/ControlPanel.tsx demonstrates consent, identify, reset, and conversion actions.
    File or area Purpose
    src/main.tsx Configures OptimizationRoot and ReactRouterAutoPageTracker
    src/App.tsx Subscribes to provider state and renders route-level controls
    src/sections/ContentEntry.tsx Demonstrates OptimizedEntry tracking props and manual views
    src/sections/LiveUpdatesExampleEntry.tsx Demonstrates locked and live entry resolution
    src/components/RichTextRenderer.tsx Demonstrates merge tag rendering with useMergeTagResolver()
    src/components/AnalyticsEventDisplay.tsx Displays event stream output from sdk.states.eventStream
    Manual selectedOptimizations lock logic <OptimizedEntry liveUpdates={false}>

    What stays the same: contentfulClient.ts, locale config, type definitions, RichTextRenderer, E2E test files, page/section component structure.

    Key architectural difference: App.tsx acts as a persistent layout (contains AnalyticsEventDisplay that stays mounted across route changes). Pages are route children that receive state via useOutletContext.