Warning
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.
Table of Contents
Install using an NPM-compatible package manager, pnpm for example:
pnpm install @contentful/optimization-nodeImport 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 Experience options to event methods inside each incoming request:
const optimization = new ContentfulOptimization({
clientId: 'your-client-id',
environment: 'main',
})
const requestOptions = { locale: 'en-US' }
const optimizationData = await optimization.page({ profile }, 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 |
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 used for Experience API location labels |
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.
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:
app.get('/products/:slug', async (req, res) => {
const optimizationData = await optimization.page(
{
profile: { id: req.cookies.profileId },
properties: { path: req.path },
},
{ locale: req.acceptsLanguages()[0] ?? 'en-US' },
)
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,
)Use getMergeTagValue() for Contentful Rich Text merge tags and getFlag() for Custom Flags. 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.exampleand create or updatepackages/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
- Integrating the Optimization Node SDK in a Node app - step-by-step server-side integration guide
- Node SDK generated reference - exported API reference
- Node reference implementation - server-rendered implementation using request-scoped SDK calls
- Node + Web reference implementation - hybrid SSR and browser implementation
- Optimization Web SDK - browser SDK used when the same application also needs client-side consent, persistence, tracking, or live updates