growthbook

package module
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 29 Imported by: 6

README

GrowthBook Go SDK Hero Image

GrowthBook Go SDK

Go Report Card GoDoc License Release

GrowthBook is a modular feature flagging and experimentation platform. You can use GrowthBook for feature flags, running no-code experiments with a visual editor, analyzing experiment results, or any combination of the above.

Requirements

  • Go version 1.21 or higher (tested with 1.21, 1.22, and 1.23)

Installation

go get github.com/growthbook/growthbook-golang

Usage

Quick Start

import (
    "context"
    "log"
    gb "github.com/growthbook/growthbook-golang"
)

// Create a new client instance with a client key and 
// a data source that loads features in the background via SSE stream.
// Pass the client's options to the NewClient function.
client, err := gb.NewClient(
    context.Background(),
    gb.WithClientKey("sdk-XXXX"),
    gb.WithSseDataSource(),
) 
defer client.Close()

if err != nil {
    log.Fatal("Client initialization failed: ", err)
}

// The data source starts asynchronously. Use EnsureLoaded to 
// wait until the client data is initialized for the first time.
if err := client.EnsureLoaded(context.Background()); err != nil {
    log.Fatal("Data loading failed: ", err)
}

// Create a child client with specific attributes.
attrs := gb.Attributes{"id": 100, "user": "user1"}
child, err := client.WithAttributes(attrs)
if err != nil {
    log.Fatal("Child client creation failed: ", err)
}

// Evaluate a text feature
buttonColor := child.EvalFeature(context.Background(), "buy-button-color")
if buttonColor.Value == "blue" {
    // Perform actions for blue button
}

// Evaluate a boolean feature
darkMode := child.EvalFeature(context.Background(), "dark-mode")
if darkMode.On {
    // Enable dark mode
}

Client

The client is the core component of the GrowthBook SDK. After installing and importing the SDK, create a single shared instance of growthbook.Client using the growthbook.NewClient function with a list of options. You can customize the client with options like a custom logger, client key, decryption key, default attributes, or a feature list from JSON. The client is thread-safe and can be safely used from multiple goroutines.

While you can evaluate features directly using the main client instance, it's recommended to create child client instances that include session- or query-specific data. To create a child client with local attributes, call client.WithAttributes:

attrs := gb.Attributes{"id": 100, "user": "Bob"}
child, err := client.WithAttributes(attrs)

Now, you can evaluate features using the child client:

res := child.EvalFeature(context.Background(), "main-button-color")

Additional options, such as WithLogger, WithUrl, and WithAttributesOverrides, can also be used to customize child clients. Since child clients share data with the main client instance, they will automatically receive feature updates.

To stop background updates, call client.Close() on the main client instance when it is no longer needed.


Tracking

Built-in GrowthBook Tracking Plugin

The SDK includes a built-in tracking plugin that automatically sends experiment and feature evaluation events to the GrowthBook warehouse. This is the easiest way to get analytics data flowing without any custom integration.

client, err := gb.NewClient(
    context.Background(),
    gb.WithClientKey("sdk-XXXX"),
    gb.WithSseDataSource(),
    gb.WithGrowthBookTracking(gb.TrackingPluginConfig{
        // Defaults to "https://us1.gb-ingest.com"
        IngestorHost: "https://us1.gb-ingest.com",
    }),
)
defer client.Close() // flushes remaining events

The plugin batches events and sends them in the background. Configuration options:

Option Default Description
IngestorHost https://us1.gb-ingest.com GrowthBook event ingestor endpoint
BatchSize 100 Max events before auto-flush
BatchTimeout 10s Max wait time before auto-flush
HTTPClient Client's HTTP client Custom HTTP client for sending events
Logger Client's logger Custom logger for error reporting

Events tracked automatically (standard GrowthBook event names, shared with the JS SDK):

  • Experiment Viewed — when a user is bucketed into an experiment
  • Feature Evaluated — every time a feature flag is evaluated

Events are sent in the ingestor's standard EventPayload shape (POST {IngestorHost}/track?client_key=... with a JSON array), carrying the evaluating client's attributes — so exposures from child clients are attributed to the right user.

If plugin initialization fails (e.g., missing client key), the plugin silently becomes a no-op — it never interferes with SDK evaluation.

Custom Events

client.LogEvent logs a custom event with arbitrary properties — the Go equivalent of logEvent in the JS SDK and log_event in the Python SDK. With the tracking plugin configured, custom events are batched and sent to the ingestor alongside the automatic events:

client.LogEvent(ctx, "button_clicked", gb.EventProperties{"button": "buy"})

You can also handle events yourself with WithEventLogger (with or without the tracking plugin — like callbacks, both fire independently). Matching the JS SDK, the event logger receives the built-in Experiment Viewed / Feature Evaluated events as well as custom LogEvent events — match on the gb.EventExperimentViewed / gb.EventFeatureEvaluated constants to filter:

client, err := gb.NewClient(
    context.Background(),
    gb.WithEventLogger(func(ctx context.Context, eventName string, properties gb.EventProperties, userCtx *gb.EventUserContext) {
        if eventName == gb.EventExperimentViewed || eventName == gb.EventFeatureEvaluated {
            return // only interested in custom events
        }
        // Send to your analytics provider; userCtx carries the evaluating
        // client's attributes and URL.
    }),
)

Custom plugins can receive these events too by implementing the optional EventLoggerPlugin interface (OnEvent).

Custom Tracking via Callbacks

For custom analytics integrations, you can set up two callbacks:

  1. ExperimentCallback: Triggered when a user is included in an experiment, with the user context (attributes and URL) the evaluation ran with — the equivalent of the JS SDK's trackingCallback.
  2. FeatureUsageCallback: Triggered on each feature evaluation.

You can also attach extra data that will be sent with each callback. These callbacks can be set globally via the NewClient function using the WithExperimentCallback and WithFeatureUsageCallback options. Alternatively, you can set them locally when creating child clients using similar methods like client.WithExperimentCallback. Extra data is set via the WithExtraData option.

client, err := gb.NewClient(
    context.Background(),
    gb.WithClientKey("sdk-XXXX"),
    gb.WithExperimentCallback(func(ctx context.Context, exp *gb.Experiment, result *gb.ExperimentResult, userCtx *gb.TrackingUserContext, extraData any) {
        // Send to your analytics provider
    }),
    gb.WithFeatureUsageCallback(func(ctx context.Context, key string, result *gb.FeatureResult, extraData any) {
        // Track feature usage
    }),
    gb.WithExtraData(myAnalyticsService),
)

Callbacks and the tracking plugin can be used together — they operate independently.

Deferred Tracking

Sometimes the process evaluating features isn't the right place to send analytics from. A common example is a remote-evaluation server: it evaluates features on behalf of client SDKs, and each client should report its own exposures. Deferred tracking buffers every experiment exposure an evaluation produces — including passthrough assignments and experiments inside prerequisite features — so you can read the buffer and forward it, instead of intercepting callbacks.

Create a TrackingBuffer and attach it with WithTrackingBuffer. The usual pattern is one buffer and one child client per user request; the child acts as the user context, and you hold the buffer handle:

buf := gb.NewTrackingBuffer()
child, _ := client.WithAttributes(gb.Attributes{"id": userID})
child, _ = child.WithTrackingBuffer(buf)

child.EvalFeature(ctx, "feature-a")
child.EvalFeature(ctx, "feature-b")

exposures := buf.TrackingCalls() // []gb.TrackingData

