---
title: Initialize the React SDK
slug: feature-experimentation/docs/initialize-the-react-sdk
docTags: 
createdAt: 2026-08-05T20:39:58.000Z
---

Use the `createInstance` method to initialize the React SDK and instantiate a `Client` instance. Each client corresponds to the datafile representing the state of a project for a certain environment.

## Minimum SDK version

v4.0.0+

For versions 3.x and earlier, see [React SDK prior to v4](docId:6VaYUNRnt2V-Sr3iQOO9Y).

## Description

The `createInstance` method accepts a modular configuration object. Unlike v3, where options like `sdkKey`, `datafile`, and event batching were top-level parameters, v4 uses dedicated factory functions for each component.

:::BlockQuote
**Important:** You must use `createInstance` from `@optimizely/react-sdk`, not from `@optimizely/optimizely-sdk`. A client created directly from the JS SDK will not work correctly with `<OptimizelyProvider>` and hooks.
:::

## Parameters

The following table lists the required and optional parameters for the `createInstance` configuration object:

| Parameter                 | Type                       | Description                                                                                                                                                           |
| ------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `projectConfigManager`    | `OpaqueConfigManager`      | **Required.** Manages the datafile. Create with `createPollingProjectConfigManager` or `createStaticProjectConfigManager`.                                            |
| `eventProcessor`          | `OpaqueEventProcessor`     | Processes and dispatches events. Create with `createBatchEventProcessor` or `createForwardingEventProcessor`. **Opt-in** — if not provided, no events are dispatched. |
| `logger`                  | `OpaqueLogger`             | Logger instance. Create with `createLogger`. **Opt-in** — disabled by default.                                                                                        |
| `errorNotifier`           | `OpaqueErrorNotifier`      | Error notification handler. Create with `createErrorNotifier`.                                                                                                        |
| `userProfileService`      | `UserProfileService`       | Synchronous user profile service for [sticky bucketing](docId\:eH-UMm_rOn_GdGDGLV6__).                                                                                |
| `userProfileServiceAsync` | `UserProfileServiceAsync`  | Asynchronous user profile service for sticky bucketing.                                                                                                               |
| `defaultDecideOptions`    | `OptimizelyDecideOption[]` | Default options applied to all decide calls.                                                                                                                          |
| `odpManager`              | `OpaqueOdpManager`         | ODP manager for audience segments and events. Create with `createOdpManager`. **Opt-in** — if not provided, ODP is disabled.                                          |
| `vuidManager`             | `OpaqueVuidManager`        | Visitor UID manager. Create with `createVuidManager`. **Opt-in** — disabled by default.                                                                               |
| `disposable`              | `boolean`                  | When `true`, marks the client as single-use for SSR (can be garbage collected without calling `close()`).                                                             |

## Returns

Instantiates a `Client` instance. In v4, `createInstance` throws an error on invalid config (v3 returned `null`).

## Example

### Instantiate with a datafile

Use `createStaticProjectConfigManager` for a fixed datafile with no polling:

```javascript
import {
  createInstance,
  createStaticProjectConfigManager,
  createForwardingEventProcessor,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createStaticProjectConfigManager({
    datafile: window.optimizelyDatafile,
  }),
  eventProcessor: createForwardingEventProcessor(),
});
```

### Instantiate with the SDK key

Use `createPollingProjectConfigManager` to have the SDK fetch and poll for the datafile:

```javascript
import {
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createPollingProjectConfigManager({
    sdkKey: "YOUR_SDK_KEY",
  }),
  eventProcessor: createBatchEventProcessor(),
});
```

### Instantiate with both SDK key and datafile

Use the given datafile immediately, then fetch and poll for updates in the background:

```javascript
import {
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createPollingProjectConfigManager({
    sdkKey: "YOUR_SDK_KEY",
    datafile: window.optimizelyDatafile,
    autoUpdate: true,
  }),
  eventProcessor: createBatchEventProcessor(),
});
```

### Render an `OptimizelyProvider` with a client and user

To use the React SDK hooks inside your app, render an `OptimizelyProvider` as the parent of your root app component. Provide your client as the `client` prop and a `user` object:

```javascript
import {
  OptimizelyProvider,
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createPollingProjectConfigManager({
    sdkKey: "YOUR_SDK_KEY",
  }),
  eventProcessor: createBatchEventProcessor(),
});

export default function App() {
  return (
    <OptimizelyProvider client={optimizely} user={{ id: "<YOUR_USER_ID>" }}>
      <App />
    </OptimizelyProvider>
  );
}
```

### Render an `OptimizelyProvider` in VUID-only mode

For VUID-only mode (no user ID), pass an empty object as the `user` prop. The SDK uses an auto-generated visitor UID for decisions and event tracking. You must enable VUID by passing `createVuidManager` and `createOdpManager` to `createInstance`:

```javascript
import {
  OptimizelyProvider,
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
  createOdpManager,
  createVuidManager,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createPollingProjectConfigManager({
    sdkKey: "YOUR_SDK_KEY",
  }),
  eventProcessor: createBatchEventProcessor(),
  odpManager: createOdpManager(),
  vuidManager: createVuidManager({
    enableVuid: true,
  }),
});

export default function App() {
  return (
    <OptimizelyProvider client={optimizely} user={{}}>
      <App />
    </OptimizelyProvider>
  );
}
```

## Config manager factories

| Factory                                                                                                | Use case                                                      |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- |
| `createPollingProjectConfigManager({ sdkKey, datafile?, autoUpdate?, updateInterval?, urlTemplate? })` | Fetches and polls for datafile updates. `sdkKey` is required. |
| `createStaticProjectConfigManager({ datafile })`                                                       | Uses a fixed datafile with no polling.                        |

### Polling config manager options

| Option           | Type             | Description                                                                  |
| ---------------- | ---------------- | ---------------------------------------------------------------------------- |
| `sdkKey`         | string           | **Required.** The key associated with an environment in the project.         |
| `datafile`       | string \| object | Optional initial datafile (JSON string or parsed object).                    |
| `autoUpdate`     | boolean          | When `true`, automatic updates are enabled. Default: `true`.                 |
| `updateInterval` | number           | Update interval in milliseconds. Minimum: 1000. Default: 300000 (5 minutes). |
| `urlTemplate`    | string           | Format string for the datafile URL. `%s` is replaced with the `sdkKey`.      |

## Event processor factories

| Factory                                                     | Use case                           |
| ----------------------------------------------------------- | ---------------------------------- |
| `createBatchEventProcessor({ batchSize?, flushInterval? })` | Batches events before dispatching. |
| `createForwardingEventProcessor()`                          | Forwards each event immediately.   |

:::hint{type="info"}
**Note**
Event processing is **opt-in** in v4. If no `eventProcessor` is passed to `createInstance`, no events are dispatched. To disable event dispatching, simply omit the `eventProcessor` parameter.
:::

## Other configurable modules

| Factory                                | Use case                                                                                       |
| -------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `createOdpManager()`                   | Enables ODP integration (audience segments, events).                                           |
| `createVuidManager({ enableVuid })`    | Enables visitor UID tracking.                                                                  |
| `createErrorNotifier({ handleError })` | Configures error notification.                                                                 |
| `createLogger({ logLevel })`           | Creates a logger instance. See [Customize the React SDK logger](docId\:P3fUO-5eYRbgDOYpu6Jli). |

### Full client creation example

```javascript
import {
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
  createOdpManager,
  createLogger,
  createErrorNotifier,
  DEBUG,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createPollingProjectConfigManager({
    sdkKey: "YOUR_SDK_KEY",
    autoUpdate: true,
    updateInterval: 60000,
  }),
  eventProcessor: createBatchEventProcessor({
    batchSize: 10,
    flushInterval: 2000,
  }),
  odpManager: createOdpManager(),
  logger: createLogger({ logLevel: DEBUG }),
  errorNotifier: createErrorNotifier({
    handleError: (error) => console.error("Custom error handler", error),
  }),
});
```

## Notes

## Dispose of the client

For effective resource management, properly close the Optimizely client instance when it is no longer needed by calling `optimizely.close()`.

The `.close()` method ensures that the processes and queues associated with the instance are properly released. This is essential for preventing memory leaks, especially in environments where resources are limited.

For SSR per-request instances, you can set `disposable: true` in `createInstance` so the instance can be garbage collected without explicitly calling `close()`.

See [Close Optimizely on application exit](docId\:yVT0vWsVCxZQGfUE4b8Ea).

## Server-side rendering

