Initialization
The Eppo JavaScript SDK is easy to initialize while offering robust customization options, making it adaptable to various use cases such as offline mode, custom caching requirements, and ultra-low-latency initialization.
Initialize the SDK
To complete basic initialization, you only need to provide an SDK key which you can created in the Eppo UI under Configuration > Environments > API Keys.
import { init } from "@eppo/js-client-sdk";
await init({
apiKey: 'YOUR_SDK_KEY',
});
Use the SDK instance
After initialization, you can use the SDK instance by importing the SDK at the scope you will use it in and calling getInstance()
. You can then use the SDK instance to assign a variation to a subject using the get*Assignment
functions.
import * as EppoSdk from "@eppo/js-client-sdk";
const eppoClient = EppoSdk.getInstance();
const user = getCurrentUser();
Advanced Configuration
Basic initialization is great for most use cases, but the SDK provides options that you can use during initialization to customize the behavior of the SDK.
Initialization Options
How the SDK fetches, serves, and caches experiment configurations is configurable via additional optional initialization options:
requestTimeoutMs
numberDefault: 5000
Timeout in milliseconds for HTTPS requests for the experiment configurations.
numInitialRequestRetries
numberDefault: 1
Number of additional times the initial configurations request will be attempted if it fails.
This is the request typically synchronously waited (via await
) for completion.
A small wait will be done between requests.
pollAfterSuccessfulInitialization
booleanDefault: false
Poll for new configurations (every 30 seconds) after successfully requesting the initial configurations.
pollAfterFailedInitialization
booleanDefault: false
Poll for new configurations even if the initial configurations request failed.
throwOnFailedInitialization
booleanDefault: true
Throw an error (reject the promise) if unable to fetch initial configurations during initialization.
numPollRequestRetries
numberDefault: 7
If polling for updated configurations after initialization, the number of additional times a request will be attempted before giving up. Subsequent attempts are done using an exponential backoff.
skipInitialRequest
booleanDefault: false
Skip the initial request for a new configuration during initialization (if polling is enabled, this will still take place later)
persistentStore
IAsyncStoreDefault: Eppo provided
An asynchronous, persistent storage for caching fetched flag configurations for use in subsequent sessions
maxCacheAgeSeconds
numberDefault: 0
Maximum age, in seconds, that a previously cached configuration is considered valid and the wait-time before fetching a fresh configuration
useExpiredCache
booleanDefault: false
Consider initialization successfully complete without fetching updates, even if the configuration loaded from the cache is expired
updateOnFetch
'always' | 'expired' | 'empty'Default: 'always'
Sets how the configuration is updated after a successful fetch:
- always - immediately start using the new configuration
- expired - immediately start using the new configuration only if the current one has expired
- empty - only use the new configuration if the current one is both expired and uninitialized/empty
Configuration caching
The SDK can cache previously loaded configurations for use in future sessions. This makes the SDK initialize faster.
By default, a Local Storage-based cache is used in a browser environment and a Chrome Storage-based cache is used in a Chrome extension environment.
A custom cache can be provided as the persistentStore
initialization option.
Why cache configurations?
Caching experiment configurations locally improves your application by making it faster and giving it a fallback value when network requests fail.
How configuration Caching Works
The SDK automatically caches configurations using:
- Local Storage in browser environments
- Chrome Storage in extension environments
You can also implement your own custom cache by providing a persistentStore
:
import { init } from "@eppo/js-client-sdk";
await init({
apiKey: 'YOUR_SDK_KEY',
persistentStore: myCustomStore
});
Expiration
Caching settings depend on the concept of expiration. Expiration is controlled by the maxCacheAgeSeconds
initialization option. This setting is overridable by the implementation of isExpired()
for a custom persistent store.
When the cached configuration is not expired, it is considered valid and no fetches will be made for updated configurations.
Example configuration options
There are a few common configurations that you might want to use depending on what type of performance and consistency characteristics you want for your application.
Prioritize flag value freshness
If you want to always using the latest flag values, you'd want settings that:
- Consider anything cached expired
- Do not use expired cached configurations
- Immediately start using the new configuration after it is fetched
- Do not retry a failed initialization fetch
Use the following configuration to achieve this:
import { init } from "@eppo/js-client-sdk";
await init({
apiKey: 'YOUR_API_KEY',
maxCacheAgeSeconds: 0, // Always consider cached configurations expired
useExpiredCache: false, // Wait for an updated configuration to be fetched before initialization is considered successful
updateOnFetch: 'always', // Immediately start using the new configuration after it is fetched
requestTimeoutMs: 5000, // Don't time out the initial configuration request until five seconds have passed
numInitialRequestRetries: 1, // If the initial configuration request fails, try one more time
pollAfterSuccessfulInitialization: true, // Check for updated configurations every 30 seconds
pollAfterFailedInitialization: false, // Check for updated configurations even if initialization wasn't able to load one
});
This configuration ensures the SDK will use the lastest assignment values immediately but may be slower to initialize than other approaches.
Prioritize fast initialization
If you want to optimize for the quickest time to initialization and serving assignments--even if those assignments may be out of date, you would want settings that:
- Immediately start using the new configuration after it is fetched
- Allow initializing with older configurations
- Reduce the initial fetch timeout and retries to quickly fall back to default values
Use the following configuration to achieve those goals:
import { init } from "@eppo/js-client-sdk";
await init({
apiKey: 'YOUR_API_KEY',
updateOnFetch: 'always', // Immediately start using the new configuration once it is fetched
maxCacheAgeSeconds: 300, // Don't even bother fetching updated configurations unless the last one is more than five minutes old
useExpiredCache: true, // If the cached configuration is expired, use it to serve assignments until an updated one is fetched
requestTimeoutMs: 500, // Give up on fetching updated configurations after half a second and--if this is the first-ever initialization--just serve default values
numInitialRequestRetries: 0, // Don't retry a failed initialization fetch
});
Note that when new configurations are loaded, the same flag may start getting a different assignment for the same session. If you want to avoid this, and have consistent assignments until the next initialization, change updateOnFetch
to empty
.
You could consider caches always expired so that it non-blocking loads an updated configuration to be used in the next session.
import { init } from "@eppo/js-client-sdk";
await init({
apiKey: 'YOUR_API_KEY',
maxCacheAgeSeconds: 0, // Always consider cached configurations expired
// Settings set to non-default values
updateOnFetch: 'empty', // Immediately start using the new configuration once it is fetched
useExpiredCache: true, // Always used the previously cached assignments
requestTimeoutMs: 500, // Give up on fetching updated configurations after half a second and--if this is the first-ever initialization--just serve default values
numInitialRequestRetries: 0, // Don't retry a failed initialization fetch
});
Offline initialization
Eppo's SDK supports offline initialization. This is useful if you want to initialize the SDK with a configuration from your server SDK or other external process. In this mode the SDK will not attempt to fetch a configuration from Eppo's CDN, instead only using the provided values.
This function is synchronous and ready to handle assignments after it returns.
import { offlineInit, Flag, ObfuscatedFlag } from "@eppo/js-client-sdk";
// configuration from your server SDK
const configurationJsonString: string = getConfigurationFromServer();
// The configuration will be not-obfuscated from your server SDK.
// If you have obfuscated flag values, you can use the `ObfuscatedFlag` type.
const flagsConfiguration: Record<string, Flag | ObfuscatedFlag> = JSON.parse(configurationJsonString);
offlineInit({
flagsConfiguration,
// If you have obfuscated flag values, you can use the `ObfuscatedFlag` type.
isObfuscated: true,
});
The offlineInit
function accepts the following optional configuration arguments.
Offline Initialization Options
A callback that sends each assignment to your data warehouse. Required only for experiment analysis.
flagsConfiguration
Record <string, Flag | ObfuscatedFlag>Default: null
The flags configuration to use for the SDK.
isObfuscated
booleanDefault: false
Whether the flag values are obfuscated.
throwOnFailedInitialization
booleanDefault: true
Throw an error if an error occurs during initialization.