
Official documentation for Amplitude Experiment's server-side JVM SDK implementation. Use this SDK in **either Java or Kotlin** server-side implementations.

This documentation has separate sections for [remote](/docs/feature-experiment/remote-evaluation) and [local](/docs/feature-experiment/local-evaluation) evaluation:

## Remote evaluation

Implements fetching variants for a user using [remote evaluation](/docs/feature-experiment/remote-evaluation).

### Install

Install the JVM Server SDK using Gradle.

{% code-group %}
```groovy Groovy
implementation "com.amplitude:experiment-jvm-server:<VERSION>"
```

```kotlin Kotlin
implementation("com.amplitude:experiment-jvm-server:<VERSION>")
```
{% /code-group %}

{% accordion title="Quick start" %}

1. [Initialize the experiment client](#initialize-remote)
2. [Fetch variants for the user](#fetch)
3. [Access a flag's variant](#fetch)

{% code-group %}
```kotlin Kotlin
// (1) Initialize the remote evaluation client with a server deployment key.
val experiment = Experiment.initializeRemote("<DEPLOYMENT_KEY>")

// (2) Fetch variants for a user
val user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build()
val variants = try {
    experiment.fetch(user).get()
} catch (e: Exception) {
    e.printStackTrace()
    return
}

// (3) Access a flag's variant
val variant = variants["<FLAG_KEY>"]
if (variant?.value == "on") {
    // Flag is on
} else {
    // Flag is off
}
```

```java Java
// (1) Initialize the remote evaluation client with a server deployment key.
RemoteEvaluationClient experiment =
        Experiment.initializeRemote("<DEPLOYMENT_KEY>");

// (2) Fetch variants for a user
ExperimentUser user = ExperimentUser.builder()
        .userId("user@company.com")
        .deviceId("abcdefg")
        .userProperty("premium", true)
        .build();
Map<String, Variant> variants;
try {
    variants = experiment.fetch(user).get();
} catch (Exception e) {
    e.printStackTrace();
    return;
}

// (3) Access a flag's variant
Variant variant = variants.get("<FLAG_KEY>");
if (Variant.valueEquals(variant, "on")) {
    // Flag is on
} else {
    // Flag is off
}
```
{% /code-group %}

{% /accordion %}

### Initialize remote

Initialize the SDK client in your server on startup. The [deployment key](/docs/feature-experiment/data-model#deployments) argument you pass to the `apiKey` parameter must live within the same project that you are sending analytics events to.

{% code-group %}
```kotlin Kotlin
fun initializeRemote(
    apiKey: String,
    config: RemoteEvaluationConfig = RemoteEvaluationConfig()
): RemoteEvaluationClient
```

```java Java
@Nonnull
public RemoteEvaluationClient initializeRemote(
    @Nonnull String apiKey,
    @Nonnull RemoteEvaluationConfig config
);
```
{% /code-group %}

| Parameter | Requirement | Description                                                                                                                                               |
| --------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`  | required    | The [deployment key](/docs/feature-experiment/data-model#deployments) that authorizes fetch requests and determines which flags to evaluate for the user. |
| `config`  | optional    | The client [configuration](#configuration) used to customize SDK client behavior.                                                                         |

{% code-group %}
```kotlin Kotlin
val experiment = Experiment.initializeRemote("<DEPLOYMENT_KEY>")
```

```java Java
RemoteEvaluationClient experiment = Experiment.initializeRemote("<DEPLOYMENT_KEY>");
```
{% /code-group %}

#### Configuration

Configure the SDK client during initialization.

{% callout type="info" heading="EU data center" %}
If you're using Amplitude's EU data center, configure the `serverZone` option on initialization.
{% /callout %}

| Name                         | Description                                                                                                                                              | Default Value                           |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `debug`                      | Set to `true` to enable debug logging.                                                                                                                   | `false`                                 |
| `logLevel`                   | The minimum log level to output. Options: `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `DISABLE`. Go to [custom logging](#custom-logging).               | `ERROR`                                 |
| `loggerProvider`             | Custom logger implementation. Implement the `LoggerProvider` interface to integrate with your logging solution. Go to [custom logging](#custom-logging). | `DefaultLogger` which outputs to stdout |
| `serverZone`                 | The Amplitude data center to use. Either `ServerZone.US` or `ServerZone.EU`.                                                                             | `ServerZone.US`                         |
| `serverUrl`                  | The host to fetch flag configurations from.                                                                                                              | `https://api.lab.amplitude.com`         |
| `fetchTimeoutMillis`         | The timeout for fetching variants in milliseconds.                                                                                                       | `500`                                   |
| `fetchRetries`               | The number of retries to attempt if a request to fetch variants fails.                                                                                   | `1`                                     |
| `fetchRetryBackoffMinMillis` | The minimum (initial) backoff after a request to fetch variants fails. The SDK scales this delay by the `fetchRetryBackoffScalar`                        | `0`                                     |
| `fetchRetryBackoffMaxMillis` | The maximum backoff between retries. If the scaled backoff becomes greater than the max, the SDK uses the max for all subsequent requests                | `10000`                                 |
| `fetchRetryBackoffScalar`    | Scales the minimum backoff exponentially.                                                                                                                | `1`                                     |

**CohortSyncConfig**

| Name                          | Description                                                                                                                                                                          | Default Value                         |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------- |
| `apiKey`                      | The analytics API key and NOT the experiment deployment key                                                                                                                          | _required_                            |
| `secretKey`                   | The analytics secret key                                                                                                                                                             | _required_                            |
| `maxCohortSize`               | The maximum size of cohort that the SDK downloads. Cohorts larger than this size won't download.                                                                                     | `2147483647`                          |
| `cohortPollingIntervalMillis` | The interval, in milliseconds, to poll Amplitude for cohort updates (60000 minimum).                                                                                                 | `60000`                               |
| `cohortServerUrl`             | The cohort server endpoint from which to fetch cohort data. For hitting the EU data center, set `serverZone` to `ServerZone.EU`. Setting this value overrides `serverZone` defaults. | `https://cohort-v2.lab.amplitude.com` |

### Fetch

Fetches variants for a [user](/docs/feature-experiment/data-model#users) and returns the results. The function [remote evaluates](/docs/feature-experiment/remote-evaluation) the user for flags associated with the deployment used to initialize the SDK client.

{% code-group %}
```kotlin Kotlin
fun fetch(user: ExperimentUser, fetchOptions: FetchOptions? = null): CompletableFuture<Map<String, Variant>>
```

```java Java
@Nonnull
public CompletableFuture<Map<String, Variant>> fetch(@Nonnull ExperimentUser user);

@Nonnull
public CompletableFuture<Map<String, Variant>> fetch(@Nonnull ExperimentUser user, @Nullable FetchOptions fetchOptions);
```
{% /code-group %}

| Parameter      | Requirement | Description                                                                       |
| -------------- | ----------- | --------------------------------------------------------------------------------- |
| `user`         | required    | The [user](/docs/feature-experiment/data-model#users) for whom to fetch variants. |
| `fetchOptions` | optional    | The [options](#fetch-options) for the fetch request.                              |

**FetchOptions**

| Name               | Description                                                                                                                              | Default Value |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `tracksExposure`   | To track or not track an exposure event for this fetch request. If `null`, uses the server's default behavior (doesn't track exposure).  | `null`        |
| `tracksAssignment` | To track or not track an assignment event for this fetch request. If `null`, uses the server's default behavior (does track assignment). | `null`        |

{% code-group %}
```kotlin Kotlin
val user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build()
val variants = try {
    experiment.fetch(user).get()
} catch (e: Exception) {
    e.printStackTrace()
    return
}
```

```java Java
ExperimentUser user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build();
Map<String, Variant> variants;
try {
    variants = experiment.fetch(user).get();
} catch (Exception e) {
    e.printStackTrace();
    return;
}
```
{% /code-group %}

After fetching variants for a user, you may to access the variant for a specific flag.

{% code-group %}
```kotlin Kotlin
val variant = variants["<FLAG_KEY>"]
if (variant?.value == "on") {
    // Flag is on
} else {
    // Flag is off
}
```

```java Java
Variant variant = variants.get("<FLAG_KEY>");
if (Variant.valueEquals(variant, "on")) {
    // Flag is on
} else {
    // Flag is off
}
```
{% /code-group %}

## Local evaluation

Implements evaluating variants for a user using [local evaluation](/docs/feature-experiment/local-evaluation). If you plan to use local evaluation, [understand the tradeoffs](/docs/feature-experiment/local-evaluation#targeting-capabilities).

### Install

Install the JVM Server SDK using Maven or Gradle.

{% code-group %}
```groovy Groovy
implementation "com.amplitude:experiment-jvm-server:<VERSION>"
```

```kotlin Kotlin
implementation("com.amplitude:experiment-jvm-server:<VERSION>")
```
{% /code-group %}

{% callout type="tip" heading="Quick start" %}

1. [Initialize the local evaluation client.](#initialize-local)
2. [Start the local evaluation client.](#start)
3. [Evaluate a user.](#evaluate)

{% code-group %}
```kotlin Kotlin
// (1) Initialize the local evaluation client with a server deployment key.
val experiment = Experiment.initializeLocal(
    "<DEPLOYMENT_KEY>",
    // (Recommended) Enable local evaluation cohort targeting.
    LocalEvaluationConfig.builder()
        .cohortSyncConfig(CohortSyncConfig("<API_KEY>", "<SECRET_KEY>"))
        .build()
)

// (2) Start the local evaluation client.
experiment.start()

// (3) Evaluate a user.
val user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build()
val variants = experiment.evaluate(user)
```

```java Java
// (1) Initialize the local evaluation client with a server deployment key.
LocalEvaluationClient experiment = Experiment.initializeLocal("<DEPLOYMENT_KEY>",
    // (Recommended) Enable local evaluation cohort targeting.
    LocalEvaluationConfig.builder()
        .cohortSyncConfig(new CohortSyncConfig("<API_KEY>", "<SECRET_KEY>"))
        .build());

// (2) Start the local evaluation client.
experiment.start();

// (3) Evaluate a user.
ExperimentUser user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build();
Map<String, Variant> variants = experiment.evaluate(user);
```
{% /code-group %}
{% /callout %}

### Initialize local

Initializes a [local evaluation](/docs/feature-experiment/local-evaluation) client.

{% callout type="warning" heading="Server deployment key" %}
You must [initialize](#initialize-local) the local evaluation client with a server [deployment](/docs/feature-experiment/data-model#deployments) key to get access to local evaluation flag configs.
{% /callout %}

{% code-group %}
```kotlin Kotlin
fun initializeLocal(
    apiKey: String,
    config: LocalEvaluationConfig = LocalEvaluationConfig(),
): LocalEvaluationClient
```

```java Java
@Nonnull
public LocalEvaluationClient initializeLocal(
    @Nonnull String apiKey,
    @Nonnull LocalEvaluationConfig config
);
```
{% /code-group %}

| Parameter | Requirement | Description                                                                                                                                                      |
| --------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`  | required    | The server [deployment key](/docs/feature-experiment/data-model#deployments) that authorizes fetch requests and determines which flags to evaluate for the user. |
| `config`  | optional    | The client [configuration](#configuration) used to customize SDK client behavior.                                                                                |

{% callout type="tip" heading="Flag streaming" %}
Use the `streamUpdates` [configuration](#configuration-1) to push flag config updates to the SDK (default `false`), instead of polling every `flagConfigPollingIntervalMillis` milliseconds. The time for SDK to receive the update after saving is generally less than one second. The SDK reverts to polling if streaming fails. Configure `flagConfigPollingIntervalMillis` [configuration](#configuration-1) to set the time flag configs take to update after modification (default 30s), as well for fallback.
{% /callout %}

#### Configuration

You can configure the SDK client on initialization.

{% callout type="info" heading="EU data center" %}
If you're using Amplitude's EU data center, configure the `serverZone` option on initialization.
{% /callout %}

**LocalEvaluationConfig**

| Name                                   | Description                                                                                                                                                                                                                                                                                 | Default Value                           |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `debug`                                | Set to `true` to enable debug logging.                                                                                                                                                                                                                                                      | `false`                                 |
| `logLevel`                             | The minimum log level to output. Options: `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `DISABLE`. Go to [custom logging](#custom-logging).                                                                                                                                                  | `ERROR`                                 |
| `loggerProvider`                       | Custom logger implementation. Implement the `LoggerProvider` interface to integrate with your logging solution. Go to [custom logging](#custom-logging).                                                                                                                                    | `DefaultLogger` which outputs to stdout |
| `serverZone`                           | The Amplitude data center to use. Either `ServerZone.US` or `ServerZone.EU`.                                                                                                                                                                                                                | `ServerZone.US`                         |
| `serverUrl`                            | The host to fetch flag configurations from.                                                                                                                                                                                                                                                 | `https://api.lab.amplitude.com`         |
| `flagConfigPollingIntervalMillis`      | The interval to poll for updated flag configs after calling [`Start()`](#start)                                                                                                                                                                                                             | `30000`                                 |
| `flagConfigPollerRequestTimeoutMillis` | The timeout for the request made by the flag config poller                                                                                                                                                                                                                                  | `10000`                                 |
| `assignmentConfiguration`              | **Deprecated.** Enable automatic assignment tracking for local evaluations.                                                                                                                                                                                                                 | `null`                                  |
| `exposureConfiguration`                | Enable exposure tracking for local evaluations.                                                                                                                                                                                                                                             | `null`                                  |
| `streamUpdates`                        | Enable streaming to replace polling for receiving flag config updates. Instead of polling every second, Amplitude servers push updates to SDK generally within one second. If the stream fails for any reason, it reverts to polling automatically and retry streaming after some interval. | `false`                                 |
| `streamServerUrl`                      | The URL of the stream server.                                                                                                                                                                                                                                                               | `https://stream.lab.amplitude.com`      |
| `streamFlagConnTimeoutMillis`          | The timeout for establishing a valid flag config stream. This includes time for establishing a connection to stream server and time for receiving initial flag configs.                                                                                                                     | `1500`                                  |
| `cohortSyncConfig`                     | Configuration to enable cohort downloading for [local evaluation cohort targeting](#local-evaluation-cohort-targeting).                                                                                                                                                                     | `null`                                  |

**AssignmentConfiguration**

| Name                      | Description                                                                                                                | Default Value |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `api_key`                 | The analytics API key and NOT the experiment deployment key                                                                | _required_    |
| `cache_capacity`          | The maximum number of assignments stored in the assignment cache                                                           | `65536`       |
| `eventUploadThreshold`    | `setEventUploadThreshold()` in the underlying [Analytics SDK](/docs/sdks/analytics/java/jre-java-sdk#configure-the-sdk)    | `10`          |
| `eventUploadPeriodMillis` | `setEventUploadPeriodMillis()` in the underlying [Analytics SDK](/docs/sdks/analytics/java/jre-java-sdk#configure-the-sdk) | `10000`       |
| `useBatchMode`            | `useBatchMode()` in the underlying [Analytics SDK](/docs/sdks/analytics/java/jre-java-sdk#configure-the-sdk)               | `true`        |

**ExposureConfiguration**

| Name                      | Description                                                                                                                | Default Value |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `api_key`                 | The analytics API key and NOT the experiment deployment key                                                                | _required_    |
| `cache_capacity`          | The maximum number of exposures stored in the exposure cache                                                               | `65536`       |
| `eventUploadThreshold`    | `setEventUploadThreshold()` in the underlying [Analytics SDK](/docs/sdks/analytics/java/jre-java-sdk#configure-the-sdk)    | `10`          |
| `eventUploadPeriodMillis` | `setEventUploadPeriodMillis()` in the underlying [Analytics SDK](/docs/sdks/analytics/java/jre-java-sdk#configure-the-sdk) | `10000`       |
| `useBatchMode`            | `useBatchMode()` in the underlying [Analytics SDK](/docs/sdks/analytics/java/jre-java-sdk#configure-the-sdk)               | `true`        |

**CohortSyncConfig**

| Name                          | Description                                                                                      | Default Value |
| ----------------------------- | ------------------------------------------------------------------------------------------------ | ------------- |
| `apiKey`                      | The analytics API key and NOT the experiment deployment key                                      | _required_    |
| `secretKey`                   | The analytics secret key                                                                         | _required_    |
| `maxCohortSize`               | The maximum size of cohort that the SDK downloads. Cohorts larger than this size won't download. | `2147483647`  |
| `cohortPollingIntervalMillis` | The interval, in milliseconds, to poll Amplitude for cohort updates (60000 minimum).             | `60000`       |

### Start

Start the local evaluation client, pre-fetching local evaluation mode flag configs for [evaluation](#evaluate) and starting the flag config poller at the [configured](#configuration) interval.

{% code-group %}
```kotlin Kotlin
fun start()
```

```java Java
public void start();
```
{% /code-group %}

Wait for `start()` to return before calling [`evaluate()`](#evaluate) to ensure that flag configs are available for use in evaluation.

### Stop

Shuts down the local evaluation client, stopping background processes for updating flag configs and cohorts.

{% code-group %}
```kotlin Kotlin
fun stop()
```

```java Java
public void stop();
```
{% /code-group %}

### Evaluate

Executes the [evaluation logic](/docs/feature-experiment/implementation) using the flags pre-fetched on [`start()`](#start). You must give `evaluate` a user object argument. You can optionally pass an array of flag keys if you require only a specific subset of flag variants.

{% callout type="tip" heading="Exposure tracking" %}
Set [`exposureConfiguration`](#configuration) to enable exposure tracking. Then, set `tracksExposure` to `true` in `EvaluateOptions` when calling `evaluate()`.
{% /callout %}

{% code-group %}
```kotlin Kotlin
fun evaluate(user: ExperimentUser, flagKeys: List<String> = listOf(), evaluateOptions: EvaluateOptions? = null): Map<String, Variant>
```

```java Java
@Nonnull
public Map<String, Variant> evaluate(@Nonnull ExperimentUser user, @Nonnull List<String> flagKeys, @Nullable EvaluateOptions evaluateOptions);
```
{% /code-group %}

| Parameter         | Requirement | Description                                                                                       |
| ----------------- | ----------- | ------------------------------------------------------------------------------------------------- |
| `user`            | required    | The [user](/docs/feature-experiment/data-model#users) to evaluate.                                |
| `flagKeys`        | optional    | Specific flags or experiments to evaluate. If empty, the SDK evaluates all flags and experiments. |
| `evaluateOptions` | optional    | The [options](#evaluate-options) for the evaluation request.                                      |

{% code-group %}
```kotlin Kotlin
// The user to evaluate
val user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build()

// Evaluate all flag variants
val allVariants = experiment.evaluate(user)

// Evaluate a specific subset of flag variants
val specificVariants = experiment.evaluate(user, listOf(
    "<FLAG_KEY_1>",
    "<FLAG_KEY_2>",
))

// Access a variant
val variant = allVariants["<FLAG_KEY>"]
if (variant?.value == "on") {
    // Flag is on
} else {
    // Flag is off
}
```

```java Java
// The user to evaluate
ExperimentUser user = ExperimentUser.builder()
    .userId("user@company.com")
    .deviceId("abcdefg")
    .userProperty("premium", true)
    .build();

// Evaluate all flag variants
Map<String, Variant> allVariants = experiment.evaluate(user);

// Evaluate a specific subset of flag variants
Map<String, Variant> specificVariants = experiment.evaluate(user,
    List.of("<FLAG_KEY_1>", "<FLAG_KEY_2>"));

// Access a variant
Variant variant = allVariants.get("<FLAG_KEY>");
if (Variant.valueEquals(variant, "on")) {
    // Flag is on
} else {
    // Flag is off
}
```
{% /code-group %}

**EvaluateOptions**

| Name             | Description                                                             | Default Value |
| ---------------- | ----------------------------------------------------------------------- | ------------- |
| `tracksExposure` | If `true`, the SDK tracks an exposure event for the evaluated variants. | `false`       |

{% accordion title="Account-level bucketing and analysis (v1.3.0+)" %}
If your organization has purchased the [Accounts add-on](/docs/analytics/account-level-reporting) you may perform bucketing and analysis on groups rather than users. Reach out to your representative to gain access to this beta feature.

Include groups in the user sent with the fetch request (recommended), or identify groups with the user through a group identify call from the [Group Identify API](/docs/apis/analytics/group-identify) or through [`setGroup()` from an analytics SDK](/docs/sdks/analytics/browser/browser-sdk-2#user-groups).

{% code-group %}
```java Java
try {
    ExperimentUser user = ExperimentUser.builder()
        .userId("user@company.com")
        .userProperty("premium", true)
        .group("org name", ["Amplitude"])
        .build();
    experiment.fetch(user).get();
} catch (Exception e) {
    e.printStackTrace();
}
```

```kotlin Kotlin
try {
    val user = ExperimentUser.builder()
        .userId("user@company.com")
        .userProperty("premium", true)
        .group("org name", ["Amplitude"])
        .build()
    experiment.fetch(user).get()
} catch (e: Exception) {
    e.printStackTrace()
}
```
{% /code-group %}
To pass freeform group properties, refer to this example:

{% code-group %}
```java Java
try {
    ExperimentUser user = ExperimentUser.builder()
        .userId("user@company.com")
        .userProperty("premium", true)
        .groupProperty("org name", ["Amplitude"])
        .build();
    experiment.fetch(user).get();
} catch (Exception e) {
    e.printStackTrace();
}
```

```kotlin Kotlin
try {
    val user = ExperimentUser.builder()
        .userId("user@company.com")
        .userProperty("premium", true)
        .groupProperty("org name", ["Amplitude"])
        .build()
    experiment.fetch(user).get()
} catch (e: Exception) {
    e.printStackTrace()
}
```
{% /code-group %}
{% /accordion %}

### Local evaluation cohort targeting

Since version `1.4.0`, the local evaluation SDK client supports downloading cohorts for local evaluation targeting. Configure the SDK using `cohortSyncConfig` with the analytics `apiKey` and `secretKey` on initialization to enable this support.

{% code-group %}
```kotlin Kotlin
val experiment = Experiment.initializeLocal(
    "<DEPLOYMENT_KEY>",
    // (Recommended) Enable local evaluation cohort targeting.
    LocalEvaluationConfig.builder()
        .cohortSyncConfig(CohortSyncConfig("<API_KEY>", "<SECRET_KEY>"))
        .build()
)
```

```java Java
// (1) Initialize the local evaluation client with a server deployment key.
LocalEvaluationClient experiment = Experiment.initializeLocal("<DEPLOYMENT_KEY>",
    // (Recommended) Enable local evaluation cohort targeting.
    LocalEvaluationConfig.builder()
        .cohortSyncConfig(new CohortSyncConfig("<API_KEY>", "<SECRET_KEY>"))
        .build());
```
{% /code-group %}

## Custom logging

Set the `logLevel` configuration to adjust log verbosity, or implement the `LoggerProvider` interface to use your own logger.

### Log levels

- `VERBOSE`: Detailed debugging logs
- `DEBUG`: Development and troubleshooting logs
- `INFO`: General information
- `WARN`: Warnings
- `ERROR`: Errors only (default)
- `DISABLE`: No logs

### Custom logger

Implement the `LoggerProvider` interface to use your own logging solution:

{% code-group %}
```kotlin Kotlin
import com.amplitude.experiment.util.LogLevel
import com.amplitude.experiment.util.LoggerProvider

class MyCustomLogger : LoggerProvider {
    override fun verbose(msg: String) {
        // Implement verbose logging
    }

    override fun debug(msg: String) {
        // Implement debug logging
    }

    override fun info(msg: String) {
        // Implement info logging
    }

    override fun warn(msg: String) {
        // Implement warn logging
    }

    override fun error(msg: String) {
        // Implement error logging
    }
}

// Initialize with custom logger
val experiment = Experiment.initializeLocal(
    "<DEPLOYMENT_KEY>",
    LocalEvaluationConfig.builder()
        .logLevel(LogLevel.DEBUG)
        .loggerProvider(MyCustomLogger())
        .build()
)
```

```java Java
import com.amplitude.experiment.util.LogLevel;
import com.amplitude.experiment.util.LoggerProvider;

public class MyCustomLogger implements LoggerProvider {
    @Override
    public void verbose(String msg) {
        // Implement verbose logging
    }

    @Override
    public void debug(String msg) {
        // Implement debug logging
    }

    @Override
    public void info(String msg) {
        // Implement info logging
    }

    @Override
    public void warn(String msg) {
        // Implement warn logging
    }

    @Override
    public void error(String msg) {
        // Implement error logging
    }
}

// Initialize with custom logger
LocalEvaluationClient experiment = Experiment.initializeLocal(
    "<DEPLOYMENT_KEY>",
    LocalEvaluationConfig.builder()
        .logLevel(LogLevel.DEBUG)
        .loggerProvider(new MyCustomLogger())
        .build()
);
```
{% /code-group %}

{% callout type="note" heading="Backward compatibility" %}
The `debug` configuration field is still supported. When set to `true`, it overrides `logLevel` to `DEBUG`.
{% /callout %}
