---
title: Initialize the Go SDK
slug: feature-experimentation/docs/initialize-sdk-go
docTags: 
createdAt: 2026-08-05T20:39:55.000Z
---

To initialize the **OptimizelyClient** that exposes API methods like [Decide](docId\:BlCsg45md_3l5fQuAUQwO), you need either the [SDK key](docId:8_kRh18IHN_0bW1xf7jYv) or a hard-coded JSON datafile.

## Basic initialization with SDK Key

```go
import optly "github.com/optimizely/go-sdk" // for v2: "github.com/optimizely/go-sdk/v2"

// Instantiates a client that syncs the datafile in the background
optlyClient, err := optly.Client("SDK_KEY_HERE")
if err != nil{
	// handle error
}
```

## Advanced configuration

### Static client instance

If you do not want the client to periodically sync the datafile in the background, you can instantiate a static client. This is useful for using the SDK in short-lived environments, such as Lambda functions. You can use the OptimizelyFactory for these more advanced use cases:

```go
import "github.com/optimizely/go-sdk/pkg/client" // for v2: "github.com/optimizely/go-sdk/v2/pkg/client"

optimizelyFactory := &client.OptimizelyFactory{
          Datafile: []byte("DATAFILE_JSON_STRING_HERE"),
}

// Instantiate a static client (no datafile polling)
staticOptlyClient, err := optimizelyFactory.StaticClient()
if err != nil {
	// handle error
}
```

If you want the SDK to initialize and perform just a one-time remote datafile fetch you can pass in the SDK key instead and instantiate a static client:

```go
import "github.com/optimizely/go-sdk/pkg/client" // for v2: "github.com/optimizely/go-sdk/v2/pkg/client"

optimizelyFactory := &client.OptimizelyFactory{
          SDKKey: "[SDK_KEY_HERE]",
}

// Instantiate a static client that will pull down the datafile one time
staticOptlyClient, err := optimizelyFactory.StaticClient()
if err != nil {
	// handle error
}
```

### Custom initialization

You can further customize the top-level components of the SDKs including the following:

- Event processor
- Config manager
- ODP manager
- Default decide options
- Decision service using `OptimizelyFactory`

```go
import (
  "time"
 
  "github.com/optimizely/go-sdk/pkg/client" // for v2: "github.com/optimizely/go-sdk/v2/pkg/client" 
)

optimizelyFactory := &client.OptimizelyFactory{
		SDKKey: "[SDK_KEY_HERE]",
	}

datafilePollingInterval := 2 * time.Second
eventBatchSize := 20
eventQueueSize := 1500
eventFlushInterval := 10 * time.Second
defaultDecideOptions := []decide.OptimizelyDecideOptions{
	decide.IgnoreUserProfileService,
}

// Instantiate a client with custom configuration
optimizelyClient, err := optimizelyFactory.Client(
  client.WithPollingConfigManager(datafilePollingInterval, nil),
  client.WithBatchEventProcessor(
    eventBatchSize,
    eventQueueSize,
    eventFlushInterval,
  ),
  client.WithDefaultDecideOptions(defaultDecideOptions),
)
if err != nil {
	// handle error
}
```

For more details on configuring the event batching, see [Event Batching](docId\:XGm92gIqiRT6z1SkcivOr). For more details on configuring default decide options, see [Decide methods](docId\:BlCsg45md_3l5fQuAUQwO).

## Dispose of the client

For effective resource management with the Optimizely Go SDK, you must properly close the Optimizely client instance when it is no longer needed. This is done by calling `.Close()`.

The `.Close()` method ensures that the processes and queues associated with the instance are properly released. This is essential for preventing memory leaks and ensuring that the application runs efficiently, especially in environments where resources are limited or in applications that create and dispose of many instances over their lifecycle.

See [Close Optimizely Feature Experimentation Go SDK on application exit](docId\:XGm92gIqiRT6z1SkcivOr).

## Use authenticated datafile in a secure environment

You can fetch the Optimizely datafile from an authenticated endpoint using a server-side (only) Optimizely SDK, like the Go SDK.

To use an [authenticated datafile](docId\:YpSOMYlWkUccLCL-uB-ZE), download your environment's access token from the [Optimizely app](https://app.optimizely.com) in **Settings > Environments**. Select your secure environment, and copy the **Datafile access token**. The following example shows how to initialize the Optimizely client using an access token and `sdkKey`, enabling the client to fetch the authenticated datafile and complete initialization.

```go
// fetch the datafile from an authenticated endpoint
accessToken := `YOUR_DATAFILE_ACCESS_TOKEN`
sdkKey := `YOUR_SDK_KEY`
factory := client.OptimizelyFactory{SDKKey: sdkKey}
optimizelyClient, err := factory.Client(client.WithDatafileAccessToken(accessToken))
if err != nil {
	// handle error
}
```

