> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://contentful.com/developers/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://contentful.com/developers/docs/_mcp/server.

# Experience Canvas Toolbar SDK Reference

> The sdk.experiences reference for the Experience Canvas Toolbar location | Experience context | Experience API | Experience Node API | Selection API | Data Assembly

This page is the method-and-property reference for `sdk.experiences`, available in [`locations.LOCATION_EXPERIENCE_TOOLBAR`](/extensibility/app-framework/locations#locations). For the concepts behind this location, see the [Experience Canvas Toolbar overview](/extensibility/app-framework/experience-canvas-toolbar-overview). For a walkthrough of building an app for this location, see [Get started with the Experience Canvas Toolbar](/extensibility/app-framework/experience-canvas-toolbar-getting-started).

## Experiences

`sdk.experiences`

Only available in [`locations.LOCATION_EXPERIENCE_TOOLBAR`](/extensibility/app-framework/locations#locations).

Exposes context and data about the experience or fragment currently open in the experience canvas or fragment canvas, and provides methods for reading and updating its content.

*Since 4.63.0*

### Getting the experience context

`sdk.experiences.context: ExperienceContext`

Returns the current editing context:

```javascript
{
  type: 'experience' | 'fragment' | 'experienceFragment',
  entityId: string
}
```

The toolbar location serves both editing contexts — check `context.type` to determine whether the app is running in the context of an experience or a fragment.

> **Info**
>
> **Note:** `'experienceFragment'` is reserved for an upcoming rename of the Fragment entity. The host does not emit it yet — code defensively against it, but expect only `'experience'` or `'fragment'` today.

### Receiving notifications when the experience context changes

`sdk.experiences.onContextChanged(callback): function`

Calls the callback every time the experience context changes. The method returns a function you can call to stop listening to changes.

```javascript
const detachHandler = sdk.experiences.onContextChanged((context) => {
  console.log(context.type, context.entityId);
});
```

*Since 4.63.0*

### The Experience API

`sdk.experiences.experience`

Gives access to the experience or fragment entity being edited.

#### Getting the experience snapshot

`experience.get(): ExperienceSnapshot`

Returns the current experience snapshot. Its shape depends on whether the entity is an experience or a fragment:

```javascript
// Experience
{
  sys: { id, type: 'Experience', version, template? },
  metadata?: { tags?, concepts?, name? }
}

// Fragment
{
  sys: { id, type: 'Fragment', version, componentType },
  metadata?: { tags?, concepts?, name? }
}
```

> **Info**
>
> **Note:** The type also accepts a third, reserved shape — `sys: { id, type: 'ExperienceFragment', version, component }` — for an upcoming rename of the Fragment entity. The host does not emit it yet.

#### Receiving notifications when the experience changes

`experience.onChange(callback): function`

Calls the callback with the updated `ExperienceSnapshot` every time the experience changes. The method returns a function you can call to stop listening to changes.

#### Getting experience metadata

`experience.getMetadata(): ExperienceMetadata | undefined`

Returns the experience's metadata (`tags`, `concepts`, `name`), or `undefined` if no metadata has been set.

#### Setting experience metadata

`experience.setMetadata(patch): Promise<void>`

Merges `patch` into the experience's existing metadata and persists the change.

#### Receiving notifications when experience metadata changes

`experience.onMetadataChanged(callback): function`

Calls the callback with the updated `ExperienceMetadata` (or `undefined`) every time the experience's metadata changes. The method returns a function you can call to stop listening to changes.

*Since 4.63.0*

#### Saving the experience

`experience.save(): Promise<void>`

Saves the current experience or fragment.

#### Publishing the experience

`experience.publish(): Promise<void>`

Publishes the current experience or fragment.

#### Getting an experience node

`experience.getNode(nodeId): ExperienceNodeAPI | null`

Returns the node with the given ID, or `null` if no node with that ID exists.

#### Getting the root nodes

`experience.getRootNodes(): Promise<ExperienceNodeAPI[]>`

Resolves with the top-level nodes of the experience or fragment tree. Use this as the entry point for enumerating an experience whose node IDs you don't already know.

There is no dedicated `getChildren()` method — descend the tree from a root node by reading a `Slot` node's [slot descriptor](#the-experience-node-api) (`node.getSlotDescriptor()`), whose `currentItems` list the child `nodeId`s, then resolve each with `getNode(nodeId)`.

*Since 4.64.0*

**Selection**

`experience.selection: ExperienceSelectionAPI`

See [Selection API](#selection-api) below.

**Data Assembly**

`experience.dataAssembly: DataAssemblyAPI`

See [Data Assembly](#data-assembly) below.

*Since 4.63.0*

### The Experience Node API

`ExperienceNodeAPI` — returned by `experience.getNode(nodeId)`.

* `node.id: string` — the node's ID.
* `node.nodeType: 'Component' | 'Fragment' | 'ExperienceFragment' | 'InlineFragment' | 'InlineExperienceFragment' | 'Slot'` — the type of the node. The `ExperienceFragment`/`InlineExperienceFragment` values are reserved for an upcoming rename of the Fragment entity; the host does not emit them yet.
* `node.get(): ExperienceNodeSnapshot` — returns the current node snapshot.
* `node.onChange(callback): function` — calls `callback` with the updated node snapshot every time the node changes; returns a function you can call to stop listening to changes.
* `node.dataAssembly: DataAssemblyParameterAPI` — node-scoped Data Assembly parameter access. See [Data Assembly](#data-assembly).
* `node.getDesignProperty(key): Promise<DesignValue>` — resolves with the value of the design property `key`.
* `node.setDesignProperty(key, value): Promise<void>` — sets the design property `key` to `value`.
* `node.onDesignPropertyChanged(key, callback): function` — calls `callback` with the updated value every time the design property `key` changes; returns a function you can call to stop listening to changes.
* `node.getProperties(): Promise<ComponentPropertyDescriptor[]>` — resolves with the node's property descriptors. These are read-only.
* `node.getSlotDescriptor(): Promise<SlotDescriptor | null>` — resolves with the node's slot descriptor, or `null` if the node is not a slot.

> **Info**
>
> **Note:** Node content is written through the node-scoped [Data Assembly](#data-assembly) parameter API, not through a content-property setter — there is no `setContentProperty` method. Only design properties (`setDesignProperty`) have setters.

*Since 4.63.0*

### Selection API

`experience.selection`

Exposes the current canvas selection.

* `selection.get(): { nodeId: string | null; nodeType?: ExperienceNodeType }` — returns the currently selected node, if any.
* `selection.onChange(callback): function` — calls `callback` with the updated selection every time it changes; returns a function you can call to stop listening to changes.
* `selection.set(nodeId): void` — sets the selected node. Synchronous.
* `selection.highlight(nodeId, options?): void` — highlights a node on the canvas. Synchronous. `options` may include `flash` (boolean) and `scrollIntoView` (boolean).

*Since 4.63.0*

### Data Assembly

Data Assembly parameters are exposed at two scopes:

* `experience.dataAssembly: DataAssemblyAPI` — experience-scoped; includes the full set of methods below plus `get()`, `getAvailable()`, and `onChange()`.
* `node.dataAssembly: DataAssemblyParameterAPI` — node-scoped; the four parameter methods only.

Both scopes share:

* `dataAssembly.getParameterDefinitions(): Promise<Record<string, DataAssemblyParameterDefinition>>` — resolves with all parameter definitions.
* `dataAssembly.getParameterDefinition(parameterId): Promise<DataAssemblyParameterDefinition | null>` — resolves with a single parameter definition, or `null` if it doesn't exist.
* `dataAssembly.setParameterValue(parameterId, value): Promise<void>` — sets a single parameter's value.
* `dataAssembly.setParameterValues(updates): Promise<void>` — sets multiple parameter values at once.

The experience-scoped `DataAssemblyAPI` additionally provides:

* `dataAssembly.get(): DataAssemblySnapshot` — returns the current Data Assembly snapshot.
* `dataAssembly.getAvailable(): Promise<DataAssemblySummary[]>` — resolves with the list of Data Assemblies available to the experience.
* `dataAssembly.onChange(callback): function` — calls `callback` with the updated snapshot every time it changes; returns a function you can call to stop listening to changes.

> **Info**
>
> **Note:** Data Assembly is definition-only in this release — there is no support for resolvers or nested Data Assemblies.

*Since 4.63.0*

## Window

`sdk.window`

The shared [window API](/extensibility/app-framework/sdk#window) — `startAutoResizer()`, `stopAutoResizer()`, `updateHeight()` — for reporting the toolbar app's content height to the host. Also available in this location since app-sdk 4.67.0.