Skill 09 · Contentful Personalization
Subchapter 9.23
references/rendering-pipeline.mdMarkdown3 KBView on GitHub
This is the part that turns Contentful entries plus personalization data into rendered UI.
Use separate delivery and preview clients when preview mode exists.
const contentfulClient = createClient({
space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID ?? '',
accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_TOKEN ?? '',
environment: process.env.NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT ?? 'master',
}).withoutUnresolvableLinks;
const previewClient = createClient({
space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID ?? '',
accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_PREVIEW_TOKEN ?? '',
host: 'preview.contentful.com',
}).withoutUnresolvableLinks;
const getClient = (preview: boolean) => (preview ? previewClient : contentfulClient);Why this helps:
210If experiences or variants fail to resolve, include depth is one of the first things to inspect.
The baseline entry should contain fields.nt_experiences.
Those linked entries are mapped into the format expected by the SDK.
Use a component map plus renderer plus experience wrapper.
const ContentTypeMap = {
hero: Hero,
cta: CTA,
feature: Feature,
};
const ComponentRenderer = (props) => {
const contentTypeId = props?.sys?.contentType?.sys?.id;
const Component = ContentTypeMap[contentTypeId];
if (!Component) return null;
return <Component {...props} />;
};
const BlockRenderer = ({ block }) => {
const experiences = (block.fields.nt_experiences || [])
.filter(ExperienceMapper.isExperienceEntry)
.map(ExperienceMapper.mapExperience);
return (
<Experience {...block} id={block.sys.id} component={ComponentRenderer} experiences={experiences} trackClicks />
);
};nt_experiences before rendering.Use merge tags for inline personalization.
nt_mergetag embedded in rich textMergeTag component usage in JSXIf preview tooling is enabled, fetch:
Preview setup is incomplete if the provider has no preview data to work with.
If the customer chooses @contentful/optimization, the personalized rendering primitive changes from <Experience> to <OptimizedEntry>.
The architectural idea is the same: