SDK Client Reference
Overview
Section titled “Overview”The Optimizely client is the entry point for the Feature Experimentation SDK. It downloads your project’s configuration (the datafile), manages the user profile service, dispatches events, and provides the createUserContext method that starts every feature decision.
You create one client instance per application lifecycle and reuse it for all decisions.
createInstance
Section titled “createInstance”Creates and returns an Optimizely client configured with your SDK key. The client begins downloading the datafile immediately.
import { createInstance } from '@optimizely/optimizely-sdk';
const optimizely = createInstance({
sdkKey: 'YOUR_SDK_KEY',
// Optional configuration
datafileOptions: {
autoUpdate: true, // Poll for datafile changes
updateInterval: 60_000, // Poll every 60 seconds
},
eventBatchSize: 10, // Batch up to 10 events
eventFlushInterval: 30_000, // Flush every 30 seconds
eventMaxQueueSize: 10_000, // Max queued events before dropping
}); using OptimizelySDK;
// Standard initialization
var optimizely = OptimizelyFactory.NewDefaultInstance(
"YOUR_SDK_KEY"
);
// With custom configuration
var config = new OptimizelyConfig
{
SdkKey = "YOUR_SDK_KEY",
DatafileAutoUpdate = true,
DatafileUpdateInterval = TimeSpan.FromSeconds(60),
EventBatchSize = 10,
EventFlushInterval = TimeSpan.FromSeconds(30),
};
var optimizely = OptimizelyFactory.NewDefaultInstance(config); from optimizely import optimizely
from optimizely.config_manager import PollingConfigManager
# Standard initialization
client = optimizely.Optimizely(sdk_key='YOUR_SDK_KEY')
# With polling configuration
config_manager = PollingConfigManager(
sdk_key='YOUR_SDK_KEY',
update_interval=60, # seconds
)
client = optimizely.Optimizely(
config_manager=config_manager
) Configuration options
Section titled “Configuration options”| Option | Type | Default | Description |
|---|---|---|---|
sdkKey | string | (required) | Your SDK key from Settings > Environments in the Optimizely app. |
datafileOptions.autoUpdate | boolean | false | When true, the SDK polls for datafile changes at the specified interval. |
datafileOptions.updateInterval | number | 300000 (5 min) | Polling interval in milliseconds. Minimum is 30000 (30 seconds). |
eventBatchSize | number | 10 | Number of events to batch before dispatching. Higher values reduce network calls. |
eventFlushInterval | number | 30000 | Maximum time in milliseconds to hold events before flushing, even if the batch is not full. |
eventMaxQueueSize | number | 10000 | Maximum events to queue. Events beyond this limit are dropped. |
defaultDecideOptions | OptimizelyDecideOption[] | [] | Default decision options applied to every decide call. Individual calls can override these. |
onReady
Section titled “onReady”Returns a promise that resolves when the SDK has downloaded and parsed the datafile. In JavaScript, always await this before making decisions.
const optimizely = createInstance({ sdkKey: 'YOUR_SDK_KEY' });
// Wait with a timeout
const result = await optimizely.onReady({ timeout: 5000 });
if (result.success) {
console.log('SDK ready — datafile loaded');
} else {
console.warn('SDK timed out — using defaults');
// decide() still works but returns default (off) decisions
} // NewDefaultInstance blocks until the datafile is ready.
// No separate onReady call is needed in C#.
var optimizely = OptimizelyFactory.NewDefaultInstance("YOUR_SDK_KEY");
// The client is ready to use immediately after this line.
var user = optimizely.CreateUserContext("user-42"); # The Python SDK initializes synchronously.
# If using PollingConfigManager, the first fetch happens before returning.
client = optimizely.Optimizely(sdk_key='YOUR_SDK_KEY')
# Check if the config is valid
if client.config_manager.get_config() is not None:
print('SDK ready')
else:
print('Config not yet available') Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
timeout | number | No | Maximum time in milliseconds to wait for the datafile. If the datafile is not available within this window, the promise resolves with { success: false }. JavaScript only. |
Return value (JavaScript)
Section titled “Return value (JavaScript)”| Field | Type | Description |
|---|---|---|
success | boolean | true if the datafile was loaded before the timeout. |
reason | string | When success is false, describes why initialization failed (e.g., "TIMEOUT"). |
createUserContext
Section titled “createUserContext”Creates an OptimizelyUserContext for making decisions. See the User Context reference for full details.
const user = optimizely.createUserContext('user-42', {
plan: 'enterprise',
country: 'US',
}); var user = optimizely.CreateUserContext("user-42",
new UserAttributes
{
{ "plan", "enterprise" },
{ "country", "US" },
}); user = client.create_user_context('user-42', {
'plan': 'enterprise',
'country': 'US',
}) getOptimizelyConfig
Section titled “getOptimizelyConfig”Returns a snapshot of the current project configuration. Use this for debugging or building admin interfaces that display the active datafile state.
const config = optimizely.getOptimizelyConfig();
if (config) {
console.log('Revision:', config.revision);
console.log('SDK Key:', config.sdkKey);
console.log('Environment:', config.environmentKey);
// Iterate over feature flags
for (const [key, feature] of Object.entries(config.featuresMap)) {
console.log(`Flag: ${key}`);
for (const [varKey, variable] of Object.entries(feature.variablesMap)) {
console.log(` Variable: ${varKey} = ${variable.value}`);
}
}
} var config = optimizely.GetOptimizelyConfig();
if (config != null)
{
Console.WriteLine($"Revision: {config.Revision}");
Console.WriteLine($"SDK Key: {config.SdkKey}");
foreach (var feature in config.FeaturesMap)
{
Console.WriteLine($"Flag: {feature.Key}");
foreach (var variable in feature.Value.VariablesMap)
{
Console.WriteLine($" Variable: {variable.Key} = {variable.Value.Value}");
}
}
} config = client.get_optimizely_config()
if config:
print(f'Revision: {config.revision}')
print(f'SDK Key: {config.sdk_key}')
for key, feature in config.features_map.items():
print(f'Flag: {key}')
for var_key, variable in feature.variables_map.items():
print(f' Variable: {var_key} = {variable.value}') Return type: OptimizelyConfig
Section titled “Return type: OptimizelyConfig”| Field | Type | Description |
|---|---|---|
revision | string | The datafile revision number. Increments with each publish in the Optimizely app. |
sdkKey | string | The SDK key used to initialize the client. |
environmentKey | string | The environment (e.g., "production", "development"). |
featuresMap | Map<string, FeatureConfig> | All feature flags with their variables and experiment rules. |
attributes | Attribute[] | All custom attributes defined in the project. |
events | Event[] | All events defined in the project. |
audiences | Audience[] | All audiences defined in the project. |
Shuts down the Optimizely client. Flushes any pending events, stops datafile polling, and releases resources. Call this when your application shuts down to avoid losing event data.
// Flush pending events and stop polling
await optimizely.close();
console.log('Optimizely client shut down'); // In a .NET 8+ application, call on shutdown
optimizely.Dispose();
Console.WriteLine("Optimizely client shut down"); # Flush pending events and stop polling
client.close()
print('Optimizely client shut down') In web server applications, register the close call with your application’s shutdown hook:
var builder = WebApplication.CreateBuilder(args);
// Register Optimizely as a singleton
var optimizely = OptimizelyFactory.NewDefaultInstance("YOUR_SDK_KEY");
builder.Services.AddSingleton(optimizely);
var app = builder.Build();
// Clean up on shutdown
app.Lifetime.ApplicationStopping.Register(() =>
{
optimizely.Dispose();
});
app.Run(); Notification listeners
Section titled “Notification listeners”Register callbacks that fire when the SDK makes decisions, dispatches events, or updates the datafile.
import { NOTIFICATION_TYPES } from '@optimizely/optimizely-sdk';
// Listen for decision events
const listenerId = optimizely.notificationCenter.addNotificationListener(
NOTIFICATION_TYPES.DECISION,
(notification) => {
console.log('Decision made:', {
type: notification.type,
userId: notification.userId,
flagKey: notification.decisionInfo.flagKey,
enabled: notification.decisionInfo.enabled,
});
}
);
// Listen for datafile updates
optimizely.notificationCenter.addNotificationListener(
NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE,
() => {
console.log('Datafile updated — new config is active');
}
);
// Remove a specific listener
optimizely.notificationCenter.removeNotificationListener(listenerId);
// Remove all listeners
optimizely.notificationCenter.clearAllNotificationListeners(); // Listen for decision events
optimizely.NotificationCenter.AddNotification(
NotificationCenter.NotificationType.Decision,
(notification) =>
{
Console.WriteLine($"Decision: {notification.Type}");
});
// Listen for datafile updates
optimizely.NotificationCenter.AddNotification(
NotificationCenter.NotificationType.OptimizelyConfigUpdate,
() =>
{
Console.WriteLine("Datafile updated");
}); from optimizely.notification_center import NotificationCenter
def on_decision(notification_type, args):
print(f'Decision made: {args}')
client.notification_center.add_notification_listener(
NotificationCenter.NOTIFICATION_TYPES.DECISION,
on_decision
)
def on_config_update():
print('Datafile updated')
client.notification_center.add_notification_listener(
NotificationCenter.NOTIFICATION_TYPES.OPTIMIZELY_CONFIG_UPDATE,
on_config_update
) Notification types
Section titled “Notification types”| Type | When it fires | Payload |
|---|---|---|
DECISION | After every decide call | Decision type, user ID, flag key, enabled state, variation key |
LOG_EVENT | When the SDK dispatches an event batch | The event payload being sent to Optimizely |
OPTIMIZELY_CONFIG_UPDATE | When the SDK detects a new datafile revision | No payload — call getOptimizelyConfig to inspect the new config |
TRACK | After every trackEvent call | Event key, user ID, event tags |
Thread safety
Section titled “Thread safety”The Optimizely client is thread-safe. You can share a single instance across threads, goroutines, or async contexts. User context objects are not thread-safe — create a new user context per request or thread.