> ## Documentation Index
> Fetch the complete documentation index at: https://statsig-4b2ff144-serverless-cloudflare.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Server Persistent Assignment

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.

<Info>
  Currently only supported in `Go`, `Ruby`, `Legacy Node`, `Node Core`, `Kotlin`, `.Net`, `Python Core`
</Info>

### 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

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val options = GetExperimentOptions(
      ...
      persistentAssignmentOptions = PersistentAssignmentOptions(
        enforceTargeting = true,
      )
    )
    ```
  </Tab>

  <Tab title="Node JS">
    ```ts theme={null}
    const options: GetExperimentOptions = {
      ...
      persistentAssignmentOptions: {
        enforceTargeting: true,
      }
    }

    ```
  </Tab>
</Tabs>

### Example usage

<Tabs>
  <Tab title="Ruby">
    ```ruby theme={null}
    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'
    ```
  </Tab>

  <Tab title="Python (Python Core)">
    ```python theme={null}
    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
    ```
  </Tab>

  <Tab title="Node Core">
    ```typescript theme={null}
    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")))

    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    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"
    ```
  </Tab>

  <Tab title="Node JS">
    ```ts theme={null}
    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"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    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"
    ```
  </Tab>

  <Tab title=".Net">
    ```csharp theme={null}
    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"

    ```
  </Tab>
</Tabs>
