Experiment JavaScript SDK

Official documentation for Amplitude Experiment's Client-side JavaScript SDK implementation.

Install

Install the Experiment JavaScript Client SDK with one of the three following methods:

1npm install --save @amplitude/experiment-js-client

1yarn add @amplitude/experiment-js-client

1<script src="https://unpkg.com/@amplitude/experiment-js-client@1.9.0/dist/experiment.umd.js"></script>
2<script>
3 // TODO: Replace DEPLOYMENT_KEY with your own deployment key.
4 // If you're using a 3rd party for analytics, configure an exposure
5 // tracking provider.
6 window.experiment = Experiment.Experiment.initializeWithAmplitudeAnalytics(
7 'DEPLOYMENT_KEY'
8 );
9</script>

Quick start

The right way to initialize the Experiment SDK depends on whether you use an Amplitude SDK for analytics or a third party (for example, Segment).

  1. Initialize the experiment client
  2. Fetch variants
  3. Access a flag's variant
1import { Experiment } from '@amplitude/experiment-js-client';
2 
3// (1) Initialize the experiment client with Amplitude Analytics.
4const experiment = Experiment.initializeWithAmplitudeAnalytics(
5 'DEPLOYMENT_KEY'
6);
7 
8// (2) Fetch variants and await the promise result.
9await experiment.fetch();
10 
11// (3) Lookup a flag's variant.
12const variant = experiment.variant('FLAG_KEY');
13if (variant.value === 'on') {
14 // Flag is on
15} else {
16 // Flag is off
17}

  1. Initialize the experiment client
  2. Fetch variants for a user
  3. Access a flag's variant
1import { Experiment } from '@amplitude/experiment-js-client';
2 
3// (1) Initialize the experiment client and implement a
4// custom exposure tracking provider.
5const experiment = Experiment.initialize(
6 'DEPLOYMENT_KEY',
7 {
8 exposureTrackingProvider: {
9 track: (exposure) => {
10 // TODO: Implement exposure tracking
11 // analytics.track('$exposure', exposure)
12 }
13 }
14 }
15);
16 
17// (2) Fetch variants with the user and await the promise result.
18const user = {
19 user_id: 'user@company.com',
20 device_id: 'abcdefg',
21 user_properties: {
22 premium: true,
23 },
24}
25await experiment.fetch(user);
26 
27// (3) Lookup a flag's variant.
28const variant = experiment.variant('FLAG_KEY');
29if (variant.value === 'on') {
30 // Flag is on
31} else {
32 // Flag is off
33}

Initialize

Initialize the SDK in your application on startup. The deployment key argument you pass into the apiKey parameter must live in the same Amplitude project to which you send events.

1initializeWithAmplitudeAnalytics(apiKey: string, config?: ExperimentConfig): ExperimentClient

1initialize(apiKey: string, config?: ExperimentConfig): ExperimentClient

Paramater Description
apikey Required. The deployment key which authorizes fetch requests and determines which flags to evaluate for the user
config The client configuration to customize SDK client behavior.

The initializer returens a singleton instance, so subsequent initializations for the same instance name always return the initial instance. To create multiple instances, use the instanceName configuration.

1import { Experiment } from '@amplitude/experiment-js-client';
2 
3const experiment = initializeWithAmplitudeAnalytics('DEPLOYMENT_KEY');

1import { Experiment } from '@amplitude/experiment-js-client';
2 
3const experiment = Experiment.initialize(
4 'DEPLOYMENT_KEY',
5 {
6 exposureTrackingProvider: {
7 track: (exposure) => {
8 // TODO: Implement exposure tracking
9 // analytics.track('$exposure', exposure)
10 }
11 }
12 }
13);

Configuration

Configure the SDK client once during initialization.

Configuration

