# Canvas Client SDK

> How to use the Uniform Canvas Client to fetch, search, filter, and manage compositions and component definitions.

Source: https://docs.uniform.app/docs/sdk/canvas-client

> **Deprecated:**
>
> `CanvasClient` and `UncachedCanvasClient` are deprecated. They are replaced by
> `CompositionDeliveryClient`, `CompositionManagementClient`, and `ComponentDefinitionClient`.
> See [content API clients](https://docs.uniform.app/docs/sdk/content-api-clients) for the current clients and a
> migration guide.

The Canvas Client (`CanvasClient` from `@uniformdev/canvas`) provides programmatic access to compositions and component definitions in a Uniform project. Use it for server-side data fetching, static site generation, build scripts, content migrations, or any scenario where you need to work with compositions outside of the standard rendering pipeline.

The client wraps the composition endpoints of the Uniform APIs; see the _For the US region:_

_For the EU region:_

 for the underlying API reference.

---

## Installation

The Canvas Client is part of the `@uniformdev/canvas` package:

```bash
npm install @uniformdev/canvas
```

---

## Initializing the client

### Standalone usage

```ts
import { CanvasClient } from "@uniformdev/canvas";

const canvasClient = new CanvasClient({
  apiKey: process.env.UNIFORM_API_KEY,
  projectId: process.env.UNIFORM_PROJECT_ID,
});
```

| Option | Type | Description |
| --- | --- | --- |
| `apiKey` | `string` | API key with read access to the project (write access for management operations) |
| `projectId` | `string` | The Uniform project ID |
| `apiHost` | `string` | Uniform API host, used when data resolution is skipped and for management operations. Default: `https://uniform.app` |
| `edgeApiHost` | `string` | Edge API host, used when fetching compositions with data resolution. Default: `https://uniform.global` |
| `disableSWR` | `boolean` | When `true`, disables stale-while-revalidate caching on the edge and always returns fresh data |
| `bypassCache` | `boolean` | When `true`, bypasses API caching entirely. `UncachedCanvasClient` is a shortcut for this |

### Within the App Router SDK

There is only one Canvas Client implementation. The App Router SDK provides `getCanvasClient`, a factory that returns the same `CanvasClient` pre-configured for Next.js: credentials are read from environment variables, and a custom `fetch` wires composition requests into the Next.js data cache (per-composition cache tags, `revalidate`, and draft-mode cache bypass):

```ts
import { getCanvasClient } from "@uniformdev/next-app-router";

const canvasClient = getCanvasClient({
  cache: { type: "no-cache" },
});
```

Use `getCanvasClient` in App Router server code so composition fetches participate in Next.js caching and revalidation; use `new CanvasClient(...)` everywhere else.

---

## Fetching a single composition

The client provides one method per lookup key. All of them accept the same options and return the same response shape:

| Method | Looks up by |
| --- | --- |
| `getCompositionById` | Composition ID |
| `getCompositionBySlug` | Composition slug |
| `getCompositionByNodePath` | Project map node path (accepts optional `projectMapId`) |
| `getCompositionByNodeId` | Project map node ID (accepts optional `projectMapId`) |

```ts
import { CANVAS_PUBLISHED_STATE } from "@uniformdev/canvas";

const { composition } = await canvasClient.getCompositionBySlug({
  slug: "/company/about-us",
  state: CANVAS_PUBLISHED_STATE,
});

console.log(composition._name, composition.parameters);
```

### Common options

| Option | Type | Description |
| --- | --- | --- |
| `state` | `number` | Publishing state to fetch: `CANVAS_DRAFT_STATE` (0) for draft, `CANVAS_PUBLISHED_STATE` (64) for published. |
| `locale` | `string` | Locale(s) to localize the response to. Accepts a single value (`en-US`), a comma-delimited list (`fr-CA,fr`), or `Accept-Language` header syntax. When omitted, all locales' data is returned. |
| `releaseId` | `string` | Fetch the composition as it would appear in the given release. |
| `withComponentIDs` | `boolean` | When `true`, includes the `_id` of each non-root component in the response. |
| `skipPatternResolution` | `boolean` | When `true`, pattern references are left unresolved. Useful when serializing compositions and patterns separately. |
| `versionId` | `string` | Fetch a historical version (retrieved from `getCompositionHistory`). Only valid with `getCompositionById`. |
| `skipDataResolution` | `boolean` | Skip edge-side data resolution (see below). |
| `resolutionDepth` | `number` | How many levels deep content references are resolved. |
| `dataSourceVariant` | `"unpublished"` | When set, data resources that support it fetch unpublished data from their data source. |

### Data resolution

By default, single-composition fetches go through the Uniform Edge API, which resolves data resources, dynamic tokens, and referenced entries before returning the composition. Pass `skipDataResolution: true` to fetch the raw, unresolved composition from the origin API instead -- appropriate for serialization, migration scripts, or when you resolve data yourself:

```ts
const { composition } = await canvasClient.getCompositionById({
  compositionId: "abc123",
  state: CANVAS_PUBLISHED_STATE,
  skipDataResolution: true,
});
```

---

## Listing compositions

`getCompositionList` fetches multiple compositions, optionally filtered by root component type:

```ts
const { compositions } = await canvasClient.getCompositionList({
  type: "landingPage",
  state: CANVAS_PUBLISHED_STATE,
});

for (const { composition } of compositions) {
  console.log(composition._name, composition._slug);
}
```

In addition to the [common options](#common-options), list queries accept:

| Option | Type | Description |
| --- | --- | --- |
| `type` | `string \| string[]` | Filter by root component type (public ID). Components in slots are not matched. |
| `keyword` | `string` | Matches compositions whose name, slug, or definition name contains the keyword. Not a full-text search. |
| `search` | `string` | Full-text search on textual fields, including resolved pattern content. Use for "where does this content appear" queries. |
| `pattern` | `boolean \| "any"` | `true` returns only patterns, `false` only regular compositions. Default: both. |
| `orderBy` | `string` | Sorting: `updated_at_DESC`, `updated_at_ASC`, `created_at_DESC`, `created_at_ASC`, `name_DESC`, `name_ASC`, `slug_DESC`, `slug_ASC`. Default: name ascending. |
| `limit` / `offset` | `number` | Pagination. |
| `withTotalCount` | `boolean` | Include the total result count in the response (impacts performance). |
| `resolveData` | `boolean` | When `true`, the list is fetched through the edge API with data resolution applied to each composition. Default: `false`. |
| `filters` | `CompositionFilters` | Structured field filters (see below). |
| `select` | `ProjectionSpec` | [Data projection](#selecting-fields-with-data-projection) applied to each composition. |

---

## Filtering compositions

The Canvas Client supports the same structured filter syntax as the [Content Client](https://docs.uniform.app/docs/sdk/content-client#search-and-filtering), but compositions use `parameters` where entries use `fields`:

```ts
const response = await canvasClient.getCompositionList({
  filters: {
    "type[eq]": "landingPage",
    "parameters.heroTitle[match]": "summer",
  },
});
```

See the [Content Client filter reference](https://docs.uniform.app/docs/sdk/content-client#available-operators) for the full list of operators.

---

## Selecting fields with data projection

The `select` option fetches a subset of each composition instead of the whole thing, reducing payload size and skipping server-side resolution work for content you don't need. For compositions, the `fields` bucket selects parameters by name and the `slots` bucket controls how much of the component tree is returned:

```ts
const response = await canvasClient.getCompositionList({
  filters: { "type[eq]": "landingPage" },
  select: {
    fields: { only: ["pageTitle", "slug"] },
    slots: { depth: 1 },
  },
});
```

See [data projection](https://docs.uniform.app/docs/sdk/content-client#selecting-fields-with-data-projection) on the Content Client page for the full projection reference. The same option is available on [`RouteClient.getRoute`](https://docs.uniform.app/docs/sdk/route-client#fetching-a-subset-with-select).

---

## Component definitions

`getComponentDefinitions` fetches the component definitions of a project -- useful for tooling, validation, or generating typed component maps:

```ts
const { componentDefinitions } = await canvasClient.getComponentDefinitions();

const compositionTypes = componentDefinitions.filter(
  (definition) => definition.canBeComposition
);
```

---

## Management operations

The client can also create, update, and delete compositions and component definitions. These operations require an API key with write permissions:

| Method | Description |
| --- | --- |
| `updateComposition(body, options?)` | Creates or updates a composition. Pass `options.ifUnmodifiedSince` for optimistic concurrency control (the API returns HTTP 409 if the composition changed since that timestamp). |
| `removeComposition(body)` | Deletes a composition by ID. |
| `getCompositionHistory(options)` | Fetches historical versions of a composition or pattern. |
| `updateComponentDefinition(body)` | Creates or updates a component definition. |
| `removeComponentDefinition(body)` | Deletes a component definition. |

```ts
await canvasClient.updateComposition({
  state: CANVAS_DRAFT_STATE,
  composition: updatedComposition,
});
```

> **Warning:**
>
> Most front ends only need the read methods. Management operations modify project content directly -- prefer running them in scripts or trusted server environments, never in browser code.

---

## Import reference

| Export | Package | Description |
| --- | --- | --- |
| `CanvasClient` | `@uniformdev/canvas` | Main composition client |
| `UncachedCanvasClient` | `@uniformdev/canvas` | Canvas Client with API caching bypassed |
| `CANVAS_DRAFT_STATE` / `CANVAS_PUBLISHED_STATE` | `@uniformdev/canvas` | Constants for the `state` option |
| `ProjectionSpec` | `@uniformdev/canvas` | Type for the `select` data projection option |
| `getCanvasClient` | `@uniformdev/next-app-router` | Pre-configured canvas client (server-only, App Router) |