WithDeferredTracking() is the convenience form — it attaches a fresh internal buffer, readable through Client.DeferredTrackingCalls() and cleared with Client.ClearDeferredTrackingCalls() (both delegate to the attached buffer, whichever way it was attached).

Good to know:

  • The buffer keeps one entry per unique assignment (same user, experiment, and variation), in the order they were first seen. Reads return detached copies, safe to retain or mutate, and don't drain the buffer; Clear empties it, including its dedupe memory.
  • TrackingData marshals to the same JSON shape as the JS SDK's tracking data — including the user context the evaluation ran with — so a forwarded list can be passed directly to a JS client's setDeferredTrackingCalls.
  • Child clients cloned from a client with a buffer share it — the attacher chooses the scope. Attaching a different buffer (or nil) detaches the new client from the parent's.
  • Attaching one buffer to a long-lived shared client also works — the buffer is safe for concurrent use and entries carry their user identity — but it grows without bound until drained, so prefer one buffer per request. When draining a shared buffer in a loop, use TakeTrackingCalls() (or Client.TakeDeferredTrackingCalls()): it returns and empties atomically, so an exposure recorded mid-drain is never cleared without being returned.
  • Buffering is independent of callbacks and plugins: both always fire. The buffer exists to forward exposures to a client SDK that reports them there; if a server-side callback reports to the same analytics destination, that destination sees each exposure twice — route each destination through one channel.
  • Feature usage is not buffered, only experiment exposures. Usage events describe where evaluation happened, and remote-evaluation clients report their own; on the server they still reach callbacks and plugins.
Custom Plugins

You can implement the Plugin interface to create custom tracking or other plugins:

type Plugin interface {
    Init(client *gb.Client) error
    OnExperimentViewed(ctx context.Context, experiment *gb.Experiment, result *gb.ExperimentResult)
    OnFeatureEvaluated(ctx context.Context, featureKey string, result *gb.FeatureResult)
    Close() error
}

Register custom plugins using WithPlugins:

client, err := gb.NewClient(
    context.Background(),
    gb.WithClientKey("sdk-XXXX"),
    gb.WithPlugins(myCustomPlugin),
)

Plugins are shared with child clients. Any panics in plugin methods are recovered and logged — they never interrupt SDK evaluation.


Sticky Bucketing

Sticky Bucketing ensures users see consistent experiment variations across sessions and devices. The SDK provides an in-memory implementation by default, but you can implement your own storage solution.

Basic Usage
// Create an in-memory sticky bucket service
service := gb.NewInMemoryStickyBucketService()

// Create a client with sticky bucketing
client, err := gb.NewClient(
    context.Background(),
    gb.WithClientKey("sdk-XXXX"),
    gb.WithStickyBucketService(service),
)

// Run an experiment with sticky bucketing
exp := &gb.Experiment{
    Key:        "my-experiment",
    Variations: []gb.FeatureValue{"control", "treatment"},
    Meta: []gb.VariationMeta{
        {Key: "0"}, // Use numeric keys to match variation IDs
        {Key: "1"},
    },
    BucketVersion:    1,
    MinBucketVersion: 0,
}

result := client.RunExperiment(context.Background(), exp)
Custom Implementation

Implement the StickyBucketService interface for custom storage:

Concurrency & Caching
  • The in-memory service implementation is thread-safe using sync.RWMutex
  • Assignments are cached per client to reduce storage calls; the cache is shared between a client and its child clients (created via With* methods) and is bounded (LRU, 10,000 docs by default — tune or remove the bound with WithStickyBucketCacheSize)
  • Within a client and its children, concurrent reads and saves of the same user's assignment doc are serialized, so parallel evaluations merge assignments instead of overwriting each other
  • Scope of the guarantee: independently constructed clients — or separate processes — sharing one StickyBucketService are not serialized against each other. SaveAssignments writes whole documents last-write-wins, so truly concurrent saves for the same user from different clients can drop an assignment. If that matters for your deployment, make your service's SaveAssignments merge atomically in the backend (e.g. a Redis hash or a transactional upsert)

For more details, see the official documentation.

Contextual Bandits

GrowthBook contextual bandits (an Enterprise feature) learn per-segment variation weights server-side — the SDK evaluates no model. A bandit rule references a set of targeting contexts ("leaves"); the SDK routes the user to the first leaf whose condition matches and buckets with that leaf's weights. Definitions arrive in the SDK payload alongside features (encrypted payloads supported), so no extra configuration is needed. For manual setups there are WithContextualBandits(...) at construction and SetContextualBandits(...) at runtime.

res := client.EvalFeature(ctx, "my-bandit-feature")
r := res.ExperimentResult
// r.LeafId, r.VariationWeights, r.BanditVersion — log these with the
// exposure so the bandit keeps learning.

Good to know:

  • ExperimentResult carries LeafId, VariationWeights, and BanditVersion only for real hashed assignments (never for forced variations, QA mode, or sticky-bucketed users). Log them in your tracking callback — the bandit reweights outcomes by these propensities.
  • Weights change as the bandit learns, so a user may be re-bucketed between payload refreshes. That is by design: GrowthBook disables sticky bucketing on bandit rules and attributes each user to their first exposure at analysis time.
  • Bandit rules carry their variations under contextualVariations, so older SDK versions without bandit support skip the rule and serve the feature's default value.
  • Malformed bandit data degrades safely — fallback leaf -1 with the rule's aggregate weights — and never blocks the feature update it arrived with.
  • Deferred tracking forwards bandit attribution too: buffered TrackingData carries the same fields.

Documentation


Documentation

Overview

Package growthbook is the GrowthBook Go client library. It enables you to seamlessly evaluate feature flags and conduct A/B testing (experiments) directly within your Go application, integrating with the GrowthBook platform.

Index

Constants

View Source
const (
	EventExperimentViewed = "Experiment Viewed"
	EventFeatureEvaluated = "Feature Evaluated"
)

Built-in event names dispatched through the event-logger channel for every tracked exposure and feature evaluation, mirroring the JS SDK's EVENT_EXPERIMENT_VIEWED / EVENT_FEATURE_EVALUATED (sdk-js core.ts). Event logger callbacks can match on these to filter built-ins from custom LogEvent events.

Variables

View Source
var (
	ErrCryptoInvalidEncryptedFormat = errors.New("Crypto: encrypted data is in invalid format")
	ErrCryptoInvalidIVLength        = errors.New("Crypto: invalid IV length")
	ErrCryptoInvalidPadding         = errors.New("Crypto: invalid padding")
)
View Source
var (
	ErrNoDecryptionKey = errors.New("no decryption key provided")
)

Functions

func SaveStickyBucketAssignment added in v0.2.3

func SaveStickyBucketAssignment(
	experimentKey string,
	bucketVersion int,
	variationID int,
	variationKey string,
	service StickyBucketService,
	attributeName string,
	attributeValue string,
	cachedAssignments StickyBucketAssignments,
) error

SaveStickyBucketAssignment saves a sticky bucket assignment

Types

type Attributes

type Attributes map[string]any

type BucketRange added in v0.2.0

type BucketRange struct {
	Min float64
	Max float64
}

BucketRange represents a single bucket range.

func (*BucketRange) InRange added in v0.2.0

func (r *BucketRange) InRange(n float64) bool

func (BucketRange) MarshalJSON added in v0.4.0

func (br BucketRange) MarshalJSON() ([]byte, error)

func (*BucketRange) UnmarshalJSON added in v0.2.0

func (br *BucketRange) UnmarshalJSON(data []byte) error

type Client added in v0.2.0

type Client struct {
	// contains filtered or unexported fields
}

Client is a GrowthBook SDK client.

