# Go Server Core SDK

## Setup the SDK

{% steps %}
{% step title="Install the SDK" %}
Using the `go get` CLI, install the latest version of the SDK:

```
go get github.com/statsig-io/statsig-go-core@latest
```

Or add a dependency on the most recent version in go.mod:

```
require (
  github.com/statsig-io/statsig-go-core v0.10.2-beta
)
```

Go to the [Releases tab in GitHub](https://github.com/statsig-io/statsig-server-core/releases) for the latest versions.

:::note
`go get` requires a Go module project with a go.mod file.
:::
{% /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.

```go expandable
import (
    "log"

    statsig "github.com/statsig-io/statsig-go-core"
)
			
options, err := statsig.NewOptionsBuilder().
    WithOutputLogLevel("DEBUG").
    Build()
if err != nil {
    log.Fatalf("failed to build options: %v", err)
}

s, err := statsig.NewStatsigWithOptions("secret-key", options)
if err != nil {
    log.Fatalf("failed to create Statsig client: %v", err)
}

s.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:

```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()

// Basic check
if s.CheckGate(user, "a_gate") {
    // Gate is on, enable new feature
} else {
    // Gate is off
}

// With options (e.g., disable automatic exposure logging)
options := &statsig.FeatureGateEvaluationOptions{DisableExposureLogging: true}
s.CheckGateWithOptions(user, "a_gate", options)
```

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

```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()

// You can disable exposure logging for this specific check
dynamicConfigOptions := &statsig.DynamicConfigEvaluationOptions{DisableExposureLogging: false}

dynamic_config := "a_config"
config := s.GetDynamicConfigWithOptions(user, dynamic_config, dynamicConfigOptions)

// Access the config values
str_val := config.GetString("str_val", "default_str_val") // returns String
int_val := config.GetNumber("number_val", 100) // returns float64
bool_val := config.GetBool("bool_val", false) // returns bool
interface_val := config.GetSlice("interface_val", []any{"default_interface_val"}) // returns []any
map_val := config.GetMap("map_val", map[string]any{"default": "value"}) // returns map[string]interface{}

// The config object also provides metadata about the evaluation
fmt.Println(config.RuleID) // The ID of the rule that served this config
fmt.Println(config.IDType) // The type of the evaluation (experiment, config, etc)
```

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

```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()

// Getting values with GetExperiment
experimentOptions := &statsig.ExperimentEvaluationOptions{DisableExposureLogging: false}

experiment := s.GetExperimentWithOptions(user, "a_test_experiment", experimentOptions)
str_val := experiment.GetString("str_val", "default_str_val") // returns String
int_val := experiment.GetNumber("number_val", 100) // returns float64

// Getting values with GetLayer
layerOptions := &statsig.LayerEvaluationOptions{DisableExposureLogging: false}

layer := s.GetLayerWithOptions(user, "a_test_experiment", layerOptions)
str_val := layer.GetString("str_val", "default_str_val") // returns String
int_val := layer.GetNumber("number_val", 100) // returns float64

```

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

```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()

options := &statsig.FeatureGateEvaluationOptions{DisableExposureLogging: false}
featureGate := s.GetFeatureGateWithOptions(user, "a_gate", options)
```

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

```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()

event := statsig.EventPayload{
    EventName: "sample_event",
    Value:     "event",
    Metadata: map[string]string{
        "val_1": "log val 1",
    },
}

s.LogEvent(user, event)
```

## Manual exposures

By default, the SDK automatically logs an exposure event when you check a gate, get a config, get an experiment, or call `get()` on a layer parameter. To delay exposure logging until the user actually uses the feature, use manual exposures.

All main SDK functions (`CheckGate`, `GetDynamicConfig`, `GetExperiment`, `GetLayer`) accept an optional options parameter with a `DisableExposureLogging` field. When set to `true`, the SDK doesn't automatically log an exposure event. You can then manually log the exposure using the corresponding manual exposure logging method:

{% tabs %}
{% tab title="Feature Gates" %}
```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()
options := &statsig.FeatureGateEvaluationOptions{DisableExposureLogging: true}
result := s.CheckGateWithOptions(user, "a_gate_name", options)
```

```go
s.ManuallyLogFeatureGateExposure(user, "gate_name")
```
{% /tab %}

{% tab title="Dynamic Configs" %}
```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()
options := &statsig.DynamicConfigEvaluationOptions{DisableExposureLogging: true}
config := s.GetDynamicConfigWithOptions(user, "config_name", options)
```

```go
s.ManuallyLogDynamicConfigExposure(user, "config_name")
```
{% /tab %}

{% tab title="Experiments" %}
```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()
options := &statsig.ExperimentEvaluationOptions{DisableExposureLogging: true}
experiment := s.GetExperimentWithOptions(user, "experiment_name", options)
```

```go
s.ManuallyLogExperimentExposure(user, "experiment_name")
```
{% /tab %}

{% tab title="Layers" %}
```go
user, _ := statsig.NewUserBuilderWithUserID("a-user").Build()
options := &statsig.LayerEvaluationOptions{DisableExposureLogging: true}
layer := s.GetLayerWithOptions(user, "layer_name", options)
paramValue := layer.GetString("param_name", "fallback")
```

```go
s.ManuallyLogLayerParamExposure(user, "layer_name", "param_name")
```
{% /tab %}
{% /tabs %}

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

## Statsig options

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

### Parameters

{% parameter name="SpecsUrl" type="string" %}
Custom URL for fetching feature specifications.
{% /parameter %}

{% parameter name="LogEventUrl" type="string" %}
Custom URL for logging events.
{% /parameter %}

{% parameter name="Environment" type="string" %}
Environment parameter for evaluation.
{% /parameter %}

{% parameter name="EventLoggingFlushIntervalMs" type="number" %}
How often the SDK flushes events to Statsig servers (in milliseconds).
{% /parameter %}

{% parameter name="EventLoggingMaxQueueSize" type="number" %}
Maximum number of events to queue before forcing a flush.
{% /parameter %}

{% parameter name="SpecsSyncIntervalMs" type="number" %}
How often the SDK updates specifications from Statsig servers (in milliseconds).
{% /parameter %}

{% parameter name="OutputLogLevel" type="string" %}
Controls the verbosity of SDK logs.
{% /parameter %}

{% parameter name="DisableCountryLookup" type="boolean" %}
Disables country lookup based on IP address. Set to `true` to improve performance if country-based targeting isn't needed.
{% /parameter %}

{% parameter name="DisableUserAgentParsing" type="boolean" %}
Disables user agent parsing. Set to `true` to improve performance if device/browser-based targeting isn't needed.
{% /parameter %}

{% parameter name="WaitForCountryLookupInit" type="boolean" %}
When set to `true`, the SDK waits for country lookup data (such as GeoIP or YAML files) to fully load during initialization. This may add approximately 1 second to startup time, but ensures that IP-to-country parsing is ready at evaluation time.
{% /parameter %}

{% parameter name="WaitForUserAgentInit" type="boolean" %}
When set to `true`, the SDK waits until user agent parsing data is fully loaded during initialization. This may add approximately 1 second to startup time, but ensures that parsing of the user's `userAgent` string into fields such as `browserName`, `browserVersion`, `systemName`, `systemVersion`, and `appVersion` is ready before any evaluations.
{% /parameter %}

{% parameter name="EnableIdLists" type="boolean" %}
Enables downloading ID lists; set to false to skip ID list syncing.
{% /parameter %}

{% parameter name="IdListsUrl" type="string" %}
Custom URL for fetching ID lists.
{% /parameter %}

{% parameter name="IdListsSyncIntervalMs" type="number" %}
How often the SDK syncs ID lists (in milliseconds).
{% /parameter %}

{% parameter name="DisableAllLogging" type="boolean" %}
When set to true, the SDK doesn't log any events or exposures.
{% /parameter %}

{% parameter name="DisableNetwork" type="boolean" %}
When set to true, the SDK doesn't make any network requests.
{% /parameter %}

{% parameter name="GlobalCustomFields" type="string" %}
JSON string of custom fields that should be appended to every evaluation.
{% /parameter %}

{% parameter name="ObservabilityClientRef" type="number" %}
Internal reference for a custom observability client created through the SDK.
{% /parameter %}

{% parameter name="DataStoreRef" type="number" %}
Internal reference for a custom data store adapter created through the SDK.
{% /parameter %}

{% parameter name="PersistentStorageRef" type="number" %}
Internal reference for a persistent storage adapter created through the SDK.
{% /parameter %}

{% parameter name="InitTimeoutMs" type="number" %}
Maximum time in milliseconds to wait for SDK initialization to complete. If initialization takes longer than this timeout, the SDK continues to operate but may return default values until initialization completes.
{% /parameter %}

{% parameter name="FallbackToStatsigApi" type="boolean" %}
When set to true, the SDK falls back to using the Statsig API directly if custom adapters (like local file adapters) fail to load configurations.
{% /parameter %}

### Proxy and custom network routing

The Go Server Core SDK currently documents endpoint overrides rather than a dedicated outbound proxy config. Use `WithSpecsUrl(...)`, `WithLogEventUrl(...)`, and `WithIdListsUrl(...)` to route Statsig network calls through your own endpoints or proxy layer.

***

### Example options usage

```go expandable
import (
    statsig "github.com/statsig-io/statsig-go-core"
)

// Initialize StatsigOptions with custom parameters
options, err := statsig.NewOptionsBuilder().
    WithSpecsUrl("https://example.com/specsUrl").
    WithLogEventUrl("https://example.com/logUrl").
    WithEnvironment("production").
    WithEventLoggingFlushIntervalMs(2000).
    WithEventLoggingMaxQueueSize(5000).
    WithSpecsSyncIntervalMs(1000).
    WithOutputLogLevel("DEBUG").
    WithDisableCountryLookup(true).
    WithDisableUserAgentParsing(true).
    WithWaitForCountryLookupInit(false).
    WithEnableIdLists(true).
    WithIdListsSyncIntervalMs(60000).
    WithInitTimeoutMs(3000).
    WithFallbackToStatsigApi(false).
    Build()
if err != nil {
    // handle options build error
}

// Pass the options object when initializing the Statsig client
s, err := statsig.NewStatsigWithOptions("secret-key", options)
if err != nil {
    // handle init error
}
s.Initialize()
```

## 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 shutting down your app or server:

```go
// Method signature
func (s *Statsig) Shutdown() {}

// example usage
s, err := statsig.NewStatsig("secret-key")
s.Initialize()
s.Shutdown()
```

### Flush events

```go
// Method signature
func (s *Statsig) FlushEvents() {}

// example usage
s, err := statsig.NewStatsig("secret-key")
s.Initialize()
s.FlushEvents()
```

## FAQ

##### Installation FAQs

#### How do I fix undefined symbol errors/linker errors

You may need to reset your environment variables to those found in the `statsig.env` or `statsig.env.ps1` file generated during the post-install script. Running the command sets the environment variables for the current terminal session. Add the variables to your `.bashrc`, `.zshrc`, or `.ps1` file to load them automatically.