## `ODPManager`

The `ODPManager` contains the logic supporting Real-Time Audiences for Feature Experimentation-related features, including audience segments. You must configure this parameter to use Real-Time Audiences for Feature Experimentation.

The Go SDK enables the Real-Time Audiences for Feature Experimentation methods by default. But, the methods do nothing unless you have enabled and configured the [Real-Time Audiences for Feature Experimentation](docId:6UBBxxRv331nBIVZ2lun8).

:::hint{type="info"}
To explicitly disable Real-Time Audiences for Feature Experimentation, pass `WithOdpDisabled(true)` as `clientOption` while initiating `OptimizelyClient`.
:::

The following settings are optionally configurable when the Go SDK is initialized:

- **ODP SegmentsCache size** – `WithSegmentsCacheSize`
  - **Default** – 10,000
  - Set to 0 to disable caching.
- **ODP SegmentsCache timeout** (in seconds) – `WithSegmentsCacheTimeout`
  - **Default** – 600 secs (10 minutes)
  - Set to 0 to disable timeout (never expires).
- **ODP enable** – `WithOdpDisabled`
  - **Default** – false (enabled)
  - The Go SDK returns or logs an `odpNotEnabled` error when ODP is disabled and its features are requested.

See [Customize ODPSegmentManager](docId\:lA6eDbcuVC3C-SQUsCcXV).

### `ODPSegmentManager`

This module provides an interface to the remote Optimizely Data Platform (ODP) server for audience segment mappings.

It fetches all qualified segments for the given user context and returns `true` if the qualified segments array in the [user context](docId\:YD23vbbeambJxxmSEXUo8) is updated.

It also manages a segment's cache shared for all user contexts. The cache is in memory (not persistent), which is reset when the device is rebooted or the app is terminated.

### `ODPEventManager`

This module provides an interface to the remote ODP server for events.

It queues all pending events (persistent) and sends them (in batches of up to 10) to the ODP server when all resources are available, including network connection and ODP public key (in the SDK's datafile).

:::hint{type="info"}
The Go SDK tries to dispatch all events (stored in a persistent queue and retried on recoverable errors), but completion is not guaranteed.
:::

```go
import (
	"github.com/optimizely/go-sdk/pkg/odp"         // for v2: "github.com/optimizely/go-sdk/v2/pkg/odp"
	"github.com/optimizely/go-sdk/pkg/odp/event"   // for v2: "github.com/optimizely/go-sdk/v2/pkg/odp/event"
	"github.com/optimizely/go-sdk/pkg/odp/segment" // for v2: "github.com/optimizely/go-sdk/v2/pkg/odp/segment"
)

// You must configure Real-Time Audiences for Feature Experimentation
// before being able to calling ODPApiManager, ODPEventManager, and ODPSegmentManager.
sdkKey := `YOUR_SDK_KEY`
defaultEventApiManager := event.NewEventAPIManager(sdkKey, nil)
odpEventManager := event.NewBatchEventManager(event.WithAPIManager(defaultEventApiManager))
defaultSegmentApiManager := segment.NewSegmentAPIManager(sdkKey, nil)
odpSegmentManager := segment.NewSegmentManager(sdkKey, segment.WithAPIManager(defaultSegmentApiManager))

odpManager := odp.NewOdpManager(sdkKey, 
		false,
		odp.WithEventManager(odpEventManager),     // Optional
		odp.WithSegmentManager(odpSegmentManager), // Optional
)
```

### Customize `EventApiManager`

The `APIManager` is an interface, and its implementation requires the user to provide the functionality of the following methods:

```go
// APIManager represents the event API manager.
type APIManager interface {
	SendOdpEvents(apiKey, apiHost string, events []Event) (canRetry bool, err error)
}
```

Moreover, you can provide  `eventDispatchTimeout` in the constructor of `DefaultEventAPIManager`.

```go
eventDispatchTimeoutMillis := 20000 * time.Millisecond
defaultEventApiManager := event.NewEventAPIManager(sdkKey, utils.NewHTTPRequester(logging.GetLogger(sdkKey, "EventAPIManager"), utils.Timeout(eventDispatchTimeoutMillis)))
```

### Customize SegmentAPIManager

`APIManager` is an interface, and its implementation requires the user to provide the functionality of the following methods:

```go
// APIManager represents the segment API manager.
type APIManager interface {
	FetchQualifiedSegments(apiKey, apiHost, userID string, segmentsToCheck []string) ([]string, error)
}
```

You can provide a `segmentFetchTimeoutMillis`  in the constructor of `DefaultSegmentAPIManager`.

```go
segmentFetchTimeoutMillis := 20000 * time.Millisecond
defaultSegmentApiManager := segment.NewSegmentAPIManager(sdkKey, utils.NewHTTPRequester(logging.GetLogger(sdkKey, "SegmentAPIManager"), utils.Timeout(segmentFetchTimeoutMillis)))
```

### Customize `ODPEventManager`

You can provide a custom `queueSize` and `flushInterval` (if set to 0, then `batchSize` is set to 1. Otherwise, `batchSize` is the default, 10, in the constructor).

```go
queueSize := 20000
// Note: if this is set to 0 then batchSize will be set to 1, otherwise batchSize will be default, which is 10.
flushIntervalInMillis := 10000 * time.Millisecond // 10,000 msecs = 10 secs 

odpEventManager := event.NewBatchEventManager(
	event.WithAPIManager(defaultEventApiManager),
	event.WithQueueSize(queueSize),
	event.WithFlushInterval(flushIntervalInMillis),
)
```

### Customize `ODPSegmentManager`

You can provide a `cacheSize` and a `cacheTimeout` in the constructor, but these values are ignored if you provide a custom cache in the `ODPManager`. By default, `SegmentManager` is using `LRUCache`.

```go
cacheSize := 600
cacheTimeoutInSeconds := 600 * time.Second // 10 mins = 600 secs
odpSegmentManager := segment.NewSegmentManager(
	sdkKey,
	segment.WithAPIManager(defaultSegmentApiManager),
	segment.WithSegmentsCacheSize(cacheSize),
	segment.WithSegmentsCacheTimeout(cacheTimeoutInSeconds),
)

// Second method to set custom cache size and timeout using odpManager
odpManager := odp.NewOdpManager(
	sdkKey, false,
	odp.WithSegmentsCacheSize(cacheSize),
	odp.WithSegmentsCacheTimeout(cacheTimeoutInSeconds),
)
```

### Custom cache

You can use the custom cache, which is used in storing the `FetchQualifiedSegments` results. To provide a custom cache, you have to implement the `Cache` interface.

```go
// Cache is used for caching ODP segments
type Cache interface {
	Save(key string, value interface{})
	Lookup(key string) interface{}
	Reset()
}
```

The following is an example of `customCache` implementation:

```go
type CustomSegmentsCache struct {
	Cache map[string]interface{}
	lock  sync.Mutex
}

func (c *CustomSegmentsCache) Save(key string, value interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.Cache[key] = value
}

func (c *CustomSegmentsCache) Lookup(key string) interface{} {
	c.lock.Lock()
	defer c.lock.Unlock()
	return c.Cache[key]
}

func (c *CustomSegmentsCache) Reset() {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.Cache = map[string]interface{}{}
}
```

Pass this `customCache` object to `OdpManager` using its builder option and do not pass `SegmentManager` object:

```go
customCache := &CustomSegmentsCache{
	Cache: map[string]interface{}{},
}

// Note: To use custom Cache user should not pass SegmentManager 
odpManager = odp.NewOdpManager(
	sdkKey, 
	false,
	odp.WithSegmentsCache(customCache),
)
```

## CMAB Configuration

Configure caching behavior for Contextual Multi-Armed Bandit (CMAB) decisions at initialization time.

Pass a `CmabConfig` struct to `WithCmabConfig` when initializing your client with the following parameters:

| Parameter                      | Type                      | Default                                                | Description                                                                                                     |
| ------------------------------ | ------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| \`CacheSize\`                  | \`int\`                   | 10,000                                                 | Maximum number of cached decisions                                                                              |
| \`Cache\`                      | \`cache.CacheWithRemove\` | nil                                                    | Optional custom cache implementation for distributed deployments                                                |
| \`CacheTTL\`                   | \`time.Duration\`         | 30 minutes                                             | Time-to-live for cache entries                                                                                  |
| \`PredictionEndpointTemplate\` | \`string\`                | \`https\://prediction.cmab.optimizely.com/predict/%s\` | URL template for CMAB prediction API. The \`%s\` placeholder is replaced with the rule ID. Useful for proxying. |
| \`HTTPTimeout\`                | \`time.Duration\`         | 10 seconds                                             | Timeout for CMAB API requests                                                                                   |

:::hint{type="info"}
When `CacheSize`, `CacheTTL`, or `HTTPTimeout` are set to `0`, the Go SDK uses the default values shown above.
:::

For configuration examples, cache behavior details, and runtime control options, see [Configure the CMAB cache for the Go SDK](docId\:DO99zUMx-6ddApNEfOqHo).
