Skip to main content
Persistent assignment allows you to ensure that a user’s variant stays consistent while an experiment is running, regardless of changes to allocation or targeting.

Persistent Storage Adapter

The persistent storage adapter allows you to plug in your own storage solution that Statsig SDK uses to persist user assignments. The storage interface consists of just a load and save API for read/write operations.
Currently only supported in Go, Ruby, Legacy Node, Node Core, Kotlin, .Net, Python Core

Persistent Storage Logic

  • Providing a storage adapter on Statsig initialization will give the SDK access to read & write on your custom storage
  • Providing user persisted values to get_experiment will inform the SDK to
    • save the evaluation of the current user on first evaluation
      • Will only save when experiment / layer is active
    • load the previously saved evaluation of a persisted user on subsequent evaluations
  • CAVEAT Persisted Value will be deleted when:
    • When you provided call getExperiment with user_persisted_values=None
    • or When experiment is not active

Persistent Assignment Options (Limited SDK Support)

  • Enforce Targeting: boolean, default: false
    • Whether or not to enforce targeting rules before assigning persisted values
  • Kotlin
val options = GetExperimentOptions(
  ...
  persistentAssignmentOptions = PersistentAssignmentOptions(
    enforceTargeting = true,
  )
)
```text
  </Tab>
  <Tab title="Node JS">
```ts
const options: GetExperimentOptions = {
  ...
  persistentAssignmentOptions: {
    enforceTargeting: true,
  }
}

```text
  </Tab>
</Tabs>

### Example usage

<Tabs>
  <Tab title="Ruby">
```ruby
Statsig.initialize(
  'secret-key',
  StatsigOptions.new(
    user_persistent_storage: DummyPersistentStorageAdapter.new
  )
)
persisted_user = StatsigUser.new({ 'userID' => 'test-123' })
exp = Statsig.get_experiment( # User gets saved to persisted storage
  persisted_user,
  'active_experiment',
  Statsig::GetExperimentOptions.new(
    user_persisted_values: Statsig.get_user_persisted_values(persisted_user, 'userID')
  )
)
puts exp.group_name # 'Control'
exp = Statsig.get_experiment( # User evaluates using values from persisted storage
  StatsigUser.new({'userID' => 'unknown'}),
  'active_experiment',
  Statsig::GetExperimentOptions.new(
    user_persisted_values: Statsig.get_user_persisted_values(persisted_user, 'userID')
  )
)
puts exp.group_name # 'Control'
```text

  </Tab>
  <Tab title="Python (Python Core)">
```python
from statsig_python_core import Statsig, StatsigUser, StatsigOptions, ExperimentEvaluationOptions, PersistentStorage

options = StatsigOptions(persistent_storage = MyPersistentStorage())
statsig = Statsig.initialize(options).wait
user = StatsigUser("a-user")
exp = statsig.get_experiment(StatsigUser("a-user"), ExperimentEvaluationOptions(user_persisted_values= PersistentStorage.get_user_persisted_value(user, "user_id")))
print(f"{exp.group_name}") # control
```text
  </Tab>
  <Tab title="Node Core">
```typescript
let persistedStorage =  new MyPersistentStorage() // See https://docs.statsig.com/server-core/node-core/#persistent-storage on how to implement it
let options = new StatsigOptions(persistentStorage = persistedStorage)
let statsig = new Statsig(secretKye, options)
let user = new StatsigUser("a-user")
let exp = statsig.getExperiment(user, ExperimentEvaluationOptions(userPersistentValues= persistedStorage.getUserPersistedValues(user, "user_id")))

```text
  </Tab>
  
  <Tab title="Kotlin">
```kotlin
runBlocking {
  Statsig.initialize(
    "secret-key",
    StatsigOptions(userPersistentStorage = MyPersistentStorageAdapter())
  )
}
val persistedUser = StatsigUser("test-123")
var exp = Statsig.getExperimentSync(
  persistedUser,
  "active_experiment",
  GetExperimentOptions(
    userPersistedValues = Statsig.getUserPersistedValues(persistedUser, "userID"),
  ),
)
println(exp.groupName) // "Control"
exp = Statsig.getExperimentSync(
  StatsigUser("unknown"),
  "active_experiment",
  GetExperimentOptions(
    userPersistedValues = Statsig.getUserPersistedValues(persistedUser, "userID"),
  ),
)
println(exp.groupName) // "Control"
```text
  </Tab>
  <Tab title="Node JS">
```ts
await Statsig.initialize(
  "secret-key",
  {
    userPersistentStorage: new MyPersistentStorageAdapter() 
  }
)
const persistedUser: StatsigUser = { userID: "123" }
let exp = Statsig.getExperimentSync(
  persistedUser,
  "active_experiment",
  { 
    userPersistedValues: Statsig.getUserPersistedValues(user, "userID")
  },
)
console.log(exp.getGroupName()) // "Control"
exp = Statsig.getExperimentSync(
  { userID: "unknown" },
  "active_experiment",
  { 
    userPersistedValues: Statsig.getUserPersistedValues(user, "userID")
  },
)
console.log(exp.getGroupName()) // "Control"
```text
  </Tab>
  <Tab title="Go">
```go
InitializeWithOptions(
  "secret-key",
  &Options{
    UserPersistentStorage: persistentStorage,
  }
)
persistedUser := User{UserID: "123"}
exp := GetExperimentWithOptions(
  persistedUser,
  "active_experiment",
  &GetExperimentOptions{
    PersistedValues: GetUserPersistedValues(persistedUser, "userID")
  }
)
fmt.Println(exp.GroupName) // "Control"
exp = GetExperimentWithOptions(
  User{UserID: "unknown"},
  "active_experiment",
  &GetExperimentOptions{
    PersistedValues: GetUserPersistedValues(persistedUser, "userID")
  }
)
fmt.Println(exp.GroupName) // "Control"
```text
  </Tab>
  <Tab title=".Net">
```csharp
var options = new StatsigServerOptions();
options.UserPersistentStorage = new MyPersistentStorageAdapter()
await StatsigServer.Initialize("server-secret-key", options);

var persistedUser = new StatsigUser { UserID = "123" };
var values = await StatsigServer.GetUserPersistedValues(persistedUser, "userID");
var getExpOptions = new StatsigGetExperimentOptions(values);
var exp = StatsigServer.GetExperimentSync(persistedUser, "active_experiment", getExpOptions);
Console.WriteLine(exp.GroupName); // "Control"

var newValues = await StatsigServer.GetUserPersistedValues(persistedUser, "userID");
var newGetExpOptions = StatsigGetExperimentOptions(newValues);

var newExp = StatsigServer.GetExperimentSync(new StatsigUser {UserID = "unknown"}, "active_experiment", newGetExpOptions);
Console.WriteLine(newExp.GroupName); // "Control"