Name Description Default Value
debug Enable additional debug logging within the SDK. Should be set to false in production builds. false
fallbackVariant The default variant to fall back if a variant for the provided key doesn't exist. {}
initialVariants An initial set of variants to access. This field is valuable for bootstrapping the client SDK with values rendered by the server using server-side rendering (SSR). {}
source The primary source of variants. Set the value to Source.InitialVariants and configured initialVariants to bootstrap the SDK for SSR or testing purposes. Source.LocalStorage
serverZone Select the Amplitude data center to get flags and variants from, us or eu. us
serverUrl The host to fetch remote evaluation variants from. For hitting the EU data center, use serverZone. https://api.lab.amplitude.com
flagsServerUrl The host to fetch local evaluation flags from. For hitting the EU data center, use serverZone. https://flag.lab.amplitude.com
fetchTimeoutMillis The timeout for fetching variants in milliseconds. 10000
retryFetchOnFailure Whether to retry variant fetches in the background if the request doesn't succeed. true
automaticExposureTracking If true, calling variant() will track an exposure event through the configured exposureTrackingProvider. If no exposure tracking provider is set, this configuration option does nothing. true
fetchOnStart If true or undefined, always fetch remote evaluation variants on start. If false, never fetch on start. true
pollOnStart Poll for local evaluation flag configuration updates once per minute on start. true
automaticFetchOnAmplitudeIdentityChange Only matters if you use the initializeWithAmplitudeAnalytics initialization function to seamlessly integrate with the Amplitude Analytics SDK. If true any change to the user ID, device ID or user properties from analytics will trigger the experiment SDK to fetch variants and update it's cache. false
userProvider An interface used to provide the user object to fetch() when called. null
exposureTrackingProvider Implement and configure this interface to track exposure events through the experiment SDK, either automatically or explicitly. null
instanceName Custom instance name for experiment SDK instance. The value of this field is case-sensitive. null
initialFlags A JSON string representing an initial set of flag configurations to use for local evaluation. undefined

Integrations

If you use either Amplitude or Segment Analytics SDKs to track events into Amplitude, set up an integration on initialization. Integrations automatically implement provider interfaces to enable a more streamlined developer experience by making it easier to manage user identity and track exposures events.

Amplitude integration
The Amplitude Experiment SDK is set up to integrate seamlessly with the Amplitude Analytics SDK.

1import * as amplitude from '@amplitude/analytics-browser';
2import { Experiment } from '@amplitude/experiment-js-client';
3 
4amplitude.init('API_KEY');
5const experiment = Experiment.initializeWithAmplitudeAnalytics('DEPLOYMENT_KEY');

Using the integration initializer configures implementations of the user provider and exposure tracking provider interfaces to pull user data from the Amplitude Analytics SDK and track exposure events.

Supported Versions

All versions of the next-generation Amplitude analytics Browser SDK support this integration.

Legacy Analytics SDK Version Experiment SDK Version
8.18.1+ 1.4.1+

Segment integration
Experiment's integration with Segment Analytics requires manual configuration. Then, configure the Experiment SDK on initialization with an instance of the exposure tracking provider. Make sure this happens after the analytics SDK loads an initializes.

1analytics.ready(() => {
2 const experiment = Experiment.initialize('DEPLOYMENT_KEY', {
3 exposureTrackingProvider: {
4 track: (exposure) => {
5 analytics.track('$exposure', exposure)
6 }
7 }
8 });
9});

When fetching variants, pass the segment anonymous ID and user ID for the device ID and user ID, respectively.

1await experiment.fetch({
2 user_id: analytics.user().id(),
3 device_id: analytics.user().analyticsId(),
4});

mParticle integration
Experiment's integration with mParticle requires manual integration. The values you use for user_id and device_id depend on your specific configuration.

In accordance with your event forwarding settings to Amplitude, the event type Other may not be the right classification. Make sure that the event type you use is forwarded to Amplitude in destination settings.

1const identityRequest = {
2 userIdentities: {
3 email: "joe_slow@gmail.com",
4 customerid: "abcdxyz"
5 }
6};
7mParticle.Identity.login(identityRequest, () => {
8 console.log("Identity callback");
9});
10 
11const experiment = Experiment.initialize("DEPLOYMENT_KEY", {
12 exposureTrackingProvider: {
13 track: (exposure) => {
14 window.mParticle.logEvent('$exposure', window.mParticle.EventType.Other, exposure);
15 }
16 },
17 userProvider: {
18 getUser: () => {
19 const user_id = window.mParticle.Identity.getCurrentUser().getUserIdentities().userIdentities.customerid;
20 const device_id = window.mParticle.getDeviceId();
21 if (user_id != null) {
22 return {
23 user_id: user_id,
24 device_id: device_id
25 };
26 else
27 return {
28 device_id: device_id
29 };
30 }
31 }
32 }
33});

