Skip to navigation

Render experiences

Experiences SDK is currently available in alpha. APIs are unstable and subject to change.

Each framework adapter has two renderers for a fetched experience: a server renderer and a client renderer. Both take the experience from fetchExperience and your configuration, and render every node with your registered components.

Choose a renderer

Render on the server by default. Use the client renderer only when the experience itself must change in the browser, for example after refetching it with new parameters or during live preview.

FrameworkServer rendererClient renderer
ReactServerExperienceRendererClientExperienceRenderer (alias ExperienceRenderer)
SvelteServerExperienceRendererClientExperienceRenderer (alias ExperienceRenderer)
Angular<cf-server-experience><cf-experience>

In React, ServerExperienceRenderer works in React Server Components. Interactive components don’t need the client renderer. A component marked 'use client' hydrates inside ServerExperienceRenderer, and the rest of the page stays server-rendered.

// app/[slug]/page.tsx
import { fetchExperience, ServerExperienceRenderer } from '@contentful/experiences-react';
import { experienceConfig } from '../../../../lib/experience-config';
export default async function ExperiencePage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const experience = await fetchExperience(
{ spaceId: process.env.SPACE_ID!, environmentId: 'master', experienceId: slug },
{ accessToken: process.env.CDA_TOKEN! },
{ config: experienceConfig }
);
return <ServerExperienceRenderer experience={experience} config={experienceConfig} />;
}

Renderer props

Both renderers take the same props. Only experience and config are required. The others override values the experience already carries.

PropDescription
experienceThe experience from fetchExperience or resolveExperience. An experience with no nodes renders nothing.
configThe same configuration you passed to fetchExperience.
metadataMerged over the experience’s metadata.
debugOverrides the experience’s debug. false turns debug mode off for an experience fetched with it on.
renderUnknownThe fallback for an unregistered component. See Errors and debugging.
renderErrorThe fallback for a component that throws while rendering.

config is a prop, not part of the experience, because it holds component references and functions. The experience stays serializable so it can cross the server/client boundary: React Server Components, SvelteKit page data, and Angular’s TransferState.

Re-render with a new experience

To show different content without a page load, fetch the experience again and pass it to the client renderer. For example, a client component that refetches an experience with new parameters:

'use client';
import { useState } from 'react';
import { ClientExperienceRenderer, fetchExperience, type PortableRenderPlan } from '@contentful/experiences-react';
import { experienceConfig } from '../../../../lib/experience-config';
export function FeaturedPosts({ initialExperience }: { initialExperience: PortableRenderPlan }) {
const [experience, setExperience] = useState(initialExperience);
async function showMore() {
const nextExperience = await fetchExperience(
{
spaceId: '<space-id>',
environmentId: 'master',
experienceId: '<experience-id>',
parameters: { featuredPosts: { limit: 12, order: 'sys.createdAt' } },
},
{ accessToken: '<browser-safe-delivery-token>' },
{ config: experienceConfig }
);
setExperience(nextExperience);
}
return (
<>
<button onClick={showMore}>Show 12, oldest first</button>
<ClientExperienceRenderer experience={experience} config={experienceConfig} />
</>
);
}

A browser fetch exposes its token. Use a token that’s safe to expose, or a trusted proxy as host.

Read the render context

Every component and every resolveData function sees the render context:

FieldDescription
debugWhether debug mode is on. Use it to add your own debug output.
metadataThe application data passed to fetchExperience and the renderer’s metadata prop.

Read it with useExperience() in React, getExperience() in Svelte, or injectExperience() in Angular. In resolveData, it’s ctx.experience. The accessor throws outside a renderer.

metadata is the place for your application’s own data, such as the locale, the slug, or feature flags. The SDK never writes to it. It’s typed Record<string, unknown>, so narrow it where you read it:

interface PageMeta {
slug: string;
locale: string;
}
const { slug, locale } = useExperience().metadata as PageMeta;

metadata must be plain serializable data. Functions and class instances don’t survive the server/client boundary.

Render in other frameworks