# Elixir Server SDK

## Setup the SDK

{% steps %}
{% step title="Install the SDK" %}
To use the SDK, add the following to your `mix.exs`:

```elixir
{:statsig_elixir, "~> 0.8.0"},
```

The SDK is written using `rustler_precompiled`, which downloads a precompiled binary by default. You can also build the Rust code within your project by cloning [statsig-server-core](https://github.com/statsig-io/statsig-server-core)

```bash
cd statsig-server-core/statsig-elixir/ 
# set the environment variable 
FORCE_STATSIG_NATIVE_BUILD="true" mix compile
```
{% /step %}

{% step title="Initialize the SDK" %}
After installation, initialize the SDK using a [Server Secret Key from the Statsig console](https://console.statsig.com/api_keys).

{% callout type="warning" %}
Always keep Server Secret Keys private. If you expose one, you can disable and recreate it in the Statsig console.
{% /callout %}

An optional `options` parameter accepts a `StatsigOptions` object to customize the SDK.

`Statsig.ex` uses GenServer to manage the Statsig instance (which is written in Rust). Add Statsig to your Supervision Tree:

```elixir
# Initializing, with StatsigOptions
sdk_key = "secret-key******" # your secret key
statsig_options = %StatsigOptions{enable_id_lists: true}

# Add to your supervision tree 
statsig_spec = %{id: Statsig, start: {Statsig, :start_link, [sdk_key, statsig_options]}}
children = [
    # Other Apps
    statsig_spec
]
res = Supervisor.start_link(children, opts)

# Or directly initialize the GenServer
{:ok,_} = Statsig.start_link(sdk_key, statsig_options)
Statsig.initialize()
```

`initialize` performs a network request. After `initialize` completes, virtually all SDK operations are synchronous (refer to [Evaluating Feature Gates in the Statsig SDK](https://blog.statsig.com/evaluating-feature-gates-in-the-statsig-sdk-a6f8881a1ad8)). The SDK fetches updates from Statsig in the background, independent of your API calls.
{% /step %}
{% /steps %}

## Working with the SDK

### Checking a feature flag/gate

After you initialize the SDK, you can fetch a [**Feature Gate**](https://docs.statsig.com/feature-flags/overview). Feature Gates create logic branches in code that you can roll out to different users from the Statsig Console. Gates are **CLOSED** or **OFF** (equivalent to `return false;`) by default.

All APIs require a user object (refer to [Statsig user](#statsig-user)). To check a gate for a user:

```elixir
user = %StatsigUser{
    user_id: "test_user_123"
}

{:ok, check_gate} = Statsig.check_gate("test_public", user)
# check_gate will be a boolean
```

### Reading a dynamic config

Feature Gates are useful for simple on/off switches with optional user targeting. To send different values (strings, numbers, etc.) to clients based on user attributes such as country, use [**Dynamic Configs**](https://docs.statsig.com/dynamic-config/overview). The API is similar to Feature Gates, but returns a JSON object from which you can retrieve typed parameters. For example:

```elixir
# Get a dynamic config for a specific user
user = %StatsigUser{
    user_id: "test_user_123"
}
{:ok, config} = Statsig.get_dynamic_config("a_config", user)

# Access the values in the dynamic config:

param_value = DynamicConfig.get_param_value(config, "header_text")

# Disable exposure
options = %Statsig.DynamicConfigEvaluationOptions{
    disable_exposure_logging = true
}
{:ok, config} = Statsig.get_dynamic_config("a_config", user, options)

```

### Getting a layer/experiment

**Layers/Experiments** let you run A/B/n experiments. Two APIs are available, but Statsig recommends [layers](https://docs.statsig.com/experiments/layers-overview) because layers make parameters reusable and support mutually exclusive experiments.

```elixir
# Values via get_layer
user = %StatsigUser{
    user_id: "test_user_123"
}

{:ok, layer} = Statsig.get_layer("user_promo_experiments", user)
{:ok, title_string_value} = Layer.get(layer, "title", "Welcome to Statsig!")
{:ok, discount_float_value} = Layer.get(layer, "discount", 0.1)

# Via get_experiment
{:ok, experiment} = Statsig.get_experiment("user_promo_experiment", user)
title_exp = Experiment.get_param_value(experiment, "new_user_promo_title")

# Disable exposure
options = %Statsig.ExperimentEvaluationOptions{
    disable_exposure_logging = true
}
{:ok, experiment} = Statsig.get_experiment("user_promo_experiment", user, options)
```

{% callout type="note" %}
When you use a layer to get a value, use get param value. This method returns primitive types (boolean, string, and numbers). For more complex types, the SDK returns JSON-serialized values.
{% /callout %}

### Retrieving feature gate metadata

To retrieve more information about a gate evaluation than a boolean value, use the Get Feature Gate API, which returns a `FeatureGate` object:

```elixir
{:ok, feature_gate} = Statsig.get_feature_gate(user, "example_gate")
# access the value, or the name off of the feature_gate object

options = %Statsig.FeatureGateEvaluationOptions{
    disable_exposure_logging = true
}
{:ok, feature_gate} = Statsig.get_feature_gate(user, "example_gate", options)

```

### Parameter stores

If you want dynamic control over whether a value comes from a Feature Gate, Experiment, or Dynamic Config outside your deployment cycle, use Parameter Stores. A Parameter Store lets you define a parameter that you can change at any point in the Statsig console. Parameter Stores are optional, but parameterizing your application supports future flexibility and allows non-technical Statsig users to turn parameters into experiments.

{% callout type="note" %}
*Parameter stores are not yet available for this sdk. Need it now? Reach out in Slack.*
{% /callout %}

### Logging an event

After setting up a Feature Gate or Experiment, track custom events to measure how features or experiment groups affect user behavior. Call the Log Event API and specify the user and event name. You can also provide a value and metadata:

```elixir
Statsig.log_event(user, "test_event", 1, %{"metadata_1" => "value"})
```

### Sending events to Log Explorer

You can forward logs to Logs Explorer for analysis using the Forward Log Line Event API. The API lets you include custom metadata and event values with each log.

{% callout type="note" %}
Sending events to Log Explorer is not yet available for this sdk. Need it now? Reach out in Slack.
{% /callout %}

## Statsig user

The `StatsigUser` object represents a user in Statsig. You must provide a `userID` or at least one of the `customIDs` to identify the user.

When calling APIs that require a user, pass as much information as possible. More user attributes enable advanced gate and config conditions (such as country or OS/browser checks) and more accurate experiment impact measurement. You must provide at least one identifier (userID or customID) to ensure a consistent experience for a given user. For details, refer to [why an ID is always required for server SDKs](https://docs.statsig.com/sdks/user#why-is-an-id-always-required-for-server-sdks).

In addition to `userID`, the top-level fields on `StatsigUser` are: `email`, `ip`, `userAgent`, `country`, `locale`, and `appVersion`. You can also pass key-value pairs in the `custom` field for targeting.

### Private attributes

Private attributes are user attributes that Statsig uses for evaluation but doesn't forward to any integrations. Use them for PII or sensitive data that you don't want to send to third-party services.

```elixir
user = %Statsig.User{
  user_id: "a-user-id",
  email: "user@example.com",
  ip: "192.168.1.1",
  user_agent: "Mozilla/5.0...",
  country: "US",
  locale: "en_US",
  app_version: "1.0.0",
  custom: %{
    # Custom fields
    "plan" => "premium",
    "age" => 25
  },
  custom_ids: %{
    # Custom ID types
    "stable_id" => "stable-id-123"
  },
  private_attributes: %{
    # Private attributes not forwarded to integrations
    "email" => "private@example.com"
  }
}
```

## Statsig options

You can pass an optional `options` parameter in addition to `sdkKey` during initialization to customize the Statsig client.

{% accordion title="StatsigOptions" %}
{% parameter name="environment" type="string" %}
The environment you're operating in (e.g., Production)
{% /parameter %}

{% parameter name="output_log_level" type="string" %}
The type of logs you'd like exposed. (e.g., Debug)
{% /parameter %}

{% parameter name="init_timeout_ms" type="number" %}
How long it should take for initialization to time out.
{% /parameter %}

{% parameter name="event_logging_flush_interval_ms" type="number" %}
How often events should flush to the Statsig servers.
{% /parameter %}

{% parameter name="event_logging_max_queue_size" type="Option<u32>" %}
Maximum number of events to queue before forcing a flush.

* Default is `2000`
* event\_logging\_max\_queue\_size \* event\_logging\_max\_pending\_batch\_queue\_size is the upper limit on how many events are queued
* See also `event_logging_max_pending_batch_queue_size`
{% /parameter %}

{% parameter name="event_logging_max_pending_batch_queue_size" type="Option<u32>" %}
Maximum number of event batches to hold in buffer to retry.

* Default is `100`.
* event\_logging\_max\_queue\_size \* event\_logging\_max\_pending\_batch\_queue\_size is the upper limit on how many events are queued
* eg: 2000 \* 100 means the SDK can process 200k event per second before events start getting dropped
* See also `event_logging_max_queue_size`.
{% /parameter %}

{% parameter name="log_event_url" type="string" %}
The URL events should be logged to
{% /parameter %}

{% parameter name="specs_sync_interval_ms" type="number" %}
How often specs should sync from the Statsig servers
{% /parameter %}

{% parameter name="specs_url" type="string" %}
The URL Statsig should download specs from
{% /parameter %}

{% parameter name="spec_adapter_configs" type="list" %}
Advanced configuration for fetching specs from custom sources, including [Statsig Forward Proxy](https://docs.statsig.com/infrastructure/api_proxy/introduction).
{% /parameter %}

{% parameter name="enable_id_lists" type="boolean" %}
Enable ID list download. **Required to be `true` when using segments with more than 1000 IDs.** See [ID List segments](https://docs.statsig.com/segments/add-id-list) for more details.
{% /parameter %}

{% parameter name="id_lists_url" type="string" %}
The URL ID lists should be downloaded from
{% /parameter %}

{% parameter name="id_lists_sync_interval_ms" type="number" %}
How often ID lists should be synced.
{% /parameter %}

{% parameter name="wait_for_country_lookup_init" type="boolean" %}
Block initialization call until country lookup is initialized
{% /parameter %}

{% parameter name="wait_for_user_agent_init" type="boolean" %}
Block initialization call until user\_agent is initialized
{% /parameter %}

{% parameter name="disable_all_logging" type="boolean" %}
When `true`, disables all event logging.
{% /parameter %}

{% parameter name="disable_country_lookup" type="boolean" %}
To improve memory usage, disable using country lookup.
{% /parameter %}

{% parameter name="disable_network" type="boolean" %}
Turn off all network requests including get\_dcs and log\_events
{% /parameter %}

{% parameter name="disable_user_agent_parsing" type="boolean" %}
To improve memory usage, disable using user agent parsing.
{% /parameter %}

***

```elixir
# Initialize StatsigOptions with custom parameters
statsig_options = %StatsigOptions{
  enable_id_lists: true
}

# Pass the options object into statsig.initialize()
{:ok, _} = Statsig.start_link(sdk_key, statsig_options)
Statsig.initialize()
```
{% /accordion %}

### Proxy and custom network routing

The Elixir Server Core SDK doesn't document a dedicated outbound HTTP proxy config. For custom network routing, use `spec_adapter_configs` for [Statsig Forward Proxy](https://docs.statsig.com/infrastructure/api_proxy/introduction) or set `specs_url`, `log_event_url`, and `id_lists_url` directly.

```elixir
statsig_options = %StatsigOptions{
  spec_adapter_configs: [
    %Statsig.SpecAdapterConfig{
      adapter_type: "network_grpc_websocket",
      specs_url: "http://forward-proxy.internal:50051",
      authentication_mode: "none"
    }
  ],
  fallback_to_statsig_api: true
}
```

## Shutting Statsig down

Because the SDK batches events and periodically flushes them, some events might not send before your app or server shuts down. To flush all logged events, call `shutdown()` before your app or server shuts down:

```elixir
Statsig.shutdown()
```

## Client SDK Bootstrapping | SSR

If you are using the Statsig client SDK in a browser or mobile app, you can bootstrap the client SDK with values from the server SDK to avoid a network request on the client. Bootstrapping is useful for server-side rendering (SSR) or when you want to reduce the number of network requests on the client.

```elixir
# Get client initialize response for a user
{:ok, response} = Statsig.get_client_init_response_as_string(user)

# Pass values to a client SDK to initialize without a network request
```

## Persistent storage

The Persistent Storage interface lets you implement custom storage for user-specific configurations. Use it to persist user assignments across sessions, ensuring consistent experiment groups when users return. Persistent storage is useful for client-side A/B testing where users must always see the same variant.

{% callout type="note" %}
Not supported yet.
{% /callout %}

## Data store

The Data Store interface lets you implement custom storage for Statsig configurations, enabling advanced caching strategies and integration with your preferred storage systems.

{% callout type="note" %}
Not supported yet.
{% /callout %}

## Custom output logger

The Output Logger interface lets you customize how the SDK logs messages, enabling integration with your own logging system and control over log verbosity.

{% callout type="note" %}
Not supported yet.
{% /callout %}

## Observability client

The Observability Client interface lets you monitor SDK health by integrating with your own observability systems, enabling tracking of metrics, errors, and performance data. For more information on the metrics emitted by Statsig SDKs, go to the [Monitoring documentation](https://docs.statsig.com/infrastructure/sdk-monitoring).

{% callout type="note" %}
Not supported yet.
{% /callout %}

## FAQ

{% accordion-group %}
{% accordion title="How do I run experiments for logged out users?" %}
Refer to the guide on [device level experiments](https://docs.statsig.com/guides/logging-events#device-level-events)
{% /accordion %}
{% /accordion-group %}
