Nuxt SDK
The Uniform SDK for Nuxt (@uniformdev/uniform-nuxt) provides a first-class integration between Uniform's visual workspace and Nuxt. It handles route resolution, component rendering, personalization, A/B testing, and visual editing -- all through a dedicated Nuxt module and Vue composables.
How it works#
Understanding the request lifecycle helps you reason about configuration choices and debug issues effectively:
A visitor requests a page -- When a visitor navigates to a URL (e.g.,
/about), Nuxt's catch-all route receives the request and resolves the path against Uniform's Project Map.The composition is fetched -- The
useUniformCompositioncomposable fetches the full composition data from the Uniform API based on the resolved Project Map node path.Components render via the composition tree --
UniformCompositionwalks the composition tree and uses yourresolveRendererfunction to map each Uniform component type to a Vue component. Parameters are flattened and passed directly as props.Personalization and testing are evaluated -- The
UniformContextProvider(set up automatically by the Nuxt module) evaluates personalization rules and A/B tests client-side or server-side, depending on youroutputTypeconfiguration.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#
- Nuxt 4+ (Vue 3)
- Node.js 18+
- A Uniform project with compositions set up
Install packages#
You also need the Uniform CLI as a dev dependency for syncing content and downloading manifests:
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: Nuxt configuration#
Register the @uniformdev/uniform-nuxt module and configure it in nuxt.config.ts:
The Nuxt module automatically:
- Sets up the
UniformContextProvideraround your app - Registers
UniformComposition,UniformPlayground,UniformSlot,UniformText, andUniformRichTextas global components (no imports needed in templates) - Provides the
useUniformCompositioncomposable - Exposes the Uniform configuration via
useRuntimeConfig().public.$uniform
Uniform module options#
| Option | Type | Default | Description |
|---|---|---|---|
projectId | string | -- | Your Uniform project ID |
readOnlyApiKey | string | -- | API key with read access |
apiHost | string | undefined | Custom API host URL |
edgeApiHost | string | undefined | Custom edge API host URL |
manifest | ManifestV2 | -- | The personalization manifest object |
defaultConsent | boolean | false | Default storage consent for new visitors |
outputType | "standard" | "edge" | "standard" | How personalization variants are output |
playgroundPath | string | "/playground" | Path to the playground page handler |
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 standard SSR/SSG deployments.edge-- Outputs all variants in the HTML with metadata, suitable for edge-side personalization where an edge worker selects the winning variant.
Step 2: Catch-all route#
Create pages/[...path].vue. This catch-all route handles all Uniform-managed pages:
Key points:
useUniformCompositionis an async composable provided by the Nuxt module. It fetches the composition data for the given Project Map node path.- The returned
compositionis a reactive ref containing theRootComponentInstancedata. - If the composition cannot be found,
errorwill contain the error details.
useUniformComposition options#
| Option | Type | Description |
|---|---|---|
projectMapNodePath | string | The Project Map node path to resolve (e.g., /about) |
Step 3: Playground route#
Create pages/playground.vue. The playground route enables visual editing and previewing individual compositions from the Uniform dashboard:
The UniformPlayground component renders an empty composition shell that the Uniform Canvas editor populates during contextual editing sessions. It uses the same resolveRenderer function as your main composition route.
Step 4: Component resolution#
Create components/canvasComponents.ts. This function maps Uniform component types (defined in your Uniform project) to Vue components:
The resolveRenderer function receives a ComponentInstance and returns the Vue component to render. It is called for every component in the composition tree.
DefaultNotImplementedComponent is a built-in fallback that renders a helpful message when a component type has no registered implementation. Always include it as a fallback to gracefully handle unknown component types during development.
warning
The resolveRenderer function signature differs from the Next.js SDK. In Nuxt, it returns a Vue Component directly (not a { component } result object).
Step 5: CORS middleware for preview#
Create server/middleware/cors.ts. This server middleware is required for the Uniform Canvas visual editor to communicate with your Nuxt app during preview:
Step 6: Root app#
Your root app.vue is a standard Nuxt app file. The Uniform module handles context setup automatically, so no Uniform-specific components are needed here:
Building components#
Uniform components in Nuxt receive flattened props -- parameter values are extracted from their ComponentParameter wrappers and spread directly onto the component. For example, if a Uniform component has a title parameter of type text, your Vue 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, and slots.
Component props#
Every component rendered via resolveRenderer receives these props:
| Prop | Type | Description |
|---|---|---|
component | ComponentInstance | The full component instance with raw parameters, slots, and metadata |
[parameterName] | flattened value | Each parameter's .value is spread as a top-level prop |
Basic component with parameters#
Parameters defined in the Uniform dashboard are passed as flattened props. Define your component's props interface using the expected value types:
note
Props are flattened automatically. Unlike the Next.js SDK where you access parameters.title?.value, in Nuxt your component receives title directly as a prop with the raw value. The component prop gives you access to the full ComponentInstance when you need raw parameter metadata.
Accessing raw parameter values#
When you need the full parameter metadata (e.g., for conditional logic based on parameter type or contextual editing state), access the component prop:
UniformText#
UniformText renders text parameters with built-in support for inline editing in the Uniform visual editor. It is registered globally by the Nuxt module, so no import is needed in templates:
UniformText props#
| Prop | Type | Default | Description |
|---|---|---|---|
parameterId | string | -- | Required. The ID of the parameter to render |
as | string | "span" | The HTML element to render |
isMultiline | boolean | false | When true, adds white-space: pre-wrap to support line breaks |
placeholder | string | ((param: { id: string }) => string) | undefined | Placeholder text shown in the Canvas editor when the value is empty |
Custom rendering with the default slot#
UniformText supports a default scoped slot for custom value rendering:
UniformRichText#
UniformRichText renders rich text parameters with full formatting support. It is also globally registered:
UniformRichText props#
| Prop | Type | Default | Description |
|---|---|---|---|
parameterId | string | -- | Required. The ID of the rich text parameter |
as | keyof HTMLElementTagNameMap | undefined | Optional wrapper element. If not set, no wrapper is rendered |
placeholder | string | ((param: { id: string }) => string) | undefined | Placeholder text shown when the value is 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 using resolveRichTextRenderer:
Each custom renderer component receives a node prop with the RichTextNode data and a children slot/prop for nested nodes.
Slots#
Slots define where child components can be placed within a parent component. A page component typically has slots like content, header, and footer.
Rendering slots with UniformSlot#
UniformSlot is globally registered by the Nuxt module:
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 | ResolveRenderer | inherited | Override the component resolver for this slot's children |
Custom slot rendering with scoped slots#
UniformSlot supports a default scoped slot for wrapping individual slot items:
The scoped slot receives:
| Property | Type | Description |
|---|---|---|
child | VNode | The rendered child component |
component | ComponentInstance | The raw component instance data |
Empty slot placeholder#
UniformSlot supports an emptyPlaceholder slot shown when the slot has no items:
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.
Composition wrapper component#
For more complex page layouts where you need to wrap UniformComposition with navigation, metadata, or other elements, create a composition wrapper:
Then use it in your catch-all route:
Personalization and testing#
Personalization and A/B testing are configured in the Uniform dashboard and evaluated automatically by the SDK. The UniformSlot component handles personalization and test containers transparently -- when it encounters a personalization or test component in the composition tree, it renders the appropriate Personalize or Test component from @uniformdev/context-vue.
How personalization works in Nuxt#
- The personalization manifest is downloaded locally (see Manifest management) and passed to the Nuxt module configuration.
- The
UniformContextProvider(set up automatically by the Nuxt module) creates aContextinstance from the manifest. - 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 in your nuxt.config.ts controls how variants are rendered:
standard(default) -- Evaluates personalization during SSR or on the client. Only the winning variant HTML is included in the response. Best for most deployments.edge-- All variant HTML is rendered with metadata tags. An edge worker (CDN-level) selects and shows the winning variant. Best for fully cached/static sites with edge personalization.
Behavior tracking#
Components with enrichment tags automatically track visitor behavior. The behaviorTracking prop on UniformComposition controls when tracking occurs:
| Value | Description |
|---|---|
"onView" (default) | Tracks when the component enters the viewport (uses IntersectionObserver). Renders a wrapping <div> |
"onLoad" | Tracks immediately when the component mounts, regardless of viewport. No wrapping element |
Client-side context#
The Nuxt module automatically sets up the UniformContextProvider for your app. Several composables are available for client-side interactivity.
useUniformContext#
Access the Uniform Context instance directly. Available through the Nuxt app instance:
The context object is the @uniformdev/context Context instance, providing access to:
| Method / Property | Description |
|---|---|
context.scores | Current visitor score values |
context.quirks | Current visitor quirk values |
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 |
useQuirks#
Provides reactive access to the current visitor's quirk values. The component re-renders whenever quirks change:
useScores#
Provides reactive access to the current visitor's score values:
Updating quirks#
Update visitor quirks to trigger personalization changes:
Project Map integration#
The Uniform Project Map defines the site's URL structure and maps paths to compositions. You can query project map nodes to build navigation or resolve routes programmatically.
Fetching navigation from Project Map#
Create a composable to fetch project map nodes for navigation:
Use it in a navigation component:
Manifest management#
warning
Nuxt requires downloading the manifest locally. Unlike the Next.js App Router SDK which fetches the manifest at runtime, the Nuxt SDK expects the manifest to be imported as a JSON file and passed to the module configuration.
Add these scripts to your package.json:
| Script | Description |
|---|---|
download:manifest | Downloads the personalization manifest to a local JSON file |
uniform:push | Pushes local content definitions to your Uniform project |
uniform:pull | Pulls content definitions from your Uniform project |
uniform:publish | Publishes the personalization manifest (required after changing signals, enrichments, or quirks) |
note
The dev and build scripts use npm-run-all (run-s) to download the manifest before starting the dev server or building. Install it as a dev dependency: npm install -D npm-run-all.
The manifest file is imported in nuxt.config.ts:
Uniform CLI configuration#
Create uniform.config.ts at your project root to configure the Uniform CLI for content sync:
This configuration:
- Uses the
allpreset to sync all entity types - Serializes content definitions to the
./contentdirectory - Disables webhook syncing (optional)
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
useUniformContextualEditing#
This composable is integrated into UniformComposition automatically. For custom setups, you can use it directly:
| Return Value | Type | Description |
|---|---|---|
composition | ComputedRef<RootComponentInstance> | The current composition (updates during editing) |
isContextualEditing | ComputedRef<boolean> | Whether the app is currently in contextual editing mode |
Custom contextual editing enhancer#
If you need to enhance the composition data during contextual editing (e.g., to run data enhancers), pass a custom contextualEditingEnhancer to UniformComposition:
The enhancer function receives the update message and should return the enhanced composition:
Import reference#
@uniformdev/uniform-nuxt#
The Nuxt module. Register it in nuxt.config.ts under modules.
Automatically provides:
UniformComposition,UniformPlayground,UniformSlot,UniformText,UniformRichTextas global componentsuseUniformCompositioncomposableUniformContextProviderwrapping the app- Runtime config under
useRuntimeConfig().public.$uniform
@uniformdev/canvas-vue#
Component and utility exports for Canvas rendering:
| Export | Description |
|---|---|
UniformComposition | Main composition renderer component |
UniformPlayground | Playground composition renderer for visual editing |
UniformComponent | Internal component renderer (for advanced usage) |
UniformSlot | Renders child components from a named slot |
UniformText | Renders text parameters with inline editing |
UniformRichText | Renders rich text parameters with formatting |
DefaultNotImplementedComponent | Fallback component for unknown types |
useUniformContextualEditing | Composable for custom contextual editing setup |
useUniformCurrentComposition | Access the current composition data from any descendant |
useUniformCurrentComponent | Access the current component data from any descendant |
convertComponentToProps | Converts a ComponentInstance to flattened props |
getParameterAttributes | Gets editing attributes for a parameter |
ResolveRenderer | Type for the component resolver function |
ComponentProps | Type for component props (flattened) |
@uniformdev/context-vue#
Context and personalization component and composable exports:
| Export | Description |
|---|---|
UniformContextProvider | Provides Context to the component tree |
Personalize | Renders personalized content variations |
PersonalizeEdge | Edge-mode personalization renderer |
Test | Renders A/B test variations |
Track | Tracks enrichment behavior on viewport visibility |
TrackSlot | Tracks enrichment behavior on component load |
useUniformContext | Composable: access Context instance |
useQuirks | Composable: reactive quirk values |
useScores | Composable: reactive score values |
useIsPersonalized | Composable: whether inside a personalized variant |
provideUniformContext | Manually provide Context (for custom setups) |
onRouteChange | Trigger a route change event on the Context |
@uniformdev/canvas#
Core Canvas types and utilities:
| Export | Description |
|---|---|
flattenValues | Extracts values from asset parameters |
ComponentInstance | Type for a component in the composition tree |
RootComponentInstance | Type for the root composition component |
ComponentParameter | Type for raw parameter data |
AssetParamValue | Type for asset parameter values |
CANVAS_DRAFT_STATE | Constant for draft content state |
CANVAS_PUBLISHED_STATE | Constant for published content state |
@uniformdev/project-map#
| Export | Description |
|---|---|
ProjectMapClient | Client for querying project map nodes |
Type definitions#
ResolveRenderer#
ComponentProps#
UniformCompositionProps#
UniformContextProps#
UniformSlotProps#
UniformTextProps#
UniformRichTextProps#
Recipes#
Recipe: Adding Uniform to an existing Nuxt project#
- Install packages:
- Add environment variables to
.env:
- Download the personalization manifest:
- Configure
nuxt.config.ts:
- Create the component resolver (
components/canvasComponents.ts):
- Create the catch-all route (
pages/[...path].vue):
- Create the playground route (
pages/playground.vue):
- Create CORS middleware (
server/middleware/cors.ts):
- Add scripts to
package.json:
Recipe: Building a component with text, rich text, and slots#
Register it in your component resolver:
Recipe: Component with quirk-based personalization#
Recipe: Forget visitor data (reset personalization)#
Recipe: Accessing composition data for metadata#
Best practices#
Use TypeScript -- The SDK is TypeScript-first. Define
Propsinterfaces for all components with proper types for each parameter.Use
DefaultNotImplementedComponentas fallback -- Always returnDefaultNotImplementedComponentfrom yourresolveRendererfor unknown component types. It provides helpful development-time feedback about missing implementations.Download manifest before build -- Use
run-s download:manifest nuxt:buildto ensure the manifest is always up-to-date. Never commit a stale manifest.Run
uniform:publishafter 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 the
componentprop for metadata -- When you need raw parameter data, component IDs, or slot information, use thecomponentprop rather than trying to reconstruct the data from flattened props.Keep the CORS middleware in place -- The CORS server middleware is required for visual editing in the Uniform Canvas editor. Do not remove it even if your production site doesn't need CORS.
Use
useAsyncDatafor data fetching -- When fetching additional data in your components (like project map nodes for navigation), use Nuxt'suseAsyncDatato benefit from SSR data transfer and caching.Prefer
standardoutput type -- Unless you have a specific edge personalization setup, useoutputType: "standard"for simpler and more predictable personalization behavior.Keep
resolveRendererlightweight -- The resolver function is called for every component in the tree. Keep it as a simple lookup map rather than running complex logic.