Javascript
Introduction
The Javascript browser SDK is intended to be used by web applications running on modern web browsers. All modern web browsers on popular platforms should be supported.
Browser SDKs are tested on the latest versions of Chrome, Firefox, Safari, and Edge.
Telemetry collection within browser SDKs uses Web Workers to aggregate and send telemetry data. If the SDK runs on older browsers without Web Workers support, config evaluation will continue to work but no telemetry data will be collected for that session.
Installation
The SDK can be installed from NPM: https://www.npmjs.com/package/@configdirector/client-sdk
npm install --save @configdirector/client-sdk
yarn add @configdirector/client-sdk
pnpm add @configdirector/client-sdk
bun add @configdirector/client-sdk
Configure and initialize the client
- Create an instance of the client providing your client SDK key. You can retrieve a client SDK key under your project settings in the
Environments & SDK Keystab. - Initialize the client to initiate its connection lifecycle.
import { createClient } from "@configdirector/client-sdk";
export const client = createClient("YOUR-CLIENT-SDK-KEY");
await client.initialize();
Additional configuration options
metadata
The metadata option allows you to provide your application's name and version. These values can be used in targeting rules conditionals. For example, if a certain feature should only be enabled starting with a certain version of your application.
import { createClient } from "@configdirector/client-sdk";
export const client = createClient("YOUR-CLIENT-SDK-KEY", {
metadata: {
appName: "YOUR-APP-NAME",
appVersion: "1.0.2",
},
});
await client.initialize();
logger
By default, the SDK logs to the console and it is set to log warnings and errors only. You can configure a logger by either creating a ConfigDirector console logger with a different log level, or by implementing the ConfigDirectorLogger interface to provide your own logger. The interface can be used to create an adapter to another logging library.
Configure the ConfigDirector console logger to a different level:
import { createClient, createConsoleLogger } from "@configdirector/client-sdk";
export const client = createClient("YOUR-CLIENT-SDK-KEY", {
logger: createConsoleLogger("debug"),
});
await client.initialize();
Implement your own logger adapter:
import { createClient, ConfigDirectorLogger } from "@configdirector/client-sdk";
const myLogger: ConfigDirectorLogger = {
debug: function (message: string, ...args: any): void {
// your specific logging library implementation here
},
info: function (message: string, ...args: any): void {
// your specific logging library implementation here
},
warn: function (message: string, ...args: any): void {
// your specific logging library implementation here
},
error: function (message: string, ...args: any): void {
// your specific logging library implementation here
},
};
export const client = createClient("YOUR-CLIENT-SDK-KEY", {
logger: myLogger,
});
await client.initialize();
connection
The connection object accepts three optional values:
mode- The connection mode, which can be either
streamingorpolling. It is recommended to use the default ofstreamingunless you have a specific need to usepollinginstead. - Defaults to
streaming
- The connection mode, which can be either
timeout- The timeout, in milliseconds, to be used in initialization and when updating the context. This is how long the
initializemethod will wait for data from ConfigDirector services before resolving its Promise. If the timeout is reached,initializewill return but the client will still be in an unready status and returning default values. The client will continue to attempt to connect and retrieve config values in the background. - If your application is used in environments where the users frequently have poor or no connection, you may want to use a lower timeout, or simply don't await the
initializemethod call - Defaults to
3000milliseconds
- The timeout, in milliseconds, to be used in initialization and when updating the context. This is how long the
url- The base URL used to connect to ConfigDirector services
- This should only be provided if your environment requires you to configure a proxy server in order to connect to ConfigDirector services
import { createClient } from "@configdirector/client-sdk";
export const client = createClient("YOUR-CLIENT-SDK-KEY", {
connection: {
mode: "streaming",
timeout: 2_000, // 2,000 milliseconds initialization timeout
},
});
await client.initialize();
Retrieve config values
To synchronously retrieve config values, use the client's getValue method. It requires two arguments. The first argument is the config key, and the second is the default value to be returned if the client has not yet received config values from ConfigDirector services.
You can also subscribe to config value changes via the watch method. It requires three arguments, the config key, the default value, and a callback function to be called when the config value is updated. The watch method itself returns a function to remove that specific listener. Alternatively, you may also call the unwatch method to remove all listeners for a specific config key.
import { client } from "./config-director-setup"
// Retrieve the current value
const value = client.getValue("my-config-key", false);
// Subscribe to value updates
const unwatchMyKey = client.watch(
"my-config-key",
false,
(newValue) => {
console.log("Value updated:", newValue)
},
);
unwatchMyKey(); // Call the unwatch function returned to remove the listener
client.unwatch("my-config-key"); // Removes all listeners for that key
Both, getValue and watch accept default values for any type supported by that specific config (boolean, string, number, enums). If there is a type mismatch at runtime, the SDK will attempt to cast to the return value. If the cast fails, it will return the value as a string. Mismatched types at runtime are captured by the telemetry collector and will surface as warnings in the ConfigDirector dashboard.
client.getValue("my-string-config-key", "Default");
client.getValue("my-integer-config-key", 100);
client.getValue("my-boolean-config-key", false);
client.getValue<MyEnum>("my-enum-config-key", MyEnum.SomeDefaultValue);
Update the user context
A user context can be provided when initializing the client:
import { createClient } from "@configdirector/client-sdk";
export const client = createClient("YOUR-CLIENT-SDK-KEY");
await client.initialize({
id: "12345",
name: "Example User",
traits: {
region: "North America", // Any arbitrary traits which can be referenced in targeting rules
}
});
The user context can also be updated via updateContext:
import { client } from "./config-director-setup"
await client.updateContext({
id: "654321",
name: "Another User",
traits: {
region: "Australia",
},
});
// Update it to `undefined` (anonymous user context) when a user signs out
await client.updateContext();
Awaiting
updateContext will wait until the new config values are downloaded or the connection times out. In the case of a timeout, the client will continue to attempt to connect with the new context in the background.Other useful client features
The client provides additional properties and methods.
context
Returns the current user context (which may be undefined). When calling updateContext, the context is not immediately updated. The context is updated after the new connection for the new context succeeds (or times out and goes on retry).
isReady
Returns a boolean indicating if the client has been successfully initialized and is ready to evaluate configs for the given user context. It is initially false and becomes true after initialize succeeds.
Upon calling updateContext it becomes false again and it is set to true once updateContext succeeds.
unwatchAll
Removes all listeners for all config keys that were previously created via watch.
dispose
Removes all listeners and observers, and closes all connections to ConfigDirector services. Only call dispose when your application shuts down and it will no longer make use of the client instance.
It is generally not needed for applications to call dispose explicitly.