Locale handling in the Optimization SDK Suite
Overview
Use this document to keep the application Contentful locale separate from the SDK Experience/event locale across Web, React Web, Next.js, Node, React Native, iOS, and Android applications. For app-owned content fetching and entry resolution, the SDKs do not resolve Contentful locales, create Contentful Delivery API clients, or infer browser, device, or request locales. Applications choose their own locale from routing, i18n, native state, or request logic and pass it to manual Contentful calls or SDK-managed entry fetching. Preview and debug tooling is separate: preview-panel APIs can use Contentful clients or pre-fetched entries to load Optimization definitions, but they do not choose or fetch locales for application content.
For entry replacement mechanics, see Entry optimization and variant resolution. For package setup, use the relevant integration guide or package README.
Runtime locale surfaces
Each runtime exposes the SDK Experience/event locale through its own API surface:
The locale channels
Locale handling in an optimized application has two application-facing channels.
The same string is often used for both channels, but the SDK treats them as separate inputs. The SDK does not know which Contentful locales are enabled in a space and does not validate that an SDK locale is supported by Contentful.
Application Contentful locale
Choose an appLocale with application-owned logic, then pass it to CDA or CPA calls. JavaScript
managed fetching uses the application-owned contentful.js client from contentful: { client };
the SDK does not create clients, discover Contentful locales, infer browser or request locales, or
own locale policy.
SDK-managed Contentful fetch, JavaScript runtimes (TypeScript):
Per-call entryQuery or query values override contentful.defaultQuery. If no Contentful query
locale is provided, managed fetching falls back to the SDK locale before calling
contentful.js getEntry(). Request-bound Node clients use forRequest({ locale }) as that
fallback. Use a concrete locale such as en-US; do not use withAllLocales or locale=* for
entries that the SDK will resolve.
Manual Contentful fetch, JavaScript runtimes (TypeScript):
Pass the same appLocale anywhere Contentful content is fetched: browser data loaders, React hooks,
server routes, React Native services, and native app content clients. If the app omits locale,
Contentful uses the space default locale.
Use the same appLocale in cache keys when localized content can differ.
JavaScript runtimes (TypeScript):
SDK Experience and event locale
Stateful SDKs accept top-level locale as the default SDK Experience/event locale:
Web runtime (TypeScript):
That value initializes the SDK locale state, sets the default Experience API request locale, and
provides the default event context locale. If locale is omitted, the Experience API locale query
is omitted by default. Event payloads still include context.locale: 'en-US' when neither an SDK
locale nor an event payload locale is available, because the event schemas require a locale.
The Experience API locale is not a Contentful CDA locale. It can localize Experience API profile
fields, such as location.city and location.country values used by MergeTags, and the SDK also
copies it into the default event context.locale. It does not localize Contentful entries or
resolve Contentful locale fallbacks.
The low-level Experience API client still supports its own default and per-request locale options.
Use those when calling the low-level API client directly or when an advanced stateless request needs
a pass-through.
Stateful SDKs
Web, React Web, React Native, iOS, and Android keep live locale state:
- JavaScript SDKs expose
optimization.locale,optimization.states.locale, andoptimization.setLocale(locale). - Web custom elements apply
<ctfl-optimization-root locale="...">to the SDK instance that the element creates and owns. If the element reuses an assignedsdkproperty or the globalwindow.contentfulOptimizationinstance, update that SDK instance withsetLocale(). - React Web and React Native providers update provider-owned SDK instances when their
localeprop changes. - iOS exposes
OptimizationClient.localeandOptimizationClient.setLocale(_:). - Android exposes
OptimizationClient.localeandOptimizationClient.setLocale(locale).
On iOS and Android, call setLocale only after the client has initialized; set the initial locale
through OptimizationConfig before mounting or initializing.
setLocale(locale) validates and normalizes the SDK Experience/event locale. It does not refetch
Contentful content, update routes, or clear application caches. JavaScript managed fetching can use
the SDK locale only as the fallback getEntry() query locale when neither contentful.defaultQuery
nor a per-call query provides one. Application code must refetch Contentful entries with its chosen
Contentful locale.
Web or React Web client runtime (TypeScript):
Next.js adapter
Next.js composes the stateless Node SDK on the server with the React Web SDK on the client. For App
Router integrations, prefer the /app-router createNextjsAppRouterOptimization({ locale })
factory. It returns app-local bound OptimizationRoot, OptimizationProvider, OptimizedEntry,
and route trackers. Next.js resolves those bound exports to the automatic server implementation in
Server Components and to React Web-backed client exports in Client Components.
Next.js App Router binding module (TypeScript):
The bound server root and bound server OptimizedEntry use the factory locale when they load
server Optimization data. The bound client root applies the same locale through React Web
configuration.
Keep lower-level/manual surfaces for direct request control. createNextjsOptimization({ locale })
sets the server SDK default locale, getNextjsServerOptimizationData(sdk, { locale }) binds an App
Router Server Component request, getServerSideOptimizationProps(context) binds a Pages Router
getServerSideProps request with explicit locale taking precedence over context.locale,
getNextjsEsrOptimizationData(sdk, { locale }) binds a request-rendered ESR flow, and manual client
OptimizationRoot locale follows the React Web behavior.
Next.js manual server runtime (TypeScript):
Use the request-scoped manual locale path when a manual route can serve different locales. A
module-level createNextjsOptimization({ locale }) value is a default for the server SDK instance,
not the current request locale. Manual Server Components pass headers() to
getNextjsServerOptimizationData() so the SDK can derive page context from the request URL captured
by the Next.js proxy or middleware helper.
Locale handoff is separate from server optimization state handoff. When the browser provider has the
server data at its boundary, pass it with serverOptimizationState on OptimizationRoot. With App
Router bound components, the bound server root handles that state handoff. With Pages Router,
pages/_app.tsx receives the helper result through pageProps and passes it to the bound root.
Keep defaults for configuration or default state such as consent policy, not for server-returned
profile, selected optimizations, or changes.
Node and stateless SDKs
Node and other stateless environments can set a constructor locale, but that value is a default
for the SDK instance. Bind request-specific locale with forRequest({ locale }), which is the
promoted request-scoped path for localized Experience API responses and default event context.
Node server runtime (TypeScript):
forRequest({ locale }) sets the request-bound Experience API locale and default event context
locale. If both locale and experienceOptions.locale are supplied, locale wins. Use
experienceOptions.locale only as an advanced low-level pass-through when locale is not supplied.
When a Node SDK is configured with contentful: { client }, root fetchOptimizedEntry(entryId)
needs explicit selectedOptimizations for personalized results. A request-bound forRequest()
client uses the latest accepted Experience response selections by default when
fetchOptimizedEntry(entryId) omits selectedOptimizations. It also uses the request locale as
the managed Contentful query locale when neither contentful.defaultQuery nor the per-call query
sets locale.
Entry resolution and localized Contentful content
Entry resolution expects one localized view of a baseline entry and linked optimization entries. Pass direct single-locale field values to the runtime-specific entry resolution surface:
- Core, Web, and Node
fetchContentfulEntry()andfetchOptimizedEntry()for JavaScript SDK-managed fetching through an app-ownedcontentful.jsclient. - Web and Node
resolveOptimizedEntry()for manual baseline entries. - React Web
OptimizedEntryanduseOptimizedEntry()with eitherbaselineEntryor managedentryIdplus optionalentryQuery. - Web Component
ctfl-optimized-entrywith eitherbaselineEntryor managedentry-id/entryIdplus optionalentryQuery. - Next.js bound
OptimizedEntryfromcreateNextjsAppRouterOptimization()for App Router Server and Client Components, or fromcreateNextjsPagesRouterOptimization()for Pages Router client rendering. Lower-level server flows can useresolveOptimizedEntry()or managedfetchOptimizedEntry(), then pass manualbaselineEntryandresolvedDataprops or the managed result toServerOptimizedEntrywhen server-rendered tracking attributes are needed. - React Native
OptimizedEntryanduseOptimizedEntry()with eitherbaselineEntryor managedentryIdplus optionalentryQuery;useEntryResolver()remains manual-only. - iOS
OptimizationClient.resolveOptimizedEntry(baseline:selectedOptimizations:)and SwiftUIOptimizedEntry(entry:). - Android
OptimizationClient.resolveOptimizedEntry(...), ComposeOptimizedEntry(entry:), and XML ViewsOptimizedEntryView.setEntry(...).
Do not pass all-locale CDA responses from withAllLocales or locale=*.
The SDK does not mutate application Contentful clients or infer when a content refetch is needed. When route or language state changes, the application must update SDK locale state, refetch Contentful content with the app locale, clear SDK-managed Contentful entry cache entries when those cached CDA results are no longer valid, and invalidate app caches as needed.
Application responsibilities
Applications own:
- Choosing the application Contentful locale from routes, request context, i18n state, or native app state.
- Passing the Contentful locale to manual CDA and CPA requests or SDK-managed
contentful.jsfetching. - Passing the SDK Experience/event locale through top-level SDK
locale, providerlocale, Next.jscreateNextjsAppRouterOptimization({ locale }), Pages RoutergetServerSideOptimizationProps(), lower-level Next.jsgetNextjsServerOptimizationData({ locale }), Next.js ESRgetNextjsEsrOptimizationData({ locale }), native configlocale, nativesetLocale, or NodeforRequest({ locale }). - Keeping localized content cache keys distinct.
- Refetching Contentful content after locale changes.
- Ensuring the Contentful locale is supported by the target Contentful environment.
Related documentation
- Entry optimization and variant resolution
- Integrate the Web SDK in a web app
- Integrate the React Web SDK in a React app
- Integrate the Optimization Next.js SDK in a Next.js App Router app
- Integrate the Optimization Next.js SDK in a Next.js Pages Router app
- Integrate the Node SDK in a Node app
- Integrate the Optimization React Native SDK in a React Native app
- React Native SDK interaction tracking mechanics
- Integrate the Optimization iOS SDK in a SwiftUI app
- Integrate the Optimization iOS SDK in a UIKit app
- iOS SDK runtime and interaction mechanics
- Integrate the Optimization Android SDK in a Jetpack Compose app
- Integrate the Optimization Android SDK in an Android Views app
- Android SDK runtime and interaction mechanics