Get started with the Experiences SDK
Experiences SDK is currently available in alpha. APIs are unstable and subject to change.
This guide walks you from an empty Next.js project to a rendered experience. You set up the SDK first, before you have an experience or any component IDs, and add them as you go. The experience renders on the server, so your page ships only the JavaScript your components need.
The guide uses Next.js with the App Router. The SDK also has adapters for SvelteKit and Angular. See Next steps.
Prerequisites
- Node.js 22.12 or later
- A Contentful space with Experience Orchestration enabled
- The Content Delivery API access token for the space: find it in Settings > API keys in the Contentful web app. To preview draft content in step 9, you also need the Content Preview API access token from the same page.
You don’t need an experience yet. Step 5 shows how to create one or seed a demo experience.
1. Create a Next.js app
This guide uses Next.js 15, the version the Next.js example uses.
2. Install the SDK
To install the SDK, run the following command:
@contentful/experiences-react is the only package you install. It includes the delivery client, the resolver, the renderers, and the types.
Add your space credentials to .env.local in the project root:
ENVIRONMENT_ID is the environment that holds your experiences, usually master.
3. Create the SDK configuration
The configuration maps the component IDs authored in Contentful to your React components. You don’t have any components registered yet, so start with an empty registry:
You add components to components in step 6.
4. Add an experience route
Create a route that fetches an experience by ID and renders it on the server:
fetchExperience fetches the experience from the Experience Delivery API and resolves it. ServerExperienceRenderer renders it in a React Server Component. The experience ID comes from the URL, so you don’t need one in your code. locale selects the content locale; use one of your space’s locales. ?debug=true turns on debug mode, which you use in the next step.
An unknown experience ID throws NotFoundError, which the route turns into a 404 page.
5. Render your first experience
You need a published experience in your space. Either:
- Create one in the Contentful web app and publish it.
- Seed the demo experience with the bootstrap script from the Experiences SDK repository. It creates a
landingexperience with its components, content, and design tokens.
Start the development server:
Open http://localhost:3000/<experience-id>?debug=true, using the experience’s ID from Contentful, or landing for the demo.
Your registry is still empty, so each component renders as a Missing component box that names its component ID, such as Section or hero-plain, and shows the key to register. Those IDs are the keys you register in the next step. Without debug mode, unregistered components render nothing.
The boxes only show the components at the top of the experience at first. Components nested in a slot of an unregistered component appear once you register their parent. Debug mode also logs the fetch and adds a panel after the experience with the resolved experience.
6. Register your components
Write a React component for each component ID. Content properties and design properties arrive as ordinary props, under the names authored in Contentful:
Register it under its component ID:
Reload the page. The heading renders, and its placeholder is gone. Register the rest of the components the same way. A component’s prop names are the content and design property names of its definition in Contentful. The debug panel shows each node’s content and design keys.
A component with a slot, such as a section that contains other components, receives the slot’s rendered children as a prop named after the slot. The default slot is usually named children:
The registry key is the last segment of the component’s URN in Contentful. For crn:contentful:::experience:spaces/$self/environments/$self/components/Heading, the key is Heading. Experience templates go in a separate experienceTemplates registry. See Register components.
7. Resolve design tokens
A design property can hold a design token, such as size.lg, instead of a value. Map token IDs to the values your components use with resolveToken:
Use the token IDs and values of your own design system. A token with no mapping reaches the component as a raw object, { type: 'DesignToken', value: '<token-id>' }, which renders as [object Object] in a style. Debug mode logs every token ID without a mapping, so you can find the ones to add. See Style components for CSS custom properties, Tailwind, and other token sources.
8. Use the SDK hooks
Most components only need their props. Two patterns cover the common exceptions.
Read design values in a nested child
A child that isn’t a registered component gets no props from the SDK. useDesignValues() reads the design values of the nearest registered component:
A component that calls an SDK hook, or uses state or effects, must be a client component. Add 'use client' at the top of its file. Components that only read props can stay server components.
Load data before rendering
resolveData derives props from external data, such as a price from your commerce API. It runs on the server inside fetchExperience, before the experience renders, and its return value is merged into the component’s props.
This example assumes the card has an sku content property. Add a price prop to CardProps and render it in Card, then register the card with defineComponent, keeping the components and resolveToken from the earlier steps:
defineComponent registers a component with resolveData or default props. The SDK runs every resolveData function in parallel. If one throws, that component renders without the resolved data, and the rest of the experience renders normally.
9. Preview draft content
To render unpublished changes, fetch from the Content Preview API. Add the Content Preview API access token to .env.local:
Pass the token and a preview flag to fetchExperience. This example turns on preview with ?preview=true. In app/[slug]/page.tsx, read preview from the search params alongside debug, then update the fetch:
To preview unsaved changes inside the Contentful canvas, see Set up live preview.
10. Render on the client when you need to
Server rendering is the default. Use ClientExperienceRenderer only when the experience itself must change in the browser, for example after refetching it with new parameters:
Fetch the experience in a server component, as in step 4, and pass it to ExperienceClient as a prop. The resolved experience is plain data, so it crosses to the client.
A client component that imports experienceConfig bundles everything the configuration imports, including server-only code in resolveData. If your resolveData functions use server-only modules, give the client renderer a configuration with the same components and no resolveData.
Interactive components don’t need the client renderer. A 'use client' component hydrates inside ServerExperienceRenderer. See Render experiences.
Next steps
- Register components for default props, slots, and experience templates.
- Fetch experiences for locales, parameters, and destinations.
- Errors and debugging for fallbacks and diagnostics.
- Next.js example: The complete app this guide is based on.
- SvelteKit example and Angular example: The same experience in the other adapters.