Fetch

Fetches variants for a user and store the results in the client for fast access. This function remote evaluates the user for flags associated with the deployment used to initialize the SDK client.

Fetch on user identity change

If you want the most up-to-date variants for the user, it's recommended that you call fetch() whenever the user state changes in a meaningful way. For example, if the user logs in and receives a user ID, or has a user property set which may effect flag or experiment targeting rules.

Pass new user properties explicitly to fetch() instead of relying on user enrichment prior to remote evaluation. This is because user properties that are synced remotely through a separate system have no timing guarantees with respect to fetch()--for example, a race.

1fetch(user?: ExperimentUser, options?: FetchOptions): Promise<Client>
Parameter Requirement Description
user optional Explicit user information to pass with the request to evaluate. This user information is merged with user information provided from integrations via the user provider, preferring properties passed explicitly to fetch() over provided properties.
options optional Explicit flag keys to fetch.

Account-level bucketing and analysis (v1.5.6+)
If your organization has purchased the Accounts add-on you may perform bucketing and analysis on groups rather than users. Reach out to your representative to gain access to this beta feature.

Groups must either be included in the user sent with the fetch request (recommended), or identified with the user via a group identify call from the Group Identify API or via setGroup() from an analytics SDK.

1await fetch({groups: {'org name': ['Amplitude']}});

1const user = {
2 user_id: 'user@company.com',
3 device_id: 'abcdefg',
4 user_properties: {
5 'premium': true,
6 },
7};
8await experiment.fetch(user);

If you're using an integration or a custom user provider then you can fetch without inputting the user.

1await experiment.fetch();

If fetch() times out (default 10 seconds) or fails for any reason, the SDK client will return and retry in the background with back-off. You may configure the timeout or disable retries in the configuration options when the SDK client is initialized.

Start

Fetch vs start

Use start if you're using client-side local evaluation. If you're only using remote evaluation, call fetch instead of start.

Start the SDK by getting flag configurations from the server and fetching remote evaluation variants for the user. The SDK is ready once the returned promise resolves.

1start(user?: ExperimentUser): Promise<void>
Parameter Requirement Description
user optional Explicit user information to pass with the request to fetch variants. This user information is merged with user information provided from integrations via the user provider, preferring properties passed explicitly to fetch() over provided properties. Also sets the user in the SDK for reuse.

Call start() when your application is initializing, after user information is available to use to evaluate or fetch variants. The returned promise resolves after loading local evaluation flag configurations and fetching remote evaluation variants.

Configure the behavior of start() by setting fetchOnStart in the SDK configuration on initialization to improve performance based on the needs of your application.

  • If your application never relies on remote evaluation, set fetchOnStart to false to avoid increased startup latency caused by remote evaluation.
  • If your application relies on remote evaluation, but not right at startup, you may set fetchOnStart to false and call fetch() and await the promise separately.

1await experiment.start();

1const user = {
2 user_id: 'user@company.com',
3 device_id: 'abcdefg',
4 user_properties: {
5 premium: true
6 }
7};
8await experiment.start(user);

Variant

Access a variant for a flag or experiment from the SDK client's local store.

Automatic exposure tracking

When an integration is used or a custom exposure tracking provider is set, variant() will automatically track an exposure event through the tracking provider. To disable this functionality, configure automaticExposureTracking to be false, and track exposures manually using exposure().

1variant(key: string, fallback?: string | Variant): Variant
Parameter Requirement Description
key required The flag key to identify the flag or experiment to access the variant for.
fallback optional The value to return if no variant was found for the given flagKey.

When determining which variant a user has been bucketed into, you'll want to compare the variant value to a well-known string.

1const variant = experiment.variant('<FLAG_KEY>');
2if (variant.value === 'on') {
3 // Flag is on
4} else {
5 // Flag is off
6}

Access a variant's payload

A variant may also be configured with a dynamic payload of arbitrary data. Access the payload field from the variant object after checking the variant's value.

1const variant = experiment.variant('<FLAG_KEY>');
2if (variant.value === 'on') {
3 const payload = variant.payload;
4}

A null variant value means that the user hasn't been bucketed into a variant. You may use the built in fallback parameter to provide a variant to return if the store doesn't contain a variant for the given flag key.

1const variant = experiment.variant('<FLAG_KEY>', { value: 'control' });
2if (variant === 'control') {
3 // Control
4} else if (variant === 'treatment') {
5 // Treatment
6}

All

Access all variants stored by the SDK client.

1all(): Variants

Clear

Clear all variants in the cache and storage.

1clear(): void

You can call clear after user logout to clear the variants in cache and storage.

1experiment.clear();

Exposure

Manually track an exposure event for the current variant of the given flag key through configured integration or custom exposure tracking provider. Generally used in conjunction with setting the automaticExposureTracking configuration optional to false.

1exposure(key: string): void
Parameter Requirement Description
key required The flag key to identify the flag or experiment variant to track an exposure event for.
1const variant = experiment.variant('<FLAG_KEY>');
2 
3// Do other things...
4 
5experiment.exposure('<FLAG_KEY>');
6if (variant === 'control') {
7 // Control
8} else if (variant === 'treatment') {
9 // Treatment
10}

Providers

Integrations

If you use Amplitude or Segment analytics SDKs along side the Experiment Client SDK, Amplitude recommends you use an integration instead of implementing custom providers.

Provider implementations enable a more streamlined developer experience by making it easier to manage user identity and track exposures events.

User provider

The user provider is used by the SDK client to access the most up-to-date user information only when it's needed (for example, when fetch() is called). This provider is optional, but helps if you have a user information store already set up in your application. This way, you don't need to manage two separate user info stores in parallel, which may result in a divergent user state if the application user store is updated and experiment isn't (or via versa).

1interface ExperimentUserProvider {
2 getUser(): ExperimentUser;
3}

To use your custom user provider, set the userProvider configuration option with an instance of your custom implementation on SDK initialization.

1const experiment = Experiment.initialize('<DEPLOYMENT_KEY>', {
2 userProvider: new CustomUserProvider(),
3});

Exposure tracking provider

Implementing an exposure tracking provider is highly recommended. Exposure tracking increases the accuracy and reliability of experiment results and improves visibility into which flags and experiments a user is exposed to.

1export interface ExposureTrackingProvider {
2 track(exposure: Exposure): void;
3}

The implementation of track() should track an event of type $exposure (a.k.a name) with two event properties, flag_key and variant, corresponding to the two fields on the Exposure object argument. Finally, the event tracked must eventually end up in Amplitude Analytics for the same project that the [deployment] used to initialize the SDK client lives within, and for the same user that variants were fetched for.

To use your custom user provider, set the exposureTrackingProvider configuration option with an instance of your custom implementation on SDK initialization.

1const experiment = Experiment.initialize('<DEPLOYMENT_KEY>', {
2 exposureTrackingProvider: new CustomExposureTrackingProvider(),
3});

Bootstrapping

You may want to bootstrap the experiment client with an initial set of flags and variants when variants are obtained from an external source (for example, not from calling fetch() on the SDK client). Use cases include local evaluation, server-side rendering, or integration testing on specific variants.

To bootstrap the client, set the flags and variants in the initialVariants configuration object, then set the source to Source.InitialVariants so that the SDK client prefers the bootstrapped variants over any previously fetched & stored variants for the same flags.

1const experiment = Experiment.initialize('<DEPLOYMENT_KEY>', {
2 initialVariants: { /* Flags and variants */ },
3 source: Source.InitialVariants,
4});
Was this page helpful?

Thanks for your feedback!

June 4th, 2024

Need help? Contact Support

Visit Amplitude.com

Have a look at the Amplitude Blog

Learn more at Amplitude Academy

© 2024 Amplitude, Inc. All rights reserved. Amplitude is a registered trademark of Amplitude, Inc.