func NewApiClient added in v0.2.0

func NewApiClient(apiHost string, clientKey string) (*Client, error)

NewApiClient creates simple client with API host and client key

func NewClient added in v0.2.0

func NewClient(ctx context.Context, opts ...ClientOption) (*Client, error)

NewClient create a new GrowthBook SDK client.

func (*Client) CallFeatureApi added in v0.2.0

func (c *Client) CallFeatureApi(ctx context.Context, etag string) (*FeatureApiResponse, error)

func (*Client) ClearDeferredTrackingCalls added in v0.4.0

func (client *Client) ClearDeferredTrackingCalls()

ClearDeferredTrackingCalls empties the client's attached tracking buffer (see TrackingBuffer.Clear). No-op when no buffer is attached.

func (*Client) ClientKey added in v0.2.8

func (client *Client) ClientKey() string

ClientKey returns the SDK client key used to authenticate with the GrowthBook API.

func (*Client) Close added in v0.2.0

func (client *Client) Close() error

Close client's background goroutines and plugins.

func (*Client) DecryptFeatures added in v0.2.0

func (client *Client) DecryptFeatures(encrypted string) (FeatureMap, error)

func (*Client) DeferredTrackingCalls added in v0.4.0

func (client *Client) DeferredTrackingCalls() []TrackingData

DeferredTrackingCalls returns the exposures collected by the client's attached tracking buffer (see TrackingBuffer.TrackingCalls). Returns nil when no buffer is attached.

func (*Client) EnsureLoaded added in v0.2.0

func (client *Client) EnsureLoaded(ctx context.Context) error

func (*Client) EvalFeature added in v0.2.0

func (client *Client) EvalFeature(ctx context.Context, key string) *FeatureResult

EvalFeature evaluates feature based on attributes and features map

func (*Client) Features added in v0.2.0

func (client *Client) Features() FeatureMap

func (*Client) HttpClient added in v0.2.8

func (client *Client) HttpClient() *http.Client

HttpClient returns the HTTP client used by the GrowthBook client.

func (*Client) LogEvent added in v0.3.0

func (client *Client) LogEvent(ctx context.Context, eventName string, properties EventProperties)

LogEvent logs a custom event, the Go equivalent of the JS SDK's logEvent and the Python SDK's log_event. The event is delivered to the event logger configured with WithEventLogger and to every plugin that implements EventLoggerPlugin. If neither is configured a warning is logged and the call is a no-op.

func (*Client) Logger added in v0.2.8

func (client *Client) Logger() *slog.Logger

Logger returns the logger used by the GrowthBook client.

func (*Client) RefreshFeatures added in v0.2.7

func (client *Client) RefreshFeatures(ctx context.Context) error

RefreshFeatures immediately fetches the latest features from the GrowthBook API and updates the client. Useful in manual mode when no background datasource is configured and the caller wants to control when features are refreshed.

func (*Client) RunExperiment added in v0.2.0

func (client *Client) RunExperiment(ctx context.Context, exp *Experiment) *ExperimentResult

func (*Client) SetContextualBandits added in v0.5.0

func (client *Client) SetContextualBandits(bandits ContextualBanditDefinitions) error

SetContextualBandits updates the shared contextual bandit definitions.

func (*Client) SetEncryptedJSONFeatures added in v0.2.0

func (client *Client) SetEncryptedJSONFeatures(encryptedJSON string) error

SetEncryptedJSONFeatures updates shared features from encrypted JSON. Uses client's decryption key.

func (*Client) SetFeatures added in v0.2.0

func (client *Client) SetFeatures(features FeatureMap) error

SetFeatures updates shared client features.

func (*Client) SetJSONFeatures added in v0.2.0

func (client *Client) SetJSONFeatures(featuresJSON string) error

SetJSONFeatures updates shared features from JSON

func (*Client) Subscribe added in v0.2.9

func (client *Client) Subscribe(fn ExperimentSubscriber) (unsubscribe func())

Subscribe registers a callback fired when an experiment assignment changes. The returned function unregisters it. Subscribers are shared across child clients created via With* methods - register once on the root client. Subscribers observe the same experiment state the tracking pipeline records: bandit metadata is stripped before notification whenever the result carries no leaf attribution, matching the JS and Python SDKs.

func (*Client) TakeDeferredTrackingCalls added in v0.5.0

func (client *Client) TakeDeferredTrackingCalls() []TrackingData

TakeDeferredTrackingCalls atomically drains the client's attached tracking buffer (see TrackingBuffer.TakeTrackingCalls). Returns nil when no buffer is attached.

func (*Client) UpdateFromApiResponse added in v0.2.0

func (client *Client) UpdateFromApiResponse(resp *FeatureApiResponse) error

UpdateFromApiResponse updates shared data from Growthbook API response

func (*Client) UpdateFromApiResponseJSON added in v0.2.0

func (client *Client) UpdateFromApiResponseJSON(respJSON string) error

func (*Client) WithAttributeOverrides added in v0.2.0

func (c *Client) WithAttributeOverrides(attributes Attributes) (*Client, error)

WithAttributeOverrides creates child client instance with updated top-level attributes.

func (*Client) WithAttributes added in v0.2.0

func (c *Client) WithAttributes(attributes Attributes) (*Client, error)

WithAttributes creates child client instance that uses provided attributes for evaluation.

func (*Client) WithDeferredTracking added in v0.4.0

func (c *Client) WithDeferredTracking() (*Client, error)

WithDeferredTracking creates child client with deferred tracking enabled and a fresh internal buffer — the convenience form of WithTrackingBuffer(NewTrackingBuffer()).

func (*Client) WithEnabled added in v0.2.0

func (c *Client) WithEnabled(enabled bool) (*Client, error)

WithEnabled creates child client instance with updated enabled switch.

func (*Client) WithEventLogger added in v0.3.0

func (c *Client) WithEventLogger(cb EventLogger) (*Client, error)

WithEventLogger creates child client with updated event logger function.

func (*Client) WithExperimentCallback added in v0.2.0

func (c *Client) WithExperimentCallback(cb ExperimentCallback) (*Client, error)

WithExperimentCallback creates child client with updated experiment callback function.

func (*Client) WithExtraData added in v0.2.0

func (c *Client) WithExtraData(extraData any) (*Client, error)

WithExtraData creates child client with extra data that will be sent to a callback.

func (*Client) WithFeatureUsageCallback added in v0.2.0

func (c *Client) WithFeatureUsageCallback(cb FeatureUsageCallback) (*Client, error)

WithFeatureUsageCallback creates child client with udpated feature usage callback function.

func (*Client) WithForcedVariations added in v0.2.0

func (c *Client) WithForcedVariations(forcedVariations ForcedVariationsMap) (*Client, error)

WithForcedVariations creates child client with updated forced variations.

func (*Client) WithGroups added in v0.2.9

func (c *Client) WithGroups(groups map[string]bool) (*Client, error)

WithGroups creates child client with updated legacy group membership.

func (*Client) WithLogger added in v0.2.0

func (c *Client) WithLogger(logger *slog.Logger) (*Client, error)

WithLogger creates child client instance that uses provided logger.

func (*Client) WithQaMode added in v0.2.0

func (c *Client) WithQaMode(qaMode bool) (*Client, error)

WithQaMode creates child client instance with updated qaMode switch.

func (*Client) WithTrackingBuffer added in v0.5.0

func (c *Client) WithTrackingBuffer(b *TrackingBuffer) (*Client, error)

WithTrackingBuffer creates a child client that collects exposures into the given caller-owned buffer (nil detaches). Attach a fresh buffer per request or user scope; the child's own clones share it.

