This module is not part of the public Core SDK surface and is not intended for direct use by
applications or third-party SDKs. It exists solely to support the first-party Contentful preview
panel across platforms (web, React Native, iOS). It lives inside @contentful/optimization-core
because the override state machine is core to that cross-platform preview functionality and must
sit alongside the SDK's internal signals and interceptors. Treat everything documented here as
internal plumbing: APIs, types, and behaviors may change without notice and without a SemVer major
bump. If you are building an application on the Optimization SDKs, use the platform SDK's preview
panel component, not these primitives.
The @contentful/optimization-core/preview-support entry point ships the cross-platform
preview-panel toolkit: the override state machine, the preview view-model builder, the Contentful
content-model entry mappers, and the Contentful fetch helpers. It is consumed by
@contentful/optimization-react-native (re-exported as its own ./preview-support entry point) and
@contentful/optimization-ios-bridge, and is reserved for future first-party SDKs that surface a
Contentful-backed preview panel.
This entry only contains the shared toolkit. Platform-specific preview UI (the React Native
PreviewPanel component, the matching hooks, the iOS Swift glue, the future web preview panel)
remains in the respective SDKs.
import {
PreviewOverrideManager,
buildPreviewModel,
createAudienceDefinitions,
createExperienceDefinitions,
fetchAudienceAndExperienceEntries,
} from '@contentful/optimization-core/preview-support'
The toolkit pairs with the registerPreviewPanel bridge below: hosts call
registerPreviewPanel with a plain object, pull the SDK signals out via
PREVIEW_PANEL_SIGNALS_SYMBOL, and pass them into the toolkit.
registerPreviewPanelCoreStateful exposes registerPreviewPanel(previewPanel) to wire a preview consumer into the
SDK's internal signals. This is the only sanctioned way for the first-party preview tooling to read
and mutate optimization state without going through the network.
Arguments:
previewPanel: Required object that receives symbol-keyed signal bridge valuesReturns:
voidBridge symbols:
PREVIEW_PANEL_SIGNALS_SYMBOL: key used to expose internal signalsPREVIEW_PANEL_SIGNAL_FNS_SYMBOL: key used to expose internal signalFnsExample:
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]
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, and is not a general-purpose extension point.
PreviewOverrideManagerPlatform-agnostic override state machine. Registers a state interceptor on core so overrides survive API refreshes, and exposes mutation methods for the preview UI:
activateAudience(audienceId, experienceIds) — forces an audience active and sets its member
experiences to variant index 1.deactivateAudience(audienceId, experienceIds) — forces an audience inactive and resets member
experiences to variant index 0.setVariantOverride(experienceId, variantIndex) — per-experience variant override.resetAudienceOverride(audienceId) — clears one audience plus its associated experience
overrides.resetOptimizationOverride(experienceId) — clears a single experience override.resetAll() — clears everything and restores the baseline.getOverrides(), getBaselineSelectedOptimizations(), getBaselineAudienceQualifications() —
read-only accessors for the UI.destroy() — removes the interceptor and clears internal state.The constructor takes core's InterceptorManager<OptimizationData> directly (typically
optimization.interceptors.state).
applyOptimizationOverridesPure function that merges an override map into a SelectedOptimizationArray. Used internally by
PreviewOverrideManager whenever it needs to rewrite the signal from baseline. Exported for hosts
that want the same merge semantics outside the manager.
buildPreviewModelPure function that takes audience definitions, experience definitions, a snapshot of SDK signals
(PreviewSdkSignals), and the current OverrideState, and returns the PreviewModel DTO the UI
renders. It groups experiences under their audiences (adding an implicit "All Visitors" bucket for
unattached experiences), enriches each experience with its current variant index, isOverridden,
and the pre-override naturalVariantIndex when a baseline snapshot is supplied, and sorts the
result deterministically (All Visitors first, then qualified audiences, then alphabetical by name).
Translate Contentful entries into the shapes the panel understands:
createAudienceDefinitions(entries) — nt_audience entries → AudienceDefinition[].createExperienceDefinitions(entries) — nt_experience entries → ExperienceDefinition[],
including variant distribution percentages and variant display names sourced from linked entries.createExperienceNameMap(entries) — convenience lookup map from experience/personalization ID to
the human-readable nt_name.These mappers encode the Optimization platform's Contentful content-model schema. The rest of core remains free of Contentful schema knowledge.
contentfulFetch.ts wraps a minimal ContentfulClient interface (just getEntries) with
pagination handling:
fetchAllEntriesByContentType(client, contentType, include?) — fetches all entries of a single
content type, batching in pages of 100.fetchAudienceAndExperienceEntries(client) — parallel fetch of nt_audience and nt_experience
entries in one call.The package does not depend on the contentful SDK directly, so consumers can pass any compatible
client.
AudienceDefinition, ExperienceDefinition, VariantDistribution — platform-neutral shapes
produced by the entry mappers.ExperienceWithState, AudienceWithExperiences, PreviewData, PreviewModel — enriched shapes
produced by buildPreviewModel.AudienceOverride, OptimizationOverride, OverrideState, AudienceOverrideState — override
state shapes owned by PreviewOverrideManager.PreviewSdkSignals — the subset of SDK signals buildPreviewModel reads. A plain snapshot type,
not a live signal, so hosts decide how to sample and when to re-render.ContentfulClient, ContentfulEntry, ContentfulEntryCollection — the minimal Contentful
surface the fetch helpers and entry mappers operate on.ALL_VISITORS_AUDIENCE_ID, ALL_VISITORS_AUDIENCE_NAME, ALL_VISITORS_AUDIENCE_DESCRIPTION —
identifiers for the synthetic "All Visitors" bucket buildPreviewModel adds for experiences with
no audience target.