⚠️ Dev build. Published to npm as a pre-release (devtag). APIs are unstable and will change.
A TypeScript client for delivering and previewing Contentful Experiences. Fetch fully resolved Views and personalized Experiences with rich, typed responses and first-class IntelliSense.
- Installation
- Reference
- Usage
- Authentication
- Environments
- Request and Response Types
- Exception Handling
- Advanced
npm i -s @contentful/experience-deliveryNote: This package is not yet published as a stable release on the public npm registry. Until then, see BUILDING.md for how to build and consume it from source.
A full reference for this library is available here.
Instantiate the client with a Content Delivery API token and fetch a published Experience:
import { ContentfulViewDeliveryClient } from "@contentful/experience-delivery";
const client = new ContentfulViewDeliveryClient({
token: process.env.CONTENTFUL_CDA_TOKEN!,
});
const experience = await client.experience.get(
"spaceId",
"environmentId",
"experienceId",
{ locale: "en-US" },
);See Authentication for preview tokens and the
access_token query-parameter alternative.
The API supports two authentication modes — both backed by a Contentful access token. You can mint tokens from the Settings → API keys page of any Contentful space.
For published content, use a Content Delivery API (CDA) token:
import { ContentfulViewDeliveryClient } from "@contentful/experience-delivery";
const client = new ContentfulViewDeliveryClient({
token: process.env.CONTENTFUL_CDA_TOKEN!,
});For draft/unpublished content, create a separate client with a Content Preview API (CPA) token and the preview base URL:
import { ContentfulViewDeliveryClient } from "@contentful/experience-delivery";
const previewClient = new ContentfulViewDeliveryClient({
token: process.env.CONTENTFUL_CPA_TOKEN!,
baseUrl: "https://preview.xdn.contentful.com",
});
const draft = await previewClient.experience.get(spaceId, envId, experienceId, {
preview: "true",
locale: "en-US",
});For environments where you can't send the Authorization header (e.g. some browser/CDN
scenarios), the API also accepts an access_token query parameter:
await client.experience.get(spaceId, envId, experienceId, {
locale: "en-US",
accessToken: process.env.CONTENTFUL_CDA_TOKEN!,
});This SDK allows you to configure different environments for API requests.
import { ContentfulViewDeliveryClient, ContentfulViewDeliveryEnvironment } from "@contentful/experience-delivery";
const client = new ContentfulViewDeliveryClient({
environment: ContentfulViewDeliveryEnvironment.Default,
});The SDK exports all request and response types as TypeScript interfaces. Simply import them with the following namespace:
import { ContentfulViewDelivery } from "@contentful/experience-delivery";
const request: ContentfulViewDelivery.GetExperienceRequest = {
...
};When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error will be thrown.
import { ContentfulViewDeliveryError } from "@contentful/experience-delivery";
try {
await client.experience.getWithOverrides(...);
} catch (err) {
if (err instanceof ContentfulViewDeliveryError) {
console.log(err.statusCode);
console.log(err.message);
console.log(err.body);
console.log(err.rawResponse);
}
}This SDK supports direct imports of subpackage clients, which allows JavaScript bundlers to tree-shake and include only the imported subpackage code. This results in much smaller bundle sizes.
import { ExperienceClient } from '@contentful/experience-delivery/experience';
const client = new ExperienceClient({...});If you would like to send additional headers as part of the request, use the headers request option.
import { ContentfulViewDeliveryClient } from "@contentful/experience-delivery";
const client = new ContentfulViewDeliveryClient({
...
headers: {
'X-Custom-Header': 'custom value'
}
});
const response = await client.experience.getWithOverrides(..., {
headers: {
'X-Custom-Header': 'custom value'
}
});If you would like to send additional query string parameters as part of the request, use the queryParams request option.
const response = await client.experience.getWithOverrides(..., {
queryParams: {
'customQueryParamKey': 'custom query param value'
}
});The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long as the request is deemed retryable and the number of retry attempts has not grown larger than the configured retry limit (default: 2).
Which status codes are retried depends on the retryStatusCodes generator configuration:
legacy (current default): retries on
recommended: retries on
- 408 (Timeout)
- 429 (Too Many Requests)
- 502 (Bad Gateway)
- 503 (Service Unavailable)
- 504 (Gateway Timeout)
Use the maxRetries request option to configure this behavior.
const response = await client.experience.getWithOverrides(..., {
maxRetries: 0 // override maxRetries at the request level
});The SDK defaults to a 60 second timeout. Use the timeoutInSeconds option to configure this behavior.
const response = await client.experience.getWithOverrides(..., {
timeoutInSeconds: 30 // override timeout to 30s
});The SDK allows users to abort requests at any point by passing in an abort signal.
const controller = new AbortController();
const response = await client.experience.getWithOverrides(..., {
abortSignal: controller.signal
});
controller.abort(); // aborts the requestThe SDK provides access to raw response data, including headers, through the .withRawResponse() method.
The .withRawResponse() method returns a promise that results to an object with a data and a rawResponse property.
const { data, rawResponse } = await client.experience.getWithOverrides(...).withRawResponse();
console.log(data);
console.log(rawResponse.headers['X-My-Header']);The SDK supports logging. You can configure the logger by passing in a logging object to the client options.
import { ContentfulViewDeliveryClient, logging } from "@contentful/experience-delivery";
const client = new ContentfulViewDeliveryClient({
...
logging: {
level: logging.LogLevel.Debug, // defaults to logging.LogLevel.Info
logger: new logging.ConsoleLogger(), // defaults to ConsoleLogger
silent: false, // defaults to true, set to false to enable logging
}
});The logging object can have the following properties:
level: The log level to use. Defaults tologging.LogLevel.Info.logger: The logger to use. Defaults to alogging.ConsoleLogger.silent: Whether to silence the logger. Defaults totrue.
The level property can be one of the following values:
logging.LogLevel.Debuglogging.LogLevel.Infologging.LogLevel.Warnlogging.LogLevel.Error
To provide a custom logger, you can pass in an object that implements the logging.ILogger interface.
Custom logger examples
Here's an example using the popular winston logging library.
import winston from 'winston';
const winstonLogger = winston.createLogger({...});
const logger: logging.ILogger = {
debug: (msg, ...args) => winstonLogger.debug(msg, ...args),
info: (msg, ...args) => winstonLogger.info(msg, ...args),
warn: (msg, ...args) => winstonLogger.warn(msg, ...args),
error: (msg, ...args) => winstonLogger.error(msg, ...args),
};Here's an example using the popular pino logging library.
import pino from 'pino';
const pinoLogger = pino({...});
const logger: logging.ILogger = {
debug: (msg, ...args) => pinoLogger.debug(args, msg),
info: (msg, ...args) => pinoLogger.info(args, msg),
warn: (msg, ...args) => pinoLogger.warn(args, msg),
error: (msg, ...args) => pinoLogger.error(args, msg),
};The SDK provides a low-level fetch method for making custom HTTP requests while still
benefiting from SDK-level configuration like authentication, retries, timeouts, and logging.
This is useful for calling API endpoints not yet supported in the SDK.
const response = await client.fetch("/v1/custom/endpoint", {
method: "GET",
}, {
timeoutInSeconds: 30,
maxRetries: 3,
headers: {
"X-Custom-Header": "custom-value",
},
});
const data = await response.json();The SDK works in the following runtimes:
- Node.js 22+
- Vercel
- Cloudflare Workers
- Deno v1.25+
- Bun 1.0+
- React Native