func (*Client) WithUrl added in v0.2.0

func (c *Client) WithUrl(rawUrl string) (*Client, error)

WithUrl creates child client with updated current page URL.

type ClientOption added in v0.2.0

type ClientOption func(*Client) error

func WithApiHost added in v0.2.0

func WithApiHost(apiHost string) ClientOption

WithApiHost sets the GrowthBook API Host.

func WithAttributes added in v0.2.0

func WithAttributes(attributes Attributes) ClientOption

WithAttributes sets attributes that used to assign variations.

func WithClientKey added in v0.2.0

func WithClientKey(clientKey string) ClientOption

WithClientKey sets client key used to fetch features from the GrowthBook API.

func WithContextualBandits added in v0.5.0

func WithContextualBandits(bandits ContextualBanditDefinitions) ClientOption

WithContextualBandits sets contextual bandit definitions, normally delivered in the SDK payload.

func WithDataSource added in v0.2.4

func WithDataSource(dataSource DataSource) ClientOption

func WithDecryptionKey added in v0.2.0

func WithDecryptionKey(decryptionKey string) ClientOption

WithDecryptionKey sets key used to decrypt encrypted features from the API.

func WithDeferredTracking added in v0.4.0

func WithDeferredTracking() ClientOption

WithDeferredTracking buffers every experiment exposure produced by evaluation for later retrieval with Client.DeferredTrackingCalls. It is the convenience form of WithTrackingBuffer(NewTrackingBuffer()) — use that form to hold the buffer handle yourself.

func WithEnabled added in v0.2.0

func WithEnabled(enabled bool) ClientOption

WithEnabled sets enabled switch to globally disable all experiments. Default true.

func WithEncryptedJsonFeatures added in v0.2.0

func WithEncryptedJsonFeatures(featuresJson string) ClientOption

WithEncryptedJsonFeatures sets features definitions from encrypted JSON string.

func WithEventLogger added in v0.3.0

func WithEventLogger(cb EventLogger) ClientOption

WithEventLogger sets a callback invoked by Client.LogEvent for every custom event.

func WithExperimentCallback added in v0.2.0

func WithExperimentCallback(cb ExperimentCallback) ClientOption

WithExperimentCallback sets experiment callback function.

func WithExtraData added in v0.2.0

func WithExtraData(extraData any) ClientOption

WithExtraData sets extra data that will be to callback calls.

func WithFeatureUsageCallback added in v0.2.0

func WithFeatureUsageCallback(cb FeatureUsageCallback) ClientOption

WithFeatureUsageCallback sets feature usage callback function.

func WithFeatures added in v0.2.0

func WithFeatures(features FeatureMap) ClientOption

WithFeatures sets features definitions (usually pulled from an API or cache).

func WithForcedVariations added in v0.2.0

func WithForcedVariations(forcedVariations ForcedVariationsMap) ClientOption

WithForcedVariations force specific experiments to always assign a specific variation (used for QA)

func WithGroups added in v0.2.9

func WithGroups(groups map[string]bool) ClientOption

WithGroups sets legacy group membership for the user, used by experiments that declare a `groups` array. Distinct from saved groups, which power $inGroup conditions on `condition`.

func WithGrowthBookTracking added in v0.2.8

func WithGrowthBookTracking(config TrackingPluginConfig) ClientOption

WithGrowthBookTracking is a convenience option that adds a GrowthBookTrackingPlugin to the client with the given configuration.

func WithHttpClient added in v0.2.0

func WithHttpClient(httpClient *http.Client) ClientOption

WithHttpClient sets http client for GrowthBook API calls.

func WithJsonFeatures added in v0.2.0

func WithJsonFeatures(featuresJson string) ClientOption

WithJsonFeatures sets features definitions from JSON string.

func WithLogger added in v0.2.0

func WithLogger(logger *slog.Logger) ClientOption

WithLogger sets logger for GrowthBook client.

func WithPlugins added in v0.2.8

func WithPlugins(plugins ...Plugin) ClientOption

WithPlugins adds plugins to the client. Plugins are initialized after all client options are applied and are shared with child clients.

func WithPollDataSource added in v0.2.0

func WithPollDataSource(interval time.Duration) ClientOption

func WithQaMode added in v0.2.0

func WithQaMode(qaMode bool) ClientOption

WithQaMode if true, random assignment is disabled and only explicitly forced variations are used.

func WithSavedGroups added in v0.2.0

func WithSavedGroups(savedGroups condition.SavedGroups) ClientOption

WithSavedGroups sets saved groups used to target the same group of users across multiple features and experiments.

func WithSseDataSource added in v0.2.0

func WithSseDataSource(opts ...SseOption) ClientOption

func WithStickyBucketAttributes added in v0.2.3

func WithStickyBucketAttributes(attributes StickyBucketAttributes) ClientOption

WithStickyBucketAttributes sets sticky bucket attributes for the client

func WithStickyBucketCacheSize added in v0.3.0

func WithStickyBucketCacheSize(size int) ClientOption

WithStickyBucketCacheSize bounds the client's in-memory sticky bucket assignments cache to size entries with LRU eviction. The cache holds one entry per attribute value evaluated, so a long-lived multi-user client grows it with every new user; evicting an entry only costs a re-fetch from the StickyBucketService. size <= 0 removes the bound. The default is 10000 entries.

func WithStickyBucketService added in v0.2.3

func WithStickyBucketService(service StickyBucketService) ClientOption

WithStickyBucketService adds a sticky bucket service to the client

func WithTrackingBuffer added in v0.5.0

func WithTrackingBuffer(b *TrackingBuffer) ClientOption

WithTrackingBuffer attaches a caller-owned buffer that collects every experiment exposure produced by evaluation (passthrough and prerequisite assignments included) for forwarding to a client SDK — read it with TrackingBuffer.TrackingCalls or Client.DeferredTrackingCalls. Buffering is independent of callbacks and plugins, which still fire. Clients cloned from this one share the attached buffer — attach a fresh buffer per request or user scope. A nil buffer detaches.

func WithUrl added in v0.2.0

func WithUrl(rawUrl string) ClientOption

WithUrl sets url of the current page.

type ContextualBanditAssignment added in v0.5.0

type ContextualBanditAssignment struct {
	LeafId           int       `json:"leafId"`
	VariationWeights []float64 `json:"variationWeights"`
	BanditVersion    *int      `json:"banditVersion,omitempty"`
}

ContextualBanditAssignment is what a contextual bandit assignment was made with: the chosen leaf (or the fallback -1) and the variation weights bucketing used. Distinct from ContextualBanditContext, which is a payload leaf (a targeting condition plus candidate weights).

type ContextualBanditContext added in v0.5.0

type ContextualBanditContext struct {
	// LeafId is nil when the payload's leafId is absent or not an integer;
	// such a leaf cannot be attributed and demotes to the fallback.
	LeafId    *int           `json:"leafId"`
	Condition condition.Base `json:"condition"`
	// Weights is nil when the payload's weights are absent or type-malformed.
	Weights []float64 `json:"weights"`
	// contains filtered or unexported fields
}

ContextualBanditContext is one leaf of a contextual bandit definition: a targeting condition and the variation weights to use when it matches. An absent condition is a catch-all leaf.

func (ContextualBanditContext) MarshalJSON added in v0.5.0

func (c ContextualBanditContext) MarshalJSON() ([]byte, error)

MarshalJSON emits the context's current fields, so values modified after decoding serialize what evaluation would use. The one exception is a malformed context: evaluation ignores its fields (leaf selection aborts at it), so serialization preserves the original junk — emitting fields would launder it into a valid catch-all leaf and change routing on re-decode.

func (*ContextualBanditContext) UnmarshalJSON added in v0.5.0

func (c *ContextualBanditContext) UnmarshalJSON(data []byte) error

UnmarshalJSON never fails: field-level junk zeroes the field, and a non-object context (or one with an unparseable condition) is kept as a malformed marker instead of being dropped, so routing order is preserved.

type ContextualBanditDefinition added in v0.5.0

type ContextualBanditDefinition struct {
	BanditVersion *int                      `json:"banditVersion"`
	Contexts      []ContextualBanditContext `json:"contexts"`
	// contains filtered or unexported fields
}

ContextualBanditDefinition holds the per-context variation weights for one contextual bandit, as served in the SDK payload.

func (ContextualBanditDefinition) MarshalJSON added in v0.5.0

func (d ContextualBanditDefinition) MarshalJSON() ([]byte, error)

MarshalJSON emits the definition's current fields, so values modified after decoding serialize what evaluation would use. A falsy definition is the exception: evaluation treats it as missing regardless of its fields, so it serializes as its canonical falsy form, null — emitting fields would turn a dangling ref into a fallback definition on re-decode.

func (*ContextualBanditDefinition) UnmarshalJSON added in v0.5.0

func (d *ContextualBanditDefinition) UnmarshalJSON(data []byte) error

UnmarshalJSON never fails: a junk banditVersion is omitted without dropping the definition, junk contexts decode to none, and a non-object definition is kept, distinguishing JS-falsy values from truthy junk.

type ContextualBanditDefinitions added in v0.5.0

type ContextualBanditDefinitions map[string]ContextualBanditDefinition

ContextualBanditDefinitions maps bandit refs to their definitions.

func ParseContextualBandits added in v0.5.0

func ParseContextualBandits(data []byte) (ContextualBanditDefinitions, error)

ParseContextualBandits strictly parses a contextual bandit definitions blob for manual configuration: unlike the tolerant UnmarshalJSON — which exists for the payload-ingestion boundary, where a bandit blob must never block the feature update it arrived with — a top-level shape that is not a JSON object is reported as an error instead of degrading to an empty map. Definition- and context-level junk still degrades per entry at evaluation time, exactly as payload-served definitions do.

func (*ContextualBanditDefinitions) UnmarshalJSON added in v0.5.0

func (defs *ContextualBanditDefinitions) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes leniently: a bandit blob the SDK cannot parse (e.g. a future schema) must not block the feature update it arrived with. Definition- and context-level junk degrades per entry at evaluation time; map-level junk yields an empty map, so every ref dangles (debug-logged at use). Manual callers who want a top-level shape error instead should use ParseContextualBandits.

type DataSource added in v0.2.0

type DataSource interface {
	Start(context.Context) error
	Close() error
}

type EventLogger added in v0.3.0

type EventLogger func(ctx context.Context, eventName string, properties EventProperties, userCtx *EventUserContext)

EventLogger is invoked by Client.LogEvent for every custom event. Implementations should return quickly (e.g. by enqueueing work); panics are recovered by the caller.

type EventLoggerPlugin added in v0.3.0

type EventLoggerPlugin interface {
	OnEvent(ctx context.Context, eventName string, properties EventProperties, userCtx *EventUserContext)
}

EventLoggerPlugin is an optional interface a Plugin can implement to receive events from the event-logger channel: custom events from Client.LogEvent and the built-in EventExperimentViewed / EventFeatureEvaluated events for every tracked exposure and feature evaluation. GrowthBookTrackingPlugin implements it, sending events to the GrowthBook ingestor through one batching pipeline.

type EventProperties added in v0.3.0

type EventProperties map[string]any

EventProperties holds the custom properties attached to a logged event.

type EventUserContext added in v0.3.0

type EventUserContext = TrackingUserContext

EventUserContext carries the user context a custom event was logged with: the calling client's attributes and URL. It is the Go equivalent of the userContext argument the JS and Python SDKs pass to their event loggers.

type Experiment

type Experiment struct {
	// The globally unique identifier for the experiment
	Key string `json:"key"`
	// The different variations to choose between
	Variations []FeatureValue `json:"variations"`
	// How to weight traffic between variations. Must add to 1.
	Weights []float64 `json:"weights"`
	// Active determines if the experiment is running. If set to false, always return the control (first variation)
	// If nil (field missing in JSON), the experiment is considered active by default.
	Active *bool `json:"active"`
	// What percent of users should be included in the experiment (between 0 and 1, inclusive)
	Coverage *float64 `json:"coverage"`
	// Array of ranges, one per variation
	Ranges []BucketRange `json:"ranges"`
	// Optional targeting condition
	Condition condition.Base `json:"condition"`
	// Each item defines a prerequisite where a condition must evaluate against a parent feature's value (identified by id).
	ParentConditions []ParentCondition `json:"parentConditions"`
	// Adds the experiment to a namespace
	Namespace *Namespace `json:"namespace"`
	// All users included in the experiment will be forced into the specific variation index
	Force *int `json:"force"`
	// What user attribute should be used to assign variations (defaults to id)
	HashAttribute string `json:"hashAttribute"`
	// When using sticky bucketing, can be used as a fallback to assign variations
	FallbackAttribute string `json:"fallbackAttribute"`
	// The hash version to use (default to 1)
	HashVersion int `json:"hashVersion"`
	// Meta info about the variations
	Meta []VariationMeta `json:"meta"`
	// Array of filters to apply
	Filters []Filter `json:"filters"`
	// The hash seed to use
	Seed string `json:"seed"`
	// Human-readable name for the experiment
	Name string `json:"name"`
	// Id of the current experiment phase
	Phase string `json:"phase"`
	// If true, sticky bucketing will be disabled for this experiment.
	// (Note: sticky bucketing is only available if a StickyBucketingService is provided in the Context)
	DisableStickyBucketing bool `json:"disableStickyBucketing"`
	// An sticky bucket version number that can be used to force a re-bucketing of users (default to 0)
	BucketVersion int `json:"bucketVersion"`
	// Any users with a sticky bucket version less than this will be excluded from the experiment
	MinBucketVersion int `json:"minBucketVersion"`
	// URL patterns to restrict where the experiment runs. Empty means no URL restriction.
	URLPatterns []URLTarget `json:"urlPatterns"`
	// Legacy URL regex to restrict where the experiment runs. Empty means no URL restriction.
	URL string `json:"url"`
	// Legacy group names — user must belong to at least one matching group (Client.WithGroups).
	// Distinct from saved groups, which power $inGroup conditions.
	Groups []string `json:"groups"`
	// Status controls eval: "draft" is skipped unless qaMode/forced, "stopped" only honors Force, "running" is normal.
	Status ExperimentStatus `json:"status"`
	// ContextualBandit is set during evaluation when a contextual bandit
	// decided this experiment's weights.
	ContextualBandit *ContextualBanditAssignment `json:"contextualBandit,omitempty"`
}

Experiment defines a single experiment.

func NewExperiment

func NewExperiment(key string) *Experiment

NewExperiment creates an experiment with default settings: active, but all other fields empty.

func (*Experiment) IsActive added in v0.2.2

func (e *Experiment) IsActive() bool

IsActive returns whether the experiment is active. Experiments are considered active by default (when Active field is nil).

type ExperimentCallback

type ExperimentCallback func(context.Context, *Experiment, *ExperimentResult, *TrackingUserContext, any)

ExperimentCallback function that is executed every time a user is included in an Experiment, with the user context the evaluation ran with.

