You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+33-26Lines changed: 33 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -102,12 +102,15 @@ Required at the root level. Leverages React’s `Context` API to allow access to
102
102
103
103
_props_
104
104
105
-
-`optimizely : ReactSDKClient` created from `createInstance`
106
-
-`user: { id: string; attributes?: { [key: string]: any } } | Promise` User info object - `id` and `attributes` will be passed to the SDK for every feature flag, A/B test, or `track` call, or a `Promise` for the same kind of object
107
-
-`timeout : Number` (optional) The amount of time for `useDecision` to return `null` flag Decision while waiting for the SDK instance to become ready, before resolving.
108
-
-`isServerSide : Boolean` (optional) must pass `true` here for server side rendering
109
-
-`userId : String` (optional) **_Deprecated, prefer using `user` instead_**. Another way to provide user id. The `user` object prop takes precedence when both are provided.
110
-
-`userAttributes : Object` : (optional) **_Deprecated, prefer using `user` instead_**. Another way to provide user attributes. The `user` object prop takes precedence when both are provided.
105
+
| Prop | Type | Required | Description |
106
+
| --- | --- | --- | --- |
107
+
|`optimizely`|`ReactSDKClient`| Yes | Instance created from `createInstance`|
108
+
|`user`|`{ id: string; attributes?: { [key: string]: any } }`\|`Promise`| No | User info object — `id` and `attributes` will be passed to the SDK for every feature flag, A/B test, or `track` call. Can also be a `Promise` for the same kind of object. |
109
+
|`timeout`|`number`| No | The amount of time for `useDecision` to return `null` flag Decision while waiting for the SDK instance to become ready, before resolving. |
110
+
|`isServerSide`|`boolean`| No | Must pass `true` for server side rendering. |
111
+
|`userId`|`string`| No |**Deprecated, prefer `user` instead.** Another way to provide user id. The `user` prop takes precedence when both are provided. |
112
+
|`userAttributes`|`object`| No |**Deprecated, prefer `user` instead.** Another way to provide user attributes. The `user` prop takes precedence when both are provided. |
113
+
|`qualifiedSegments`|`string[]`| No | Pre-fetched ODP audience segments for the user. Useful during SSR where async segment fetching is unavailable. |
111
114
112
115
### Readiness
113
116
@@ -382,25 +385,27 @@ The following type definitions are used in the `ReactSDKClient` interface:
382
385
383
386
`ReactSDKClient` instances have the methods/properties listed below. Note that in general, the API largely matches that of the core `@optimizely/optimizely-sdk` client instance, which is documented on the [Optimizely Feature Experimentation developer docs site](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/welcome). The major exception is that, for most methods, user id & attributes are **_optional_** arguments. `ReactSDKClient` has a current user. This user's id & attributes are automatically applied to all method calls, and overrides can be provided as arguments to these method calls if desired.
384
387
385
-
-`onReady(opts?: { timeout?: number }): Promise<onReadyResult>` Returns a Promise that fulfills with an `onReadyResult` object representing the initialization process. The instance is ready when it has fetched a datafile and a user is available (via `setUser` being called with an object, or a Promise passed to `setUser` becoming fulfilled). If the `timeout` period happens before the client instance is ready, the `onReadyResult` object will contain an additional key, `dataReadyPromise`, which can be used to determine when, if ever, the instance does become ready.
386
-
-`user: User` The current user associated with this client instance
387
-
-`setUser(userInfo: User | Promise<User>): void` Call this to update the current user
388
-
-`onUserUpdate(handler: (userInfo: User) => void): () => void` Subscribe a callback to be called when this instance's current user changes. Returns a function that will unsubscribe the callback.
389
-
-`decide(key: string, options?: optimizely.OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): OptimizelyDecision` Returns a decision result for a flag key for a user. The decision result is returned in an OptimizelyDecision object, and contains all data required to deliver the flag rule.
390
-
-`decideAll(options?: optimizely.OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): { [key: string]: OptimizelyDecision }` Returns decisions for all active (unarchived) flags for a user.
391
-
-`decideForKeys(keys: string[], options?: optimizely.OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): { [key: string]: OptimizelyDecision }` Returns an object of decision results mapped by flag keys.
392
-
-`activate(experimentKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string | null` Activate an experiment, and return the variation for the given user.
393
-
-`getVariation(experimentKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string | null` Return the variation for the given experiment and user.
394
-
-`getFeatureVariables(featureKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): VariableValuesObject`: Decide and return variable values for the given feature and user <br /> <b>Warning:</b> Deprecated since 2.1.0 <br /> `getAllFeatureVariables` is added in JavaScript SDK which is similarly returning all the feature variables, but it sends only single notification of type `all-feature-variables` instead of sending for each variable. As `getFeatureVariables` was added when this functionality wasn't provided by `JavaScript SDK`, so there is no need of it now and it would be removed in next major release
395
-
-`getFeatureVariableString(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): string | null`: Decide and return the variable value for the given feature, variable, and user
396
-
-`getFeatureVariableInteger(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): number | null` Decide and return the variable value for the given feature, variable, and user
397
-
-`getFeatureVariableBoolean(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): boolean | null` Decide and return the variable value for the given feature, variable, and user
398
-
-`getFeatureVariableDouble(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): number | null` Decide and return the variable value for the given feature, variable, and user
399
-
-`isFeatureEnabled(featureKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): boolean` Return the enabled status for the given feature and user
400
-
-`getEnabledFeatures(overrideUserId?: string, overrideAttributes?: UserAttributes): Array<string>`: Return the keys of all features enabled for the given user
401
-
-`track(eventKey: string, overrideUserId?: string | EventTags, overrideAttributes?: UserAttributes, eventTags?: EventTags): void` Track an event to the Optimizely results backend
402
-
-`setForcedVariation(experiment: string, overrideUserIdOrVariationKey: string, variationKey?: string | null): boolean` Set a forced variation for the given experiment, variation, and user. **Note**: calling `setForcedVariation` on a given client will trigger a re-render of all `useExperiment` hooks and `OptimizelyExperiment` components that are using that client.
403
-
-`getForcedVariation(experiment: string, overrideUserId?: string): string | null` Get the forced variation for the given experiment, variation, and user
388
+
| Method / Property | Signature | Description |
389
+
| --- | --- | --- |
390
+
|`onReady`|`(opts?: { timeout?: number }): Promise<onReadyResult>`| Returns a Promise that fulfills with an `onReadyResult` object representing the initialization process. The instance is ready when it has fetched a datafile and a user is available (via `setUser` being called with an object, or a Promise passed to `setUser` becoming fulfilled). If the `timeout` period happens before the client instance is ready, the `onReadyResult` object will contain an additional key, `dataReadyPromise`, which can be used to determine when, if ever, the instance does become ready. |
391
+
|`user`|`User`| The current user associated with this client instance. |
392
+
|`setUser`|`(userInfo: User \| Promise<User>, qualifiedSegments?: string[]): Promise<void>`| Call this to update the current user. Optionally pass `qualifiedSegments` to set pre-fetched ODP audience segments on the user context. |
393
+
|`onUserUpdate`|`(handler: (userInfo: User) => void): () => void`| Subscribe a callback to be called when this instance's current user changes. Returns a function that will unsubscribe the callback. |
394
+
|`decide`|`(key: string, options?: OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: UserAttributes): OptimizelyDecision`| Returns a decision result for a flag key for a user. The decision result is returned in an `OptimizelyDecision` object, and contains all data required to deliver the flag rule. |
395
+
|`decideAll`|`(options?: OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: UserAttributes): { [key: string]: OptimizelyDecision }`| Returns decisions for all active (unarchived) flags for a user. |
396
+
|`decideForKeys`|`(keys: string[], options?: OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: UserAttributes): { [key: string]: OptimizelyDecision }`| Returns an object of decision results mapped by flag keys. |
397
+
|`activate`|`(experimentKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string \| null`| Activate an experiment, and return the variation for the given user. |
398
+
|`getVariation`|`(experimentKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string \| null`| Return the variation for the given experiment and user. |
399
+
|`getFeatureVariables`|`(featureKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): VariableValuesObject`|**Deprecated since 2.1.0.** Decide and return variable values for the given feature and user. Use `getAllFeatureVariables` instead. |
400
+
|`getFeatureVariableString`|`(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string \| null`| Decide and return the variable value for the given feature, variable, and user. |
401
+
|`getFeatureVariableInteger`|`(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): number \| null`| Decide and return the variable value for the given feature, variable, and user. |
402
+
|`getFeatureVariableBoolean`|`(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): boolean \| null`| Decide and return the variable value for the given feature, variable, and user. |
403
+
|`getFeatureVariableDouble`|`(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): number \| null`| Decide and return the variable value for the given feature, variable, and user. |
404
+
|`isFeatureEnabled`|`(featureKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): boolean`| Return the enabled status for the given feature and user. |
405
+
|`getEnabledFeatures`|`(overrideUserId?: string, overrideAttributes?: UserAttributes): Array<string>`| Return the keys of all features enabled for the given user. |
406
+
|`track`|`(eventKey: string, overrideUserId?: string \| EventTags, overrideAttributes?: UserAttributes, eventTags?: EventTags): void`| Track an event to the Optimizely results backend. |
407
+
|`setForcedVariation`|`(experiment: string, overrideUserIdOrVariationKey: string, variationKey?: string \| null): boolean`| Set a forced variation for the given experiment, variation, and user. **Note:** triggers a re-render of all `useExperiment` hooks and `OptimizelyExperiment` components using that client. |
408
+
|`getForcedVariation`|`(experiment: string, overrideUserId?: string): string \| null`| Get the forced variation for the given experiment, variation, and user. |
404
409
405
410
## Rollout or experiment a feature user-by-user
406
411
@@ -445,6 +450,8 @@ function MyComponent() {
445
450
|`defaultDecideOptions`|`[DISABLE_DECISION_EVENT]`| avoids duplicate decision events if the client will also fire them after hydration |
446
451
|`odpOptions.disabled`|`true`| Disables ODP event manager processing during SSR — avoids unnecessary event batching, API calls, and VUID tracking overhead |
447
452
453
+
> **ODP audience segments during SSR:** Disabling ODP prevents automatic segment fetching, but you can still make audience-segment-based decisions by passing pre-fetched segments via the `qualifiedSegments` prop on `OptimizelyProvider`. See the [Limitations — ODP segments](#limitations) section for details.
454
+
448
455
### React Server Components
449
456
450
457
The SDK can also be used directly in React Server Components without `OptimizelyProvider`. Create an instance, set the user, wait for readiness, and make decisions — all within an `async` server component:
@@ -479,7 +486,7 @@ For detailed Next.js examples covering both App Router and Pages Router patterns
479
486
480
487
-**Datafile required** — SSR requires a pre-fetched datafile. Using `sdkKey` alone falls back to a failed decision.
481
488
-**Static user only** — User `Promise` is not supported during SSR.
482
-
-**ODP segments unavailable** — ODP audience segments require async I/O and are not available during server rendering.
489
+
-**ODP segments** — ODP audience segments require async I/O and are not available during server rendering. Pass pre-fetched segments via the `qualifiedSegments` prop on `OptimizelyProvider` to enable synchronous ODP-based decisions. Without it, consider deferring the decision to the client using the fallback pattern.
483
490
484
491
For more details and workarounds, see the [Next.js Integration Guide — Limitations](docs/nextjs-integration.md#limitations).
Copy file name to clipboardExpand all lines: docs/nextjs-integration.md
+29-13Lines changed: 29 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,19 +16,17 @@ You will need your Optimizely SDK key, available from the Optimizely app under *
16
16
17
17
Server-side rendering requires a pre-fetched datafile. The SDK cannot fetch the datafile asynchronously during server rendering, so you must fetch it beforehand and pass it to `createInstance`.
18
18
19
-
There are many ways to pre-fetch the datafile on the server. Below are two common approaches you could follow.
19
+
There are several ways to pre-fetch the datafile on the server. Below are two common approaches you could follow.
20
20
21
21
## Next.js App Router
22
22
23
23
In the App Router, fetch the datafile in an async server component (e.g., your root layout) and pass it as a prop to a client-side provider.
24
24
25
25
### 1. Create a datafile fetcher
26
26
27
-
There are several ways to fetch the datafile. Here are two common approaches:
28
-
29
27
**Option A: Using the SDK's built-in datafile fetching (Recommended)**
30
28
31
-
Create an SDK instance with your `sdkKey` and let it fetch and cache the datafile internally. This approach benefits from the SDK's built-in polling and caching, making it suitable when you want automatic datafile updates across requests.
29
+
Create a module-level SDK instance with your `sdkKey` and use a notification listener to detect when the datafile is ready. This approach benefits from the SDK's built-in polling and caching, making it suitable when you want automatic datafile updates across requests.
Fetch the datafile directly from Optimizely's CDN. This is simpler and gives you full control over caching (e.g., via Next.js `fetch` options like `next.revalidate`), but does not include automatic polling for updates.
55
+
Fetch the datafile directly from CDN.
53
56
54
57
```ts
55
58
// src/data/getDatafile.ts
@@ -270,6 +273,19 @@ User `Promise` is not supported during SSR. You must provide a static user objec
270
273
<OptimizelyProvideruser={fetchUserPromise} .../>
271
274
```
272
275
273
-
### ODP audience segments unavailable
276
+
### ODP audience segments
277
+
278
+
ODP (Optimizely Data Platform) audience segments require fetching segment data via an async network call, which is not available during server rendering. To include segment data during SSR, pass pre-fetched segments via the `qualifiedSegments` prop on `OptimizelyProvider`:
279
+
280
+
```tsx
281
+
<OptimizelyProvider
282
+
optimizely={optimizely}
283
+
user={{ id: 'user123' }}
284
+
qualifiedSegments={['segment1', 'segment2']}
285
+
isServerSide={isServerSide}
286
+
>
287
+
{children}
288
+
</OptimizelyProvider>
289
+
```
274
290
275
-
ODP (Optimizely Data Platform) audience segments require fetching segment data via an async network call, which is not available during server rendering. Decisions will be made without audience segment data. If your experiment relies on ODP segments, consider using the loading state pattern above and deferring the decision to the client.
291
+
This enables synchronous ODP-based decisions during server rendering. If `qualifiedSegments` is not provided, decisions will be made without audience segment data — in that case, consider deferring the decision to the client using the loading state fallback pattern described above, where ODP segments are fetched automatically when ODP is enabled.
0 commit comments