Use this guide when a Contentful space uses Ninetailed-authored experience entries, legacy nt_*
fields, or @ninetailed/experience.js-utils-contentful mapper code and you need the authored
content ready for Optimization SDK rendering.
The legacy mapper turns Ninetailed Contentful entries into runtime experience configuration arrays. The Optimization SDK Suite reads Optimization-authored links from the entries you fetch and resolves the entry at render time. Runtime guides own rendering; this guide owns the authoring inventory and handoff.
Before changing runtime code, read the target guide for your app:
Gather these inputs from your existing app and Contentful space:
nt_name, nt_description, nt_type,
nt_config, nt_audience, nt_variants, nt_experience_id, or nt_experiences fields.ExperienceMapper, mapCustomExperience, async custom mappers, or code that builds
ExperienceConfiguration arrays.There is no SDK-provided content migration codemod or official field mapping for converting Ninetailed-authored entries to the Optimization content model. Treat the content migration as an operational authoring task in Contentful, then verify it through the target SDK.
nt_config.@ninetailed/experience.js-utils-contentful after no runtime path imports it.Find the entries and code paths that make personalization depend on the legacy model:
fields.nt_experiences.nt_config, nt_audience, nt_variants, and nt_experience_id.Do not preserve ExperienceConfiguration arrays as the target data model. In Optimization, a
baseline entry links to Optimization experience entries through SDK-owned fields, and matching
experiences link to replacement entries. If the links are absent or unresolved in the fetched
payload, the SDK returns the baseline entry.
Use Contentful personalization authoring to create the target experiences and variants. For the
minimum first proof, identify one legacy baseline entry, create or reuse one target baseline entry,
link one Optimization experience from the baseline entry's nt_experiences field, and link one
replacement entry from that experience's nt_variants field. Configure that experience with no
restrictive audience, or with an audience rule that matches every visitor in your test route.
Keep the runtime expectation simple:
en-US; do not use all-locale payloads.include: 10; for manual fetching, set an equivalent include depth in
your app's Contentful query.baselineEntry or to resolveOptimizedEntry(). With managed fetching, your app
gives the SDK its contentful.js client and the SDK fetches explicit entry IDs for the supported
target runtime.For the first verification, choose one baseline entry and one variant that targets all visitors. That proves the authoring links and runtime resolution before you migrate more rules.
Remove mapper output from the rendering path. Replace code that passes mapped experience arrays to experience.js components with the target runtime's entry-resolution surface:
OptimizedEntry, useOptimizedEntry, or resolveOptimizedEntry().If custom mapper code added application-specific fields, keep that adaptation outside the SDK handoff. Fetch or transform the app's own content first, then pass the baseline Contentful entry to the target resolver.
Before migrating the full runtime, verify the first authored entry can resolve in the target guide's quick path:
@ninetailed/experience.js-utils-contentful, ExperienceMapper, nt_config,
and runtime ExperienceConfiguration construction.| Symptom | Check |
|---|---|
| The target runtime always renders baseline | Confirm the fetched baseline entry contains linked Optimization experiences and variant entries, and that the test experience targets the visitor. |
| The runtime crashes or returns empty fields | Confirm the app did not fetch all locales and that linked entries are resolved in the payload. |
| Mapper removal breaks custom fields | Move custom application adaptation before or after SDK entry resolution; do not rebuild legacy experience arrays. |