type ExperimentResult

type ExperimentResult struct {
	// Whether or not the user is part of the experiment
	InExperiment bool `json:"inExperiment"`
	// The array index of the assigned variation
	VariationId int `json:"variationId"`
	// The array value of the assigned variation
	Value FeatureValue `json:"value"`
	// If a hash was used to assign a variation
	HashUsed bool `json:"hashUsed"`
	// The user attribute used to assign a variation
	HashAttribute string `json:"hashAttribute"`
	// The value of hash attribute
	HashValue string `json:"hashValue"`
	// The id of the feature (if any) that the experiment came from
	FeatureId string `json:"featureId"`
	// The unique key for the assigned variation
	Key string `json:"key"`
	// The hash value used to assign a variation (float from 0 to 1)
	Bucket *float64 `json:"bucket"`
	// The human-readable name of the assigned variation
	Name string `json:"name"`
	// Used for holdout groups
	Passthrough bool `json:"passthrough"`
	// If sticky bucketing was used to assign a variation
	StickyBucketUsed bool `json:"stickyBucketUsed"`
	// The contextual bandit leaf used for this assignment
	LeafId *int `json:"leafId,omitempty"`
	// The variation weights the contextual bandit assigned with
	VariationWeights []float64 `json:"variationWeights,omitempty"`
	// The version of the contextual bandit definition used
	BanditVersion *int `json:"banditVersion,omitempty"`
}

type ExperimentStatus added in v0.1.4

type ExperimentStatus string
const (
	DraftStatus   ExperimentStatus = "draft"
	RunningStatus ExperimentStatus = "running"
	StoppedStatus ExperimentStatus = "stopped"
)

type ExperimentSubscriber added in v0.2.9

type ExperimentSubscriber func(ctx context.Context, exp *Experiment, result *ExperimentResult)

ExperimentSubscriber is invoked when an experiment assignment changes.

type Feature

type Feature struct {
	// DefaultValue is optional default value
	DefaultValue FeatureValue `json:"defaultValue"`
	//Rules determine when and how the [DefaultValue] gets overridden
	Rules []FeatureRule `json:"rules"`
}

Feature has a default value plus rules than can override the default.

type FeatureApiResponse added in v0.2.0

type FeatureApiResponse struct {
	Status                     int                         `json:"status"`
	Features                   FeatureMap                  `json:"features"`
	DateUpdated                time.Time                   `json:"dateUpdated"`
	SavedGroups                condition.SavedGroups       `json:"savedGroups"`
	EncryptedFeatures          string                      `json:"encryptedFeatures"`
	ContextualBandits          ContextualBanditDefinitions `json:"contextualBandits"`
	EncryptedContextualBandits string                      `json:"encryptedContextualBandits"`
	SseSupport                 bool
	Etag                       string
}

type FeatureMap

type FeatureMap map[string]*Feature

Map of Feature. Keys are string ids for the features. Values are pointers to Feature structs.

type FeatureResult

type FeatureResult struct {
	RuleId           string              `json:"ruleId"`
	Value            FeatureValue        `json:"value"`
	Source           FeatureResultSource `json:"source"`
	On               bool                `json:"on"`
	Off              bool                `json:"off"`
	Experiment       *Experiment         `json:"experiment"`
	ExperimentResult *ExperimentResult   `json:"experimentResult"`
}

FeatureResult is the result of evaluating a feature.

func (*FeatureResult) InExperiment added in v0.2.0

func (res *FeatureResult) InExperiment() bool

type FeatureResultSource

type FeatureResultSource string

FeatureResultSource is an enumerated type representing the source of a FeatureResult.

const (
	UnknownFeatureResultSource     FeatureResultSource = "unknownFeature"
	DefaultValueResultSource       FeatureResultSource = "defaultValue"
	ForceResultSource              FeatureResultSource = "force"
	ExperimentResultSource         FeatureResultSource = "experiment"
	OverrideResultSource           FeatureResultSource = "override"
	PrerequisiteResultSource       FeatureResultSource = "prerequisite"
	CyclicPrerequisiteResultSource FeatureResultSource = "cyclicPrerequisite"
)

FeatureResultSource values.

type FeatureRule

type FeatureRule struct {
	// Optional rule id, reserved for future use
	Id string `json:"id"`
	// Optional targeting condition
	Condition condition.Base `json:"condition"`
	// Each item defines a prerequisite where a condition must evaluate against a parent feature's value (identified by id).
	// If gate is true, then this is a blocking feature-level prerequisite; otherwise it applies to the current rule only.
	ParentConditions []ParentCondition `json:"parentConditions"`
	// What percent of users should be included in the experiment (between 0 and 1, inclusive)
	Coverage *float64 `json:"coverage"`
	// Immediately force a specific value (ignore every other option besides condition and coverage)
	Force FeatureValue `json:"force"`
	// Run an experiment (A/B test) and randomly choose between these variations
	Variations []FeatureValue `json:"variations"`
	// The globally unique tracking key for the experiment (default to the feature key)
	Key string `json:"key"`
	// How to weight traffic between variations. Must add to 1.
	Weights []float64 `json:"weights"`
	// Adds the experiment to a namespace
	Namespace *Namespace `json:"namespace"`
	// What user attribute should be used to assign variations (defaults to id)
	HashAttribute string `json:"hashAttribute"`
	// When using sticky bucketing, can be used as a fallback to assign variations
	FallbackAttribute string `json:"fallbackAttribute"`
	// If true, sticky bucketing will be disabled for this experiment.
	DisableStickyBucketing bool `json:"disableStickyBucketing"`
	// The hash version to use (default to 1)
	HashVersion int `json:"hashVersion"`
	// An sticky bucket version number that can be used to force a re-bucketing of users (default to 0)
	BucketVersion int `json:"bucketVersion"`
	// Any users with a sticky bucket version less than this will be excluded from the experiment
	MinBucketVersion int `json:"minBucketVersion"`
	// A more precise version of coverage
	Range *BucketRange `json:"range"`
	// Ranges for experiment variations
	Ranges []BucketRange `json:"ranges"`
	// Meta info about the experiment variations
	Meta []VariationMeta `json:"meta"`
	// Slice of filters to apply to the rule
	Filters []Filter `json:"filters"`
	// Seed to use for hashing
	Seed string `json:"seed"`
	//Human-readable name for the experiment
	Name string `json:"name"`
	// The phase id of the experiment
	Phase string `json:"phase"`
	// Reference to a contextual bandit definition in the payload
	ContextualBanditRef string `json:"contextualBanditRef"`
	// Variations for a contextual bandit rule, carried separately from
	// Variations so SDKs without bandit support skip the rule
	ContextualVariations []FeatureValue `json:"contextualVariations"`
	// Deprecated: ignored during evaluation. Feature rules never carried URL
	// targeting in the JS SDK; use Experiment.URLPatterns with RunExperiment.
	URLPatterns []URLTarget `json:"urlPatterns"`
	// Deprecated: ignored during evaluation. Feature rules never carried URL
	// targeting in the JS SDK; use Experiment.URL with RunExperiment.
	URL string `json:"url"`
	// Deprecated: ignored during evaluation. Feature rules never carried group
	// targeting in the JS SDK; use Experiment.Groups with RunExperiment.
	Groups []string `json:"groups"`
	// Deprecated: ignored during evaluation. Feature rules never carried a
	// status in the JS SDK; use Experiment.Status with RunExperiment.
	Status ExperimentStatus `json:"status"`
	// contains filtered or unexported fields
}

func (FeatureRule) MarshalJSON added in v0.5.0