The React SDK supports server-side rendering (SSR). A pre-fetched datafile is required for SSR — without one, the SDK cannot make decisions during server rendering.

### Per-request client

Create a client with `createStaticProjectConfigManager` and a pre-fetched datafile. Use `disposable: true` so the instance can be garbage collected without explicitly calling `close()`:

```javascript
import { useMemo } from "react";
import {
  createInstance,
  createStaticProjectConfigManager,
  OptimizelyProvider,
  OptimizelyDecideOption,
  useDecide,
} from "@optimizely/react-sdk";

export default function Page({ datafile, userId }) {
  const optimizely = useState(() =>
    createInstance({
      projectConfigManager: createStaticProjectConfigManager({ datafile }),
      defaultDecideOptions: [OptimizelyDecideOption.DISABLE_DECISION_EVENT],
      disposable: true,
    })
  );

  return (
    <OptimizelyProvider client={optimizely} user={{ id: userId }}>
      <MyComponent />
    </OptimizelyProvider>
  );
}

function MyComponent() {
  const { decision, isLoading } = useDecide("flag1");
  if (isLoading) return null;
  return decision.enabled ? <p>Feature enabled</p> : <p>Feature disabled</p>;
}
```

### Module-level client

For a long-lived server process, create a singleton client at the module level with `createPollingProjectConfigManager`:

```javascript
import {
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
  OptimizelyProvider,
  OptimizelyDecideOption,
  useDecide,
} from "@optimizely/react-sdk";

const optimizely = createInstance({
  projectConfigManager: createPollingProjectConfigManager({
    sdkKey: process.env.NEXT_PUBLIC_OPTIMIZELY_SDK_KEY,
    datafile: preloadedDatafile,
  }),
  eventProcessor: createBatchEventProcessor(),
  defaultDecideOptions: [OptimizelyDecideOption.DISABLE_DECISION_EVENT],
});

function App() {
  return (
    <OptimizelyProvider client={optimizely} user={{ id: "user1" }}>
      <MyComponent />
    </OptimizelyProvider>
  );
}
```

### `getQualifiedSegments`

A standalone async utility that fetches qualified ODP audience segments for a user, given a datafile:

```typescript
import { getQualifiedSegments } from "@optimizely/react-sdk";

const { segments, error } = await getQualifiedSegments(userId, datafile);
```

| Argument   | Type                            | Description                                      |
| ---------- | ------------------------------- | ------------------------------------------------ |
| `userId`   | `string`                        | The user ID to fetch qualified segments for.     |
| `datafile` | `string \| Record<string, any>` | The Optimizely datafile (JSON object or string). |

**Returns** `Promise<QualifiedSegmentsResult>` — `{ segments: string[], error: Error | null }`

:::hint{type="info"}
**Note**
The ODP segment fetch adds latency to server rendering. Consider caching the result per user to avoid re-fetching on every request.
:::

### React Server Components

The SDK provides a server-safe entry point via the `react-server` export condition. Frameworks that support this condition (e.g., Next.js App Router) automatically resolve `@optimizely/react-sdk` to the server entry point when importing from a Server Component. This entry point excludes hooks and Provider (which use client-only React APIs).

```javascript
import {
  createInstance,
  createStaticProjectConfigManager,
} from "@optimizely/react-sdk";

export default async function ServerComponent() {
  const client = createInstance({
    projectConfigManager: createStaticProjectConfigManager({ datafile }),
  });

  await client.onReady();

  const userContext = client.createUserContext("user-123");
  const decision = userContext.decide("flag-key");

  client.close();

  return decision.enabled ? <NewFeature /> : <Default />;
}
```

### SSR limitations

- **Datafile required** – SSR requires a pre-fetched datafile. Using `sdkKey` alone falls back to a failed decision.
- **ODP segments** – ODP audience segments require async I/O and are not available during server rendering. Use [getQualifiedSegments](docId:9CfwJPUAXUm5OPN0283Fu) to pre-fetch segments server-side and pass them with the `qualifiedSegments` prop on `OptimizelyProvider`.

For framework-specific SSR patterns, see the [Next.js Integration Guide](docId\:AYdRy25Z0i2qetG0VxHSP).

## Source files

The language and platform source files containing the implementation for the React SDK are available on [GitHub](https://github.com/optimizely/react-sdk/blob/master/src/index.ts).
