Svelte / SvelteKit SDK
warning
Preview release. The Svelte / SvelteKit SDK is currently in preview. It is fully functional and suitable for evaluation and development, but APIs may change before general availability.
The Uniform SDK for Svelte and SvelteKit provides a full integration between Uniform DXP and Svelte applications. It spans three complementary packages:
@uniformdev/canvas-svelte-- Svelte components for rendering Canvas compositions (UniformComposition,UniformSlot,UniformText,UniformRichText) and contextual editing support.@uniformdev/canvas-sveltekit-- SvelteKit-specific integrations: route loading (createUniformLoad), server hooks (createUniformHandle), preview handlers, and ISR configuration.@uniformdev/context-svelte-- Svelte bindings for Uniform Context, enabling personalization, A/B testing, visitor scoring, and behavior tracking via theUniformContextprovider and reactive helpers.
tip
Just want to try it out? Clone one of the working examples and explore:
- SvelteKit Starter -- Minimal starter with composition rendering, component mapping, and visual editing.
- SvelteKit Demo -- Full-featured demo with personalization, A/B testing, and edge middleware.
How it works#
Understanding the request lifecycle helps you reason about configuration choices and debug issues:
A visitor requests a page -- SvelteKit's catch-all route
[...path]/+page.server.tsreceives the request.The composition is fetched server-side --
createUniformLoadfrom@uniformdev/canvas-sveltekitusesRouteClientto resolve the URL against the Project Map and fetch the full composition data.Components render via the composition tree --
UniformCompositionwalks the tree and uses yourcomponentMap(or a customresolveRenderer) to map each Uniform component type to a Svelte component. Parameters are flattened and passed directly as props.Personalization and testing are evaluated -- The
UniformContextprovider evaluates personalization rules and A/B tests either client-side (standard) or outputs NESI placeholders for edge evaluation (edge).Visual editing works out of the box -- When previewing in the Uniform dashboard, the SDK automatically enables contextual editing, inline text editing, and live preview via the playground route.
Getting started#
Prerequisites#
- SvelteKit 2+ (Svelte 5)
- Node.js 18+
- A Uniform project with compositions set up
Install packages#
Install the Uniform CLI as a dev dependency for syncing content and downloading manifests:
| Package | Purpose |
|---|---|
@uniformdev/canvas | Core Canvas API client, types, and utilities |
@uniformdev/canvas-svelte | Svelte components: UniformComposition, UniformSlot, UniformText, UniformRichText |
@uniformdev/canvas-sveltekit | SvelteKit integrations: route loading, server hooks, preview handler, ISR |
@uniformdev/context | Core Context personalization engine |
@uniformdev/context-svelte | UniformContext provider and reactive helpers (getScores, getQuirks) |
@uniformdev/cli | CLI for pulling manifests and syncing content |
Environment variables#
Create a .env file in your project root:
note
You can find these values in your Uniform project under Settings > API Keys. See the API keys guide for more information.
Project setup#
The Uniform SDK requires a specific set of files to wire up routing, rendering, and preview. Here is the minimal file structure:
The following sections walk through each file.
Step 1: TypeScript declarations#
Update src/app.d.ts to include Uniform preview data types:
Step 2: Root layout with UniformContext#
Create src/routes/+layout.svelte to initialize the Uniform Context provider:
UniformContext props#
| Prop | Type | Default | Description |
|---|---|---|---|
context | Context | -- | Required. A configured Uniform Context instance |
outputType | 'standard' | 'edge' | 'standard' | How personalization variants are rendered |
trackRouteOnRender | boolean | true | Whether to track route changes on render |
includeTransferState | 'always' | 'never' | 'server-only' | 'server-only' | When to include transfer state for SSR hydration |
note
The outputType setting controls how personalization and A/B test variants are rendered:
standard-- Evaluates personalization server-side during SSR or client-side. Outputs only the winning variant. Use for development and standard SSR/SSG deployments.edge-- Outputs all variants as NESI (Nested Edge-Side Includes) placeholders. An edge middleware selects the winning variant before delivering the page. Use for production with edge personalization.
Step 3: Server hooks#
Create src/hooks.server.ts to handle Uniform preview mode detection:
The createUniformHandle hook:
- Parses preview cookies set by the Canvas editor
- Makes preview data available via
event.locals.uniformPreview - Optionally calls a callback when preview mode is active
Step 4: Catch-all route#
Create the route structure to serve Uniform compositions.
src/routes/[...path]/+page.server.ts -- Server-side data loading:
src/routes/[...path]/+page.svelte -- Composition rendering:
createUniformLoad options#
| Option | Type | Default | Description |
|---|---|---|---|
client | RouteClient | -- | Required. A configured RouteClient instance |
param | string | 'path' | The route parameter name (matches [...path]) |
projectMapId | string | undefined | Optional project map ID (uses default if not set) |
silent | boolean | false | Suppress console logging |
requestOptions | object | undefined | Customize API request options |
handleComposition | function | built-in | Custom handler for composition responses |
handleRedirect | function | built-in | Custom handler for redirect responses |
handleNotFound | function | built-in | Custom handler for 404 responses |
Step 5: Component mapping#
Create src/lib/uniform/componentMap.ts to map Uniform component types to Svelte components:
The componentMap is a simple object where keys are Uniform component type strings and values are Svelte components. For variant-specific mappings, use the type__variant format (double underscore).
note
Svelte uses componentMap instead of resolveRenderer. Unlike the React and Nuxt SDKs which use a resolveRenderer function, the Svelte SDK uses a declarative componentMap object. This is more idiomatic for Svelte and simpler to maintain.
You can also use a custom resolveRenderer function if you need dynamic resolution logic. Pass it as a prop to UniformComposition instead of componentMap.
Step 6: Preview handler#
Create src/routes/preview/+server.ts to enable Canvas contextual editing:
Step 7: Playground page#
Create src/routes/playground/+page.svelte for previewing individual components and patterns:
The playground page renders an empty composition shell that the Canvas editor populates during contextual editing sessions.
Building components#
Uniform components in Svelte receive flattened props -- parameter values are extracted from their ComponentParameter wrappers and spread directly onto the component via Svelte 5's $props(). For example, if a Uniform component has a title parameter of type text, your Svelte component receives a title prop with the string value directly.
Every component also receives a component prop containing the full ComponentInstance, which provides access to raw parameter data, component metadata, variant info, and slots.
Component props#
Every component rendered via the componentMap receives these props:
| Prop | Type | Description |
|---|---|---|
component | ComponentInstance | The full component instance with raw parameters, slots, variant, and metadata |
[parameterName] | flattened value | Each parameter's .value is spread as a top-level prop |
Basic component with parameters#
Use the ComponentProps<T> type to define your component's props:
Component with slots#
Use UniformSlot to render child components placed in named slots:
Component with variants#
Access variant information via the component prop to conditionally style components:
Register variants in the component map using the type__variant format:
UniformText#
UniformText renders text parameters with built-in support for inline editing in the Uniform visual editor:
UniformText props#
| Prop | Type | Default | Description |
|---|---|---|---|
parameterId | string | -- | Required. The ID of the parameter to render |
as | string | 'span' | The HTML element to render |
placeholder | string | ((props: { id: string }) => string) | undefined | Placeholder text shown in the Canvas editor when empty |
isMultiline | boolean | false | When true, adds white-space: pre-wrap for line break support |
Custom rendering with snippets#
UniformText supports a default snippet slot for custom value rendering:
UniformRichText#
UniformRichText renders rich text parameters with full formatting support:
UniformRichText props#
| Prop | Type | Default | Description |
|---|---|---|---|
parameterId | string | -- | Required. The ID of the rich text parameter |
as | string | undefined | Optional wrapper element |
placeholder | string | ((props: { id: string }) => string) | undefined | Placeholder text when empty |
resolveRichTextRenderer | RenderRichTextComponentResolver | undefined | Custom function to override default rich text node renderers |
Custom rich text node rendering#
Override how specific rich text node types are rendered:
UniformSlot#
UniformSlot renders child components placed in a named slot:
When name is omitted, UniformSlot renders all slots combined.
UniformSlot props#
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | undefined | The slot name to render. If omitted, all slots are rendered |
resolveRenderer | RenderComponentResolver | inherited | Override the component resolver for this slot's children |
wrapperComponent | Component | undefined | A Svelte component that wraps the slot's children |
Empty slot placeholder#
UniformSlot supports an emptyPlaceholder snippet for when the slot has no items:
UniformComposition#
UniformComposition is the entry point for rendering a composition tree:
UniformComposition props#
| Prop | Type | Required | Description |
|---|---|---|---|
data | RootComponentInstance | Yes | The composition data from the Uniform API |
componentMap | ComponentMap | Yes* | Object mapping component types to Svelte components |
resolveRenderer | RenderComponentResolver | No | Custom resolver function (alternative to componentMap) |
matchedRoute | string | No | The matched route path |
dynamicInputs | Record<string, string> | No | Dynamic input values from route parameters |
behaviorTracking | 'onLoad' | 'onView' | No | When to track enrichment behavior |
contextualEditingEnhancer | function | No | Custom enhancer for contextual editing updates |
note
Either componentMap or resolveRenderer must be provided. componentMap is the recommended approach for most projects.
Asset parameters#
Use flattenValues from @uniformdev/canvas to work with asset parameters:
warning
Always use flattenValues from @uniformdev/canvas for asset parameters. Do not create custom utility functions for extracting asset data.
Personalization and testing#
Personalization and A/B testing are configured in the Uniform dashboard and evaluated automatically by the SDK. When UniformSlot encounters a personalization or test container in the composition tree, it renders the appropriate Personalize or Test component from @uniformdev/context-svelte.
How personalization works#
- The personalization manifest is downloaded locally (see Manifest management) and passed to the Context in the root layout.
- The
UniformContextprovider creates aContextinstance and makes it available to the entire component tree. - When
UniformSlotencounters a personalization container, it evaluates the visitor's scores against the variant criteria and renders the winning variant(s). - Score updates happen through enrichment tracking (
Trackcomponent) and route-based signals.
Output types#
The outputType prop on UniformContext controls how variants are rendered:
standard(default) -- Evaluates personalization during SSR or on the client. Only the winning variant HTML is included. Best for development and most deployments.edge-- Outputs all variants as NESI placeholders. An edge middleware selects the winning variant before the response reaches the browser. Best for production with edge personalization (see Edge personalization).
Client-side context#
getUniformContext#
Access the Uniform Context instance directly. Must be called within a UniformContext provider:
The context object is the @uniformdev/context Context instance:
| Method / Property | Description |
|---|---|
context.scores | Current visitor score values (not reactive -- use getScores()) |
context.quirks | Current visitor quirk values (not reactive -- use getQuirks()) |
context.update(options) | Update visitor data (quirks, enrichments, URL) |
context.forget(purge) | Clear all visitor data. Pass true to also clear cookies |
context.personalize(options) | Manually evaluate personalization |
warning
The context.scores and context.quirks properties accessed directly are not reactive -- they do not trigger re-renders. Use getScores() and getQuirks() for reactive access.
getScores#
Provides reactive access to the current visitor's score values. Uses Svelte 5's $state rune internally:
Returns an object with a reactive .current property containing the ScoreVector.
getQuirks#
Provides reactive access to the current visitor's quirk values:
Returns an object with a reactive .current property containing the Quirks object.
Updating quirks#
Update visitor quirks to trigger personalization changes:
Contextual editing#
The SDK provides built-in support for Uniform's visual/contextual editing. When a composition is opened in the Uniform Canvas editor, the SDK automatically:
- Listens for composition update messages from the editor
- Re-renders the component tree with the updated data
- Enables inline editing for
UniformTextandUniformRichTextcomponents - Annotates components with editing attributes for the Canvas UI
getUniformContextualEditing#
For custom contextual editing setups, use getUniformContextualEditing directly:
| Return Value | Type | Description |
|---|---|---|
composition | reactive RootComponentInstance | The current composition (updates during editing) |
isContextualEditing | reactive boolean | Whether the app is in contextual editing mode |
Manifest management#
warning
SvelteKit requires downloading the manifest locally. The manifest must be imported as a JSON file and provided to the Context instance in the root layout.
Add these scripts to your package.json:
| Script | Description |
|---|---|
pull:manifest | Downloads the personalization manifest to a local JSON file |
pull:content | Pulls content definitions from your Uniform project |
push:content | Pushes local content changes to your Uniform project |
publish:manifest | Publishes the manifest (required after changing signals, enrichments, or quirks) |
Create a placeholder manifest file at src/lib/uniform/contextManifest.json:
Add contextManifest.json to src/lib/uniform/.gitignore since it is auto-generated.
Uniform CLI configuration#
Create uniform.config.ts at your project root:
Edge personalization#
For production deployments on Vercel, you can enable edge-side personalization using NESI (Nested Edge-Side Includes). This moves personalization evaluation from the client to the edge, delivering fully personalized HTML with zero client-side JavaScript overhead.
How edge personalization works#
Setup#
Edge personalization requires two additional packages:
1. Set output type to edge in production#
This is already configured if you followed the setup guide:
2. Create edge middleware#
Create middleware.ts in the project root (for Vercel deployments):
ISR (Incremental Static Regeneration)#
For Vercel deployments, enable ISR to cache and revalidate pages:
And configure the Vercel adapter in svelte.config.js:
Import reference#
@uniformdev/canvas-svelte#
| Export | Description |
|---|---|
UniformComposition | Renders a full Canvas composition tree |
UniformComponent | Internal component renderer (for advanced usage) |
UniformSlot | Renders child components from a named slot |
UniformText | Renders text parameters with inline editing support |
UniformRichText | Renders rich text parameters with formatting |
DefaultNotImplementedComponent | Fallback component for unknown types |
getUniformCurrentComposition | Get the current composition data from context |
getUniformCurrentComponent | Get the current component data from context |
getUniformContextualEditing | Set up custom contextual editing |
createUniformApiEnhancer | Create an API-based composition enhancer |
getClientConditionsComposition | Evaluate client-side visibility rules |
getClientVisibilityRules | Get client-side visibility rule definitions |
convertComponentToProps | Convert a ComponentInstance to flattened props |
getParameterAttributes | Get inline editing data attributes |
createComponentResolver | Create a resolver from a component map |
resolveComponent | Resolve a component from a map or resolver function |
ComponentMap | Type for the component mapping object |
ComponentProps | Type for component props (flattened) |
RenderComponentResolver | Type for the custom resolver function |
@uniformdev/canvas-sveltekit#
| Export | Description |
|---|---|
createUniformLoad | Create a SvelteKit load function for fetching compositions |
createUniformHandle | Create a SvelteKit handle hook for preview mode |
createPreviewHandler | Create preview API endpoint handlers (GET, POST, OPTIONS) |
createVercelIsrConfig | Create ISR configuration for Vercel deployments |
createRevalidateHandler | Create an ISR revalidation endpoint handler |
createRouteFetcher | Low-level route fetcher (used internally by createUniformLoad) |
createUniformEntries | Create entry data for static generation |
resolvePathFromParams | Helper to resolve path from SvelteKit route params |
logCompositionIssues | Log composition validation issues |
logRouteResponse | Log route resolution responses |
UniformPreviewData | Type for preview cookie data |
UniformPageData | Type for page data from the load function |
UNIFORM_PREVIEW_COOKIE_NAME | Cookie name constant for preview state |
@uniformdev/context-svelte#
| Export | Description |
|---|---|
UniformContext | Provider component for the Uniform Context engine |
Personalize | Renders personalized content based on visitor scores |
PersonalizeEdge | Edge-mode personalization renderer |
PersonalizeStandard | Standard-mode personalization renderer |
Test | Renders A/B test variations based on distribution |
TestEdge | Edge-mode test renderer |
TestStandard | Standard-mode test renderer |
Track | Tracks behavior when content enters the viewport |
TrackFragment | Tracks behavior on page load (no wrapper element) |
getUniformContext | Get the Context instance from the nearest provider |
getScores | Reactive access to visitor scores (Svelte 5 $state) |
getQuirks | Reactive access to visitor quirks (Svelte 5 $state) |
isPersonalized | Check if inside a Personalize component |
@uniformdev/canvas#
| Export | Description |
|---|---|
RouteClient | Client for resolving routes and fetching compositions |
flattenValues | Extract values from asset parameters |
EMPTY_COMPOSITION | Empty composition constant (for playground pages) |
RootComponentInstance | Type for composition root data |
ComponentInstance | Type for individual component data |
CANVAS_DRAFT_STATE | Constant for draft content state |
CANVAS_PUBLISHED_STATE | Constant for published content state |
@uniformdev/context#
| Export | Description |
|---|---|
Context | The core personalization and scoring engine |
CookieTransitionDataStore | Store for persisting visitor data in cookies |
enableContextDevTools | Plugin for enabling the Uniform DevTools browser extension |
enableDebugConsoleLogDrain | Plugin for debug logging to console |
ManifestV2 | Type for the personalization manifest |
UNIFORM_DEFAULT_COOKIE_NAME | Default cookie name for visitor data |
Type definitions#
ComponentProps#
ComponentMap#
Keys can be:
"hero"-- matches type"hero"with no variant"hero__featured"-- matches type"hero"with variant"featured"(double underscore)
RenderComponentResolver#
UniformContextComponentProps#
PersonalizeComponentProps#
TestComponentProps#
Recipes#
Recipe: Adding Uniform to an existing SvelteKit project#
- Install packages:
- Add environment variables to
.env:
- Update
src/app.d.ts:
- Download the personalization manifest:
- Create the component map (
src/lib/uniform/componentMap.ts):
Create the root layout (
src/routes/+layout.svelte) withUniformContext(see Step 2).Create the catch-all route (
src/routes/[...path]/+page.server.tsand+page.svelte) (see Step 4).Create the preview handler (
src/routes/preview/+server.ts) (see Step 6).Create the playground page (
src/routes/playground/+page.svelte) (see Step 7).Create server hooks (
src/hooks.server.ts) (see Step 3).Add scripts to
package.json:
Recipe: Building a component with text, rich text, and slots#
Recipe: Component with quirk-based personalization#
Recipe: Forget visitor data (reset personalization)#
Recipe: DevTools integration#
Enable the Uniform Context DevTools browser extension for debugging:
The DevTools extension lets you inspect and modify visitor scores and quirks in real time during development.
Svelte vs SvelteKit#
The Uniform Svelte SDK is split between framework-agnostic Svelte packages and SvelteKit-specific packages:
| Concern | Svelte package | SvelteKit package |
|---|---|---|
| Composition rendering | @uniformdev/canvas-svelte | -- |
Components (UniformText, UniformSlot, etc.) | @uniformdev/canvas-svelte | -- |
| Context provider | @uniformdev/context-svelte | -- |
Reactive helpers (getScores, getQuirks) | @uniformdev/context-svelte | -- |
Route loading (createUniformLoad) | -- | @uniformdev/canvas-sveltekit |
Server hooks (createUniformHandle) | -- | @uniformdev/canvas-sveltekit |
| Preview handler | -- | @uniformdev/canvas-sveltekit |
| ISR configuration | -- | @uniformdev/canvas-sveltekit |
| Edge personalization (NESI) | -- | @uniformdev/context-edge-sveltekit |
If you are using SvelteKit (recommended), install all packages. The Svelte-only packages (canvas-svelte, context-svelte) can also be used in non-SvelteKit Svelte setups, but you will need to handle routing and data fetching yourself.
Best practices#
Use TypeScript -- The SDK is TypeScript-first. Define
Propsinterfaces usingComponentProps<T>for all components with proper types for each parameter.Use
componentMapoverresolveRenderer-- The declarative component map is simpler, more readable, and easier to maintain than a resolver function. ReserveresolveRendererfor cases where you need dynamic resolution logic.Download manifest before build -- Use
npm run pull:manifest && vite buildto ensure the manifest is always up-to-date. Never commit a stale manifest.Run
publish:manifestafter changes -- Always rununiform context manifest publishafter modifying signals, enrichments, or quirks. The manifest must be re-downloaded after publishing.Use
flattenValuesfor assets -- Always useflattenValuesfrom@uniformdev/canvasfor asset parameters rather than manually traversing the parameter structure.Access
componentprop for metadata -- When you need raw parameter data, component IDs, variant info, or slot information, use thecomponentprop.Use
getScores()andgetQuirks()for reactive data -- Accessingcontext.scoresdirectly does not trigger re-renders. Always use the reactive helpers for values that affect the UI.Keep the preview handler in place -- The preview API endpoint and server hooks are required for visual editing in the Uniform Canvas editor. Do not remove them.
Prefer
standardoutput for development -- UseoutputType: 'standard'during development for easier debugging. Switch to'edge'only in production with a configured edge middleware.Use the
type__variantnaming convention -- For variant-specific component mappings, use double underscore (hero__dark) in the component map rather than creating separate resolver logic.
Troubleshooting#
Common issues#
"Cannot find module contextManifest.json"
- Run
npm run pull:manifestto download the manifest. - Ensure
UNIFORM_API_KEYandUNIFORM_PROJECT_IDare set correctly.
- Run
Preview not working
- Verify the preview URL is configured in Uniform Canvas settings.
- Check
UNIFORM_PREVIEW_SECRETmatches in both the.envfile and Uniform dashboard. - See the troubleshoot preview guide for more help.
Components not rendering
- Verify component type names in
componentMapmatch the types defined in Uniform Canvas. - Check browser console for mapping errors.
- Make sure the component is exported and imported correctly.
- Verify component type names in
TypeScript errors with
$props()- Ensure you are using Svelte 5. The SDK uses Svelte 5's
$props()rune for component props. - Use
interface Props extends ComponentProps<T> {}pattern for type-safe props.
- Ensure you are using Svelte 5. The SDK uses Svelte 5's
Edge personalization not working
- Ensure
outputTypeis set to'edge'in production. - Verify the edge middleware is deployed and running.
- Check that the NESI packages (
@uniformdev/context-edge,@uniformdev/context-edge-sveltekit) are installed.
- Ensure