func (r FeatureRule) MarshalJSON() ([]byte, error)

MarshalJSON omits an absent force so a marshal/unmarshal round trip does not turn every rule into a force-null rule.

func (*FeatureRule) UnmarshalJSON added in v0.5.0

func (r *FeatureRule) UnmarshalJSON(data []byte) error

type FeatureUsageCallback added in v0.1.4

type FeatureUsageCallback func(context.Context, string, *FeatureResult, any)

FeatureUsageCallback funcion is executed every time feature is evaluated

type FeatureValue

type FeatureValue any

FeatureValue is a wrapper around an arbitrary type representing the value of a feature.

type Filter added in v0.1.4

type Filter struct {
	Seed        string        `json:"seed"`
	Ranges      []BucketRange `json:"ranges"`
	Attribute   string        `json:"attribute"`
	HashVersion int           `json:"hashVersion"`
}

Filter represents a filter condition for experiment mutual exclusion.

type ForcedVariationsMap

type ForcedVariationsMap map[string]int

ForcedVariationsMap is a map that forces an Experiment to always assign a specific variation. Useful for QA.

type GrowthBookTrackingPlugin added in v0.2.8

type GrowthBookTrackingPlugin struct {
	// contains filtered or unexported fields
}

GrowthBookTrackingPlugin sends experiment and feature evaluation events to the GrowthBook ingestor for warehouse analytics.

func NewGrowthBookTrackingPlugin added in v0.2.8

func NewGrowthBookTrackingPlugin(config TrackingPluginConfig) *GrowthBookTrackingPlugin

NewGrowthBookTrackingPlugin creates a new tracking plugin with the given configuration. The plugin must be passed to WithPlugins or WithGrowthBookTracking when creating a client.

func (*GrowthBookTrackingPlugin) Close added in v0.2.8

func (p *GrowthBookTrackingPlugin) Close() error

Close flushes any remaining events and releases resources. Safe to call multiple times.

func (*GrowthBookTrackingPlugin) Init added in v0.2.8

func (p *GrowthBookTrackingPlugin) Init(client *Client) error

Init initializes the plugin with the client's configuration. If initialization fails the plugin remains uninitialised and all tracking calls become no-ops — SDK evaluation is never affected.

func (*GrowthBookTrackingPlugin) OnEvent added in v0.3.0

func (p *GrowthBookTrackingPlugin) OnEvent(ctx context.Context, eventName string, properties EventProperties, userCtx *EventUserContext)

OnEvent enqueues an event from the client's event-logger dispatch: the built-in Experiment Viewed / Feature Evaluated events and custom events logged via Client.LogEvent. The payload mirrors the EventPayload shape used by the JS and Python tracking plugins (sdk-js plugins/growthbook-tracking.ts getEventPayload). No-op if the plugin was not successfully initialized.

func (*GrowthBookTrackingPlugin) OnExperimentViewed added in v0.2.8

func (p *GrowthBookTrackingPlugin) OnExperimentViewed(ctx context.Context, experiment *Experiment, result *ExperimentResult)

OnExperimentViewed is a no-op: built-in "Experiment Viewed" events arrive via OnEvent through the client's event-logger dispatch, which carries the user context the ingestor payload needs. Retained to satisfy the Plugin interface.

func (*GrowthBookTrackingPlugin) OnFeatureEvaluated added in v0.2.8

func (p *GrowthBookTrackingPlugin) OnFeatureEvaluated(ctx context.Context, featureKey string, result *FeatureResult)

OnFeatureEvaluated is a no-op: built-in "Feature Evaluated" events arrive via OnEvent through the client's event-logger dispatch. Retained to satisfy the Plugin interface.

type InMemoryStickyBucketService added in v0.2.3

type InMemoryStickyBucketService struct {
	// contains filtered or unexported fields
}

InMemoryStickyBucketService provides a simple in-memory implementation of StickyBucketService

func NewInMemoryStickyBucketService added in v0.2.3

func NewInMemoryStickyBucketService() *InMemoryStickyBucketService

NewInMemoryStickyBucketService creates a new in-memory sticky bucket service

func (*InMemoryStickyBucketService) Destroy added in v0.2.3

func (s *InMemoryStickyBucketService) Destroy()

Destroy clears all stored assignments

func (*InMemoryStickyBucketService) GetAllAssignments added in v0.2.3

func (s *InMemoryStickyBucketService) GetAllAssignments(attributes map[string]string) (StickyBucketAssignments, error)

GetAllAssignments retrieves all assignments for the provided attributes

func (*InMemoryStickyBucketService) GetAssignments added in v0.2.3

func (s *InMemoryStickyBucketService) GetAssignments(attributeName, attributeValue string) (*StickyBucketAssignmentDoc, error)

GetAssignments retrieves assignments for a specific attribute

func (*InMemoryStickyBucketService) SaveAssignments added in v0.2.3

SaveAssignments stores assignments for a specific attribute

type Namespace

type Namespace struct {
	Id    string
	Start float64
	End   float64
}

Namespace specifies what part of a namespace an experiment includes. If two experiments are in the same namespace and their ranges don't overlap, they wil be mutually exclusive.

func (Namespace) MarshalJSON added in v0.4.0

func (namespace Namespace) MarshalJSON() ([]byte, error)

func (*Namespace) UnmarshalJSON added in v0.2.0

func (namespace *Namespace) UnmarshalJSON(data []byte) error

type ParentCondition added in v0.2.0

type ParentCondition struct {
	Id        string         `json:"id"`
	Condition condition.Base `json:"condition"`
	Gate      bool           `json:"gate"`
}

type Plugin added in v0.2.8

type Plugin interface {
	// Init is called after the client is fully configured. The plugin
	// receives a reference to the client and may read configuration
	// from it (e.g., ClientKey). Returning an error marks the plugin
	// as failed; the client logs the error and continues. The client
	// will still call OnExperimentViewed, OnFeatureEvaluated, and
	// Close on a failed plugin.
	Init(client *Client) error

	// OnExperimentViewed is called when a user is included in an
	// experiment. Implementations should return quickly (e.g., by
	// enqueueing work). Panics are recovered by the caller.
	// Must be a no-op when Init returned an error.
	OnExperimentViewed(ctx context.Context, experiment *Experiment, result *ExperimentResult)

	// OnFeatureEvaluated is called every time a feature is evaluated.
	// Implementations should return quickly. Panics are recovered by
	// the caller.
	// Must be a no-op when Init returned an error.
	OnFeatureEvaluated(ctx context.Context, featureKey string, result *FeatureResult)

	// Close performs cleanup. For tracking plugins this means flushing
	// any remaining events. Close must be safe to call multiple times
	// and must be safe to call when Init returned an error.
	Close() error
}

Plugin is an interface for extending the GrowthBook client with additional behavior such as tracking. Plugins are initialized when the client is created and closed when the client is closed.

Contract for implementors: OnExperimentViewed, OnFeatureEvaluated, and Close MUST be safe to call even when Init returned an error. The client keeps failed plugins in its list and will still call these methods — guard your implementation accordingly.

type PollDataSource added in v0.2.0

type PollDataSource struct {
	// contains filtered or unexported fields
}

func (*PollDataSource) Close added in v0.2.0

func (ds *PollDataSource) Close() error

func (*PollDataSource) Start added in v0.2.0

func (ds *PollDataSource) Start(ctx context.Context) error

type SseDataSource added in v0.2.0

type SseDataSource struct {
	// contains filtered or unexported fields
}

func (*SseDataSource) Close added in v0.2.0

func (ds *SseDataSource) Close() error

