The Optimization SDK Suite is pre-release (alpha). Breaking changes can be published at any time.
The Optimization Node SDK implements stateless server-side optimization behavior on top of the Optimization Core SDK. Use it for server rendering, server functions, and Node services that need request-scoped profile evaluation or event emission.
If you are integrating a Node application, start with Getting Started, then use Integrating the Optimization Node SDK in a Node app for the step-by-step flow. This README keeps the package orientation and common setup options close at hand; generated reference documentation remains the source of truth for exported API signatures.
Install using an NPM-compatible package manager, pnpm for example:
pnpm install @contentful/optimization-node
Import the Optimization class; both CJS and ESM module systems are supported, ESM preferred:
import ContentfulOptimization from '@contentful/optimization-node'
Create the SDK once per module or process, then pass request-scoped event context inside each incoming request:
const optimization = new ContentfulOptimization({
clientId: 'your-client-id',
environment: 'main',
contentfulLocales: {
default: 'en-US',
},
})
async function renderRequest(req: { headers: { 'accept-language'?: string } }, profileId: string) {
const { contentfulLocale, eventLocale } = optimization.resolveRequestLocale(req)
const requestOptions = contentfulLocale ? { locale: contentfulLocale } : undefined
return await optimization.page(
{ locale: eventLocale, profile: { id: profileId } },
requestOptions,
)
}
Use @contentful/optimization-node for server-side rendering, server functions, and Node services
that need stateless profile evaluation or event emission. Use the Web or React Web SDK alongside it
when browser-side consent, anonymous ID persistence, automatic interaction tracking, or live updates
are part of the same application.
The Node SDK is stateless. It does not maintain consent, profile, or browser persistence state between requests.
| Option | Required? | Default | Description |
|---|---|---|---|
clientId |
Yes | N/A | Shared API key for Experience API and Insights API requests |
environment |
No | 'main' |
Contentful environment identifier |
api |
No | See API options below | Experience API and Insights API endpoint options |
app |
No | undefined |
Application metadata attached to outgoing event context |
contentfulLocales |
No | undefined |
Contentful locale codes used by resolveRequestLocale() |
fetchOptions |
No | SDK defaults | Fetch timeout and retry behavior |
eventBuilder |
No | Node SDK defaults | Event metadata overrides for SDK-layer authors |
logLevel |
No | 'error' |
Minimum log level for the default console sink |
Common api options:
| Option | Required? | Default | Description |
|---|---|---|---|
experienceBaseUrl |
No | 'https://experience.ninetailed.co/' |
Base URL for the Experience API |
insightsBaseUrl |
No | 'https://ingest.insights.ninetailed.co/' |
Base URL for the Insights API |
enabledFeatures |
No | ['ip-enrichment', 'location'] |
Experience API features to apply to each request |
Request-scoped Experience options belong in the final argument to stateless event methods:
| Option | Description |
|---|---|
ip |
IP address override used by the Experience API |
locale |
Locale query parameter for localized Experience API responses |
plainText |
Sends performance-critical Experience API endpoints as text |
preflight |
Aggregates a new profile state without storing it |
Common fetchOptions are fetchMethod, requestTimeout, retries, intervalTimeout,
onFailedAttempt, and onRequestTimeout. Default retries intentionally apply only to HTTP 503
responses.
Use contentfulLocales.default for single-locale apps. For apps that match request locale input to
multiple Contentful locales, keep default as the fallback and list the supported Contentful locale
codes:
const optimization = new ContentfulOptimization({
clientId: 'your-client-id',
contentfulLocales: {
default: 'en-US',
supported: ['en-US', 'de-DE', 'fr-FR'],
},
})
Copy contentfulLocales.default and optional contentfulLocales.supported from Contentful locale
settings or the CMA locale list. The returned contentfulLocale, when present, is the configured
Contentful locale code to use for CDA fetches and the Experience API request option. Use
eventLocale separately in event context. Merge tags that reference localized profile fields such
as location.city and location.country then resolve in a language consistent with the rendered
content. See
Locale handling in the Optimization SDK Suite
for the full locale model.
For every option, callback payload, and exported type, use the generated Node SDK reference.
Build event context from the incoming request, then call page(), identify(), screen(),
track(), or sticky trackView() when optimization data is needed:
import type { Request } from 'express'
app.get('/products/:slug', async (req, res) => {
const { contentfulLocale, eventLocale } = optimization.resolveRequestLocale(req)
const requestOptions = contentfulLocale ? { locale: contentfulLocale } : undefined
const optimizationData = await optimization.page(
{
locale: eventLocale,
profile: { id: req.cookies.profileId },
properties: { path: req.path },
},
requestOptions,
)
res.render('product', { optimizationData })
})
In stateless runtimes, Insights-backed methods require a profile for delivery. Non-sticky
trackView, trackClick, trackHover, and trackFlagView require payload.profile.id.
Fetch Contentful entries in your application layer, then resolve variants with returned optimization data:
const resolvedEntry = optimization.resolveOptimizedEntry(
baselineEntry,
optimizationData?.selectedOptimizations,
)
Fetch entries with one CDA locale in the app layer. For localized apps, configure
contentfulLocales, then use the contentfulLocale returned by resolveRequestLocale() for CDA
fetches and the per-call { locale } request option so MergeTags that read localized profile fields
match the entry language. When contentfulLocale is absent because no contentfulLocales config is
present, omit the CDA and Experience API locale options intentionally. Do not pass all-locale CDA
responses from withAllLocales or locale=* into resolveOptimizedEntry(); the resolver expects
direct single-locale field values. See
Entry personalization and variant resolution
for the entry contract and
Locale handling in the Optimization SDK Suite
for request locale behavior.
Use getMergeTagValue() for Contentful Rich Text merge tags and getFlag() for Custom Flags. If a
merge tag references localized profile fields such as location.city or location.country, its
resolved value follows the localized profile data returned by the Experience API. The Node SDK is
stateless, so getFlag() does not automatically emit flag-view tracking.
Cache raw Contentful delivery payloads in your application layer, not profile-evaluated SDK event results.
| Data or call | Cache across requests? | Reason |
|---|---|---|
| Raw Contentful entries fetched from CDA | Yes | They are content snapshots and can be resolved per request |
resolveOptimizedEntry() and getMergeTagValue() results |
Request-local only | Results depend on the current profile and optimization data |
page(), identify(), screen(), track(), and sticky trackView() |
No | These calls perform side effects and return request-specific profile |
Non-sticky trackView(), trackClick(), trackHover(), trackFlagView() |
No | These calls emit Insights API events |
The Node SDK integration guide covers request context, profile persistence, Contentful entry resolution, and hybrid Node + browser setups in detail.
The package-local dev harness runs from packages/node/node-sdk/dev/ and reads .env from this
package directory.
Start from .env.example and create or update packages/node/node-sdk/.env.
Prefer the repo-standard PUBLIC_... variable names shown in .env.example.
Start the harness from the repo root:
pnpm --filter @contentful/optimization-node dev
Contentful ContentfulOptimization Node SDK.
Remarks
Adds Node-specific defaults via the ContentfulOptimization class. Core and transitive API exports are available from dedicated entrypoints:
@contentful/optimization-node/core-sdk,@contentful/optimization-node/api-client, and@contentful/optimization-node/api-schemas.