On this page

Client Persistent Assignment

Configure persistent assignment in Statsig client SDKs so users stay in the same experiment group across sessions and devices for consistent experiences.

Persistent assignment ensures that a user's variant stays consistent while an experiment is running, regardless of changes to allocation or targeting.

Persistent Storage

Persistent storage uses an adapter approach, allowing you to plug in a storage solution of your choice to store assignments. The SDK references stored assignments later to ensure a user stays in the same bucket. You can implement an adapter that uses Local Storage, or one that uses remote storage, to enable persistence across multiple devices. The user persistent storage interface consists of a load/loadAsync, save, and delete API for read/write operations.

Persistent Storage is supported on:

Persistent Storage Logic

  • Providing a storage adapter on Statsig initialization gives the SDK access to read & write on your custom storage.
  • Providing user persisted values to get_experiment informs the SDK to
    • save the evaluation of the current user on first evaluation
    • load the previously saved evaluation of a persisted user on subsequent evaluations
    • delete the previously saved evaluation of a persisted user if the experiment is no longer active
  • Not providing user persisted values to get_experiment deletes a previously saved evaluation.

Example usage

typescript
import { StatsigClient } from '@statsig/js-client';
import { UserPersistentOverrideAdapter } from '@statsig/js-user-persisted-storage';

// Custom storage implementation using localStorage
class LocalStorageUserPersistedStorage {
  load(key) {
    return JSON.parse(localStorage.getItem(key) ?? '{}');
  }

  save(key, experiment, data) {
    const values = JSON.parse(localStorage.getItem(key) ?? '{}');
    values[experiment] = JSON.parse(data);
    localStorage.setItem(key, JSON.stringify(values));
  }

  delete(key, experiment) {
    const data = JSON.parse(localStorage.getItem(key) ?? '{}');
    delete data[experiment];
    localStorage.setItem(key, JSON.stringify(data));
  }
}

const storage = new LocalStorageUserPersistedStorage();
const adapter = new UserPersistentOverrideAdapter(storage);
const client = new StatsigClient('client-key', { overrideAdapter: adapter });

await client.initializeAsync({ userID: "123" });

const user = { userID: "123" };
const userPersistedValues = adapter.loadUserPersistedValues(user, 'userID');

const experiment = client.getExperiment('active_experiment', { userPersistedValues });
console.log(experiment.getGroupName()); // 'Control'

// Switch to different user - will maintain same experiment group due to persistence
const newUser = { userID: "456" };
const newExperiment = client.getExperiment('active_experiment', { userPersistedValues });
console.log(newExperiment.getGroupName()); // Still 'Control'

Support in iOS and Android SDKs

Android and iOS SDKs offer a simplified version of Persistent Storage called keepDeviceValues that relies on on-device storage. This option is less flexible but requires only a single boolean flag. When enabled, the SDK checks internally for a previously stored value in the getExperiment/getLayer call and uses that value instead, even if allocation or targeting has changed. When the experiment ends, the SDK stops persisting values.

Swift:

swift
// With an Experiment:
let titleExperiment = Statsig.getExperiment("new_user_promo_title", true) // <-- "true" flag sets keep device values
// Use the experiment like normal:
let promoTitle = titleExperiment.getValue(forKey: "title", defaultValue: "Welcome to Statsig!")

// Or a Layer:
let layer = Statsig.getLayer("user_promo_experiments", true) // <-- "true" flag sets keep device values
// Use the layer like normal:
let promoTitle = layer.getValue(forKey: "title", defaultValue: "Welcome to Statsig!")

Objective C:

objc
// With an Experiment:
DynamicConfig *expConfig = [Statsig getExperimentForName:@"new_user_promo_title" true]; // <-- "true" flag sets keep device values
// Use the experiment like normal:
NSString *promoTitle = [expConfig getStringForKey:@"title" defaultValue:@"Welcome to Statsig! Use discount code WELCOME10OFF for 10% off your first purchase!"];
double discount = [expConfig getDoubleForKey:@"discount" defaultValue:0.1];

double price = msrp * (1 - discount);

Was this helpful?