func (*SseDataSource) Start added in v0.2.0

func (ds *SseDataSource) Start(ctx context.Context) error

type SseOption added in v0.3.0

type SseOption func(*SseDataSource)

SseOption configures an SseDataSource.

func WithSseMaxRetryInterval added in v0.3.0

func WithSseMaxRetryInterval(d time.Duration) SseOption

WithSseMaxRetryInterval sets the maximum backoff interval between reconnection attempts. Non-positive values keep the default cap.

type StickyBucketAssignmentData added in v0.2.3

type StickyBucketAssignmentData struct {
	Key     string
	Doc     *StickyBucketAssignmentDoc
	Changed bool
}

StickyBucketAssignmentData is used when generating sticky bucket assignments

func GenerateStickyBucketAssignmentDoc added in v0.2.3

func GenerateStickyBucketAssignmentDoc(
	attributeName string,
	attributeValue string,
	assignments map[string]string,
	service StickyBucketService,
) *StickyBucketAssignmentData

GenerateStickyBucketAssignmentDoc creates or updates a sticky bucket assignment document

type StickyBucketAssignmentDoc added in v0.2.3

type StickyBucketAssignmentDoc struct {
	AttributeName  string            `json:"attributeName"`
	AttributeValue string            `json:"attributeValue"`
	Assignments    map[string]string `json:"assignments"`
}

StickyBucketAssignmentDoc represents a document storing assignment data

type StickyBucketAssignments added in v0.2.3

type StickyBucketAssignments map[string]*StickyBucketAssignmentDoc

StickyBucketAssignments is a map of keys to assignment documents

type StickyBucketAttributes added in v0.2.3

type StickyBucketAttributes map[string]string

StickyBucketAttributes is a map of attribute names to attribute values

type StickyBucketResult added in v0.2.3

type StickyBucketResult struct {
	Variation        int
	VersionIsBlocked bool
}

StickyBucketResult holds the result of a sticky bucket lookup

func GetStickyBucketVariation added in v0.2.3

func GetStickyBucketVariation(
	experimentKey string,
	bucketVersion int,
	minBucketVersion int,
	meta []VariationMeta,
	service StickyBucketService,
	hashAttribute string,
	fallbackAttribute string,
	attributes map[string]string,
	cachedAssignments StickyBucketAssignments,
) (*StickyBucketResult, error)

GetStickyBucketVariation retrieves an existing sticky bucket assignment

type StickyBucketService added in v0.2.3

type StickyBucketService interface {
	GetAssignments(attributeName string, attributeValue string) (*StickyBucketAssignmentDoc, error)
	SaveAssignments(doc *StickyBucketAssignmentDoc) error
	GetAllAssignments(attributes map[string]string) (StickyBucketAssignments, error)
}

StickyBucketService defines operations for storing and retrieving sticky bucket assignments

type TrackingBuffer added in v0.5.0

type TrackingBuffer struct {
	// contains filtered or unexported fields
}

TrackingBuffer accumulates experiment exposures across evaluations, deduplicated for the buffer's lifetime, in first-seen order. Attach one to a client with WithTrackingBuffer; every client sharing the buffer (clones included) collects into it. Safe for concurrent use; the zero value is ready to use.

A TrackingBuffer must not be copied after first use: a copy would share the buffered state while holding an independent mutex. Share it by pointer, as WithTrackingBuffer does (`go vet`'s copylocks check flags value copies).

func NewTrackingBuffer added in v0.5.0

func NewTrackingBuffer() *TrackingBuffer

NewTrackingBuffer creates an empty tracking buffer.

func (*TrackingBuffer) Clear added in v0.5.0

func (b *TrackingBuffer) Clear()

Clear empties the buffer, including its dedupe memory: a subsequent exposure identical to one seen before Clear is recorded again. For the intended request-scoped lifecycle (one buffer per request, read once, then cleared or dropped) this never matters.

func (*TrackingBuffer) TakeTrackingCalls added in v0.5.0

func (b *TrackingBuffer) TakeTrackingCalls() []TrackingData

TakeTrackingCalls atomically returns the buffered exposures and empties the buffer — the drain form of TrackingCalls followed by Clear. Unlike calling those two separately, an exposure recorded concurrently can never be cleared without having been returned, so a long-lived shared buffer can be drained in a loop without losing exposures. Like Clear, it forgets the dedupe memory: a later identical exposure is recorded again.

func (*TrackingBuffer) TrackingCalls added in v0.5.0

func (b *TrackingBuffer) TrackingCalls() []TrackingData

TrackingCalls returns the exposures buffered so far — passthrough and prerequisite assignments included, in first-seen order — as detached copies in the SDK's JSON shape, safe to retain or mutate without affecting the buffer. It does not drain the buffer; pair with Clear.

type TrackingData added in v0.4.0

type TrackingData struct {
	Experiment *Experiment          `json:"experiment"`
	Result     *ExperimentResult    `json:"result"`
	User       *TrackingUserContext `json:"user,omitempty"`
}

TrackingData is a single experiment exposure, in the JSON shape client SDKs accept as deferred tracking calls. It holds its own copies of the experiment and result, snapshotted at evaluation time.

func (TrackingData) DedupeKey deprecated added in v0.4.0

func (t TrackingData) DedupeKey() string

DedupeKey identifies an exposure by hash attribute, hash value, experiment key, and variation.

Deprecated: informational only. The SDK no longer dedupes on this string — field values containing the NUL delimiter can make two distinct exposures share a key. Internal deduplication uses a field-wise comparable key that cannot collide.

type TrackingPluginConfig added in v0.2.8

type TrackingPluginConfig struct {
	// IngestorHost is the GrowthBook event ingestor endpoint.
	// Defaults to "https://us1.gb-ingest.com".
	IngestorHost string

	// BatchSize is the maximum number of events to accumulate before
	// flushing. Defaults to 100.
	BatchSize int

	// BatchTimeout is the maximum time to wait before flushing
	// accumulated events. Defaults to 10 seconds.
	BatchTimeout time.Duration

	// HTTPClient is used for sending events. If nil, the client's
	// HTTP client is used (which defaults to http.DefaultClient).
	HTTPClient *http.Client

	// Logger is used for error logging. If nil, the client's logger
	// is used.
	Logger *slog.Logger
}

TrackingPluginConfig configures the GrowthBookTrackingPlugin.

type TrackingUserContext added in v0.4.0

type TrackingUserContext struct {
	Attributes Attributes `json:"attributes"`
	URL        string     `json:"url,omitempty"`
}

TrackingUserContext is the user context an evaluation ran with — the evaluating client's attributes and URL. It is passed to ExperimentCallback and carried on TrackingData, mirroring the JS SDK type of the same name.

type URLTarget added in v0.1.4

type URLTarget struct {
	Type    URLTargetType `json:"type"`
	Pattern string        `json:"pattern"`
	Include *bool         `json:"include"`
}

URLTarget represents one URL targeting rule on an Experiment or FeatureRule. A nil Include is treated as include=true.

type URLTargetType added in v0.1.4

type URLTargetType string

URLTargetType is the type of an URLTarget pattern.

const (
	URLTargetSimple URLTargetType = "simple"
	URLTargetRegex  URLTargetType = "regex"
)

type VariationMeta added in v0.1.4

type VariationMeta struct {
	// Key is a unique key for this variation.
	Key string `json:"key"`
	// Name is a human-readable name for this variation.
	Name string `json:"name"`
	// Passthrough used to implement holdout groups
	Passthrough bool `json:"passthrough"`
}

VariationMeta info about an experiment variation.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL