Initialize JavaScript (Node) SDK
This topic describes how to initialize the Optimizely Feature Experimentation JavaScript (Node) SDK in your application.
Use the createInstance
method to initialize the JavaScript (Node) SDK and instantiate an instance of the Optimizely client class that exposes API methods like the Decide methods. Each client corresponds to the datafile representing the state of a project for a certain environment.
Version
SDK v5.0.0-beta and higher
Description
The createInstance
method accepts a configuration object to configure Optimizely Feature Experimentation.
Some parameters are optional because the SDK provides a default implementation, but you may want to override these for your production environments. For example, you may want override these to set up an error handler and logger to catch issues, an event dispatcher to manage network calls, and a User Profile Service to ensure sticky bucketing.
Parameters
The table below lists the required and optional properties of the config object:
Parameter | Type | Description |
---|---|---|
datafile optional | string | The JSON string representing the project. At least one of sdkKey or datafile must be provided. |
sdkKey optional | string | The key associated with an environment in the project. At least one of sdkKey or datafile must be provided. |
eventDispatcher optional | object | An event dispatcher to manage network calls. An object with a dispatchEvent method. |
logger optional | object | A logger implementation to log messages. An object with a log method. |
errorHandler optional | object | An error handler object to handle errors. An object with a handleError method |
userProfileService optional | object | A user profile service. An object with lookup and save methods. |
jsonSchemaValidator optional | object | To perform JSON schema validation on datafiles, import the validator from `'@optimizely/optimizely-sdk/dist/optimizely.json_schema_validator.min.js'', and pass it as this initialization option. Skipping JSON schema validation enhances performance during initialization. |
datafileOptions optional | object | Object with configuration for automatic datafile management. Can have autoUpdate (boolean), urlTemplate (string), and updateInterval (number) properties. |
access_token optional | string | (Server-side only) Optimizely Feature Experimentation SDKs can use an access token (in combination with an sdk key) to fetch the datafile from an authenticated endpoint. Find your datafile access token in the Optimizely app at Settings>Environments. Select your secure environment, and copy the Datafile access token. |
defaultDecideOptions optional | Array | Array of OptimizelyDecideOption enums. When the Optimizely client is constructed with this parameter, it sets default decide options which are applied to all the Decide calls made during the lifetime of the Optimizely client. Additionally, you can pass options to individual Decide methods (does not overrides defaults). For example code, see OptimizelyDecideOption. |
ODPManager optional | OptimizelySdkSettings | You must have the Optimizely Data Platform Advanced Audience Targeting integration enabled. |
Returns
Instantiates an instance of the Optimizely Feature Experimentation class.
Examples
In the JavaScript (Node) SDK, you can provide either a sdkKey
or datafile
or both.
- When initializing with just the SDK key, the SDK will poll for datafile changes in the background at regular intervals.
- When initializing with just the datafile, the SDK will NOT poll for datafile changes in the background.
- When initializing with both the SDK key and datafile, the SDK will use the given datafile and start polling for datafile changes in the background.
Instantiate using SDK Key
In the JavaScript (Node) SDK, you only need to pass the SDK key value to instantiate a client. Whenever the experiment configuration changes, the SDK handles the change for you.
Include sdkKey
as a string property in the options object you pass to the createInstance
method.
const optimizely = require('@optimizely/optimizely-sdk');
const optimizelyClientInstance = optimizely.createInstance({
sdkKey: '12345', // Provide the sdkKey of your desired environment here
});
When you provide the sdkKey
, the SDK instance downloads the datafile associated with that sdkKey
. When the download completes, the SDK instance updates itself to use the downloaded datafile. You can use the onReady
method to wait for the datafile to be downloaded before using the instance.
const optimizely = require('@optimizely/optimizely-sdk');
const optimizelyClientInstance = optimizely.createInstance({
sdkKey: '12345', // Provide the sdkKey of your desired environment here
});
optimizelyClientInstance.onReady().then(() => {
// optimizelyClientInstance is ready to use, with datafile downloaded from the
// Optimizely CDN
});
Instantiate using datafile
To instantiate using datafile, first you must get a copy of the datafile from our server. In the example below, we demonstrate fetching the datafile using the request-promise library.
// Minimal client
const optimizely = require("@optimizely/optimizely-sdk");
const rp = require("request-promise");
// replace <Your_SDK_Key>
const DATAFILE_URL =
"https://cdn.optimizely.com/datafiles/<Your_SDK_Key>.json";
const datafile = await rp({ uri: DATAFILE_URL, json: true });
console.log("Datafile:", datafile);
const optimizelyClient = optimizely.createInstance({
datafile
});
// Use optimizelyClient to run experiments
If you do not pass in an SDK key, the Optimizely Client will not automatically sync newer versions of the datafile. Any time you retrieve an updated datafile, just re-instantiate the same client.
For simple applications, all you need to provide to instantiate a client is a datafile specifying the project configuration for a given environment. For most advanced implementations, you'll want to customize the logger or error handler for your specific requirements.
Notes
Customize datafile management behavior
To customize datafile management behavior, provide a datafileOptions
object property inside the options
object passed to createInstance
. The table lists the supported customizable options.
Option | Type | Description |
---|---|---|
autoUpdate | boolean | When true, and sdkKey was provided in createInstance options, automatic updates are enabled on this instance. The default value is true . |
updateInterval | number | When automatic updates are enabled, this controls the update interval. The unit is milliseconds. The minimum allowed value is 1000 (1 second). The default value is 300000 milliseconds (5 minutes). |
urlTemplate | string | A format string used to build the URL from which the SDK will request datafiles. Instances of %s will be replaced with the sdkKey . When not provided, the SDK will request datafiles from the Optimizely CDN. |
The following example shows how to customize datafile management behavior:
const optimizely = require('@optimizely/optimizely-sdk');
const optimizelyClientInstance = optimizely.createInstance({
sdkKey: '12345',
datafileOptions: {
autoUpdate: true,
updateInterval: 600000, // 10 minutes in milliseconds
urlTemplate: 'http://localhost:5000/datafiles/%s.json',
},
});
onReady details
Use the onReady method to wait until the download is complete and the SDK is ready to use.
The onReady method returns a Promise representing the initialization process.
onReady accepts an optional timeout argument (defined in milliseconds) that controls the maximum duration that the returned Promise will remain in the pending state. If timeout is not provided, it defaults to 30 seconds.
const optimizely = require('@optimizely/optimizely-sdk');
let optimizelyClient = optimizely.createInstance({
sdkKey: '12345',
});
optimizelyClient.onReady().then(() => {
// optimizelyClientInstance is ready to use, with datafile downloaded from the Optimizely CDN
});
// Provide a timeout in milliseconds - promise will resolve if the datafile still is not available after the timeout
instance.onReady({ timeout: 5000 }).then(result => {
// Returned Promise is fulfilled with a result object
console.log(result.success); // true if the instance fetched a datafile and is now ready to use
console.log(result.reason); // If success is false, reason contains an error message
})
The Promise returned from the onReady method is fulfilled with a result object containing a boolean success property.
When the success
property is true
, the instance is ready to use with a valid datafile. When the success property is false
, there is also a reason
string property describing the failure. Failure can be caused by expiration of the timeout, network error, unsuccessful HTTP response, datafile validation error, or the instance'sclose
method being called.
Set a fallback datafile
If you provide a sdkKey and a static fallback datafile for initialization, the SDK uses the fallback datafile immediately if it is valid while simultaneously downloading the datafile associated with the sdkKey. After the download completes, if the downloaded datafile is valid and has a more recent revision than the fallback datafile, the SDK updates the instance to use the downloaded datafile.
const optimizely = require('@optimizely/optimizely-sdk');
const datafile = '{"version": "4", "rollouts": [], "typedAudiences": [], "anonymizeIP": false, "projectId": "12345", "variables": [], "featureFlags": [], "experiments": [], "audiences": [], "groups": [], "attributes": [], "botFiltering": false, "accountId": "12345", "events": [], "revision": "1"}';
const optimizelyClientInstance = optimizely.createInstance({
sdkKey: '<Your_SDK_Key>',
datafile,
});
// optimizelyClientInstance can be used immediately with the given datafile, but
// will download the latest datafile and update itself
Note
You must have the Advanced Audience Targeting integration between Optimizely Data Platform (ODP) and Optimizely Feature Experimentation enabled and set up before being able to use
OdpManager
.
OdpManager
OdpManager
contains the logic supporting Optimizely Data Platform (ODP)-related features in Optimizely Feature Experimentation, including audience segments and ODP events.
Note
Advanced Audience Targeting and
OdpManager
are currently beta. Contact your Customer Success Manager for more information or register now on Optimizely.com.
Initializing the JavaScript (Node) SDK w/ODP Disabled
const optimizelyInstance = optimizelySdk.createInstance({
sdkKey: '<YOUR_SDK_KEY>',
odpOptions: {
disabled: true,
},
});
Initializing the JavaScript (Node) SDK w/ODP + Custom Settings
const optimizelyInstance = optimizelySdk.createInstance({
sdkKey: '<YOUR_SDK_KEY>',
odpOptions: {
// disabled: false,
eventApiTimeout: 1000,
eventBatchSize: 1,
eventFlushInterval: 0,
eventQueueSize: 1,
// eventRequestHandler: new BrowserRequestHandler(),
// eventManager: new OdpEventManager(),
segmentsApiTimeout: 1000,
segmentsCacheSize: 10,
segmentsCacheTimeout: 1000,
// segmentsCache: new ICache<string, string[]>(),
// segmentsRequestHandler: new BrowserRequestHandler(),
// segmentManager: new OdpSegmentManager(),
},
});
Customize OdpManager
Using the parameters in odpOptions, you can customize the behavior of the ODP event and segment managers, even going as far as being able to replace them with your own implementations if desired.
Example odpOptions w/Custom Event Manager
odpOptions: {
// ...
eventManager: new OdpEventManager({
odpConfig, // new OdpConfig()
apiManager, // new OdpEventApiManager()
logger, // new LogHandler()
clientEngine: 'javascript-sdk',
clientVersion: '5.0.0',
batchSize: 10,
flushInterval: 2000,
}),
},
Customizing the OdpEventApiManager
export interface IOdpEventApiManager {
sendEvents(apiKey: string, apiHost: string, events: OdpEvent[]): Promise<boolean>;
}
Example odpOptions w/Custom Segments Manager
odpOptions: {
// ...
segmentManager: new OdpSegmentManager(
odpConfig, // new OdpConfig()
new BrowserLRUCache<string, string[]>({
maxSize: 2,
timeout: 4000,
}), // new ICache<string, string[]>()
segmentApiManager, // new IOdpSegmentApiManager()
),
},
Custom cache
You can provide a custom cache, which will be used to store the fetch_qualified_segments
results. To provide a custom cache, you should implement the following interface:
Segments Cache Interface
export interface ICache<K, V> {
lookup(key: K): V | null;
save({ key, value }: { key: K; value: V }): void;
reset(): void;
}
Custom Segments Cache Implementation example from LRUCache implementation
export class LRUCache<K, V> implements ICache<K, V> {
private _map: Map<K, CacheElement<V>> = new Map();
private _maxSize; // Defines maximum size of _map
private _timeout; // Milliseconds each entry has before it becomes stale
get map(): Map<K, CacheElement<V>> {
return this._map;
}
get maxSize(): number {
return this._maxSize;
}
get timeout(): number {
return this._timeout;
}
constructor({ maxSize, timeout }: LRUCacheConfig) {
const logger = getLogger();
logger.debug(`Provisioning cache with maxSize of ${maxSize}`);
logger.debug(`Provisioning cache with timeout of ${timeout}`);
this._maxSize = maxSize;
this._timeout = timeout;
}
public lookup(key: K): V | null {
if (this._maxSize <= 0) {
return null;
}
const element: CacheElement<V> | undefined = this._map.get(key);
if (!element) return null;
if (element.is_stale(this._timeout)) {
this._map.delete(key);
return null;
}
this._map.delete(key);
this._map.set(key, element);
return element.value;
}
public save({ key, value }: { key: K; value: V }): void {
if (this._maxSize <= 0) return;
const element: CacheElement<V> | undefined = this._map.get(key);
if (element) this._map.delete(key);
this._map.set(key, new CacheElement(value));
if (this._map.size > this._maxSize) {
const firstMapEntryKey = this._map.keys().next().value;
this._map.delete(firstMapEntryKey);
}
}
public reset(): void {
if (this._maxSize <= 0) return;
this._map.clear();
}
public peek(key: K): V | null {
if (this._maxSize <= 0) return null;
const element: CacheElement<V> | undefined = this._map.get(key);
return element?.value ?? null;
}
}
Use authenticated datafile in secure environment
Note
Authenticated datafiles are in beta. Contact your Customer Success Manager if you are interested in becoming an early user of authenticated datafiles as part of the beta secure environment feature.
You can fetch the Optimizely datafile from an authenticated endpoint using a server-side (only) Optimizely Feature Experimentation SDK. To use an authenticated datafile, download your environment's access token from the Optimizely app at Settings>Environments. Select your secure environment, and copy the Datafile access token. The example below shows how to initialize the Optimizely client using an access token and sdkKey, enabling the client to fetch the authenticated datafile and complete initialization.
const optimizely = require('@optimizely/optimizely-sdk');
// fetch the datafile from an authenticated endpoint
const optimizelyClientInstance = optimizely.createInstance({
sdkKey: '<YOUR_SDK_KEY>',
datafileOptions: {
datafileAccessToken: '<YOUR_DATAFILE_ACCESS_TOKEN>',
},
});
Source files
The source code files containing the implementation for the JavaScript SDK are in the javascript-sdk repository on GitHub.
Updated 15 days ago