Official Go SDK for SetBit - Simple feature flags and A/B testing.
- β Boolean Flags - Simple on/off feature toggles
- π§ͺ A/B Testing - Weighted variant distribution for experiments
- π Conversion Tracking - Track events and conversions
- π·οΈ Tag-Based Targeting - Target by environment, app, team, region, etc.
- π Fail-Open Design - Returns defaults if API is unreachable
- πͺΆ Lightweight - Zero dependencies (uses only Go standard library)
- β‘ Fast - Built-in HTTP connection pooling and timeouts
go get github.com/setbit-io/setbit-gopackage main
import (
"log"
"github.com/setbit-io/setbit-go"
)
func main() {
// Initialize the client
client, err := setbit.NewClient(setbit.Config{
APIKey: "pk_your_api_key_here",
Tags: map[string]string{
"env": "production",
"app": "web",
},
})
if err != nil {
log.Fatal(err)
}
// Check a boolean flag (user ID required for analytics)
userID := getCurrentUserID()
if client.Enabled("new-checkout", userID, false) {
showNewCheckout()
} else {
showOldCheckout()
}
// Get A/B test variant
variant := client.Variant("pricing-experiment", userID, "control")
switch variant {
case "variant_a":
showPrice99()
case "variant_b":
showPrice149()
default:
showPrice129()
}
// Track conversions (pass variant for proper attribution)
client.Track("purchase", userID, setbit.TrackOptions{
FlagName: "pricing-experiment",
Variant: variant,
Metadata: map[string]interface{}{
"amount": 99.99,
},
})
}client, err := setbit.NewClient(setbit.Config{
APIKey: "pk_your_api_key",
Tags: map[string]string{
"env": "production",
"app": "web",
"region": "us-east",
},
BaseURL: "https://flags.setbit.io", // Optional, custom endpoint
HTTPClient: &http.Client{}, // Optional, custom HTTP client
Logger: log.New(os.Stdout, "setbit: ", 0), // Optional, custom logger
})Config Parameters:
APIKey(string, required): Your SetBit API keyTags(map[string]string, optional): Tags for targeting flagsBaseURL(string, optional): API endpoint URL (useful for self-hosted instances)HTTPClient(*http.Client, optional): Custom HTTP clientLogger(*log.Logger, optional): Custom logger (silent by default)
Returns:
*Client: SetBit client instanceerror: Error if configuration is invalid (e.g., missing API key)
Check if a flag is enabled. Returns true if the flag is globally enabled, false otherwise.
Parameters:
flagName(string): Name of the flaguserID(string, required): User identifier (required for analytics and billing)defaultValue(bool): Value to return if flag not found (default behavior on error)
Returns: bool - true if enabled, false otherwise
Note: This method returns whether the flag is globally enabled. For rollout flags, use Variant() to check which rollout group the user is in.
Example:
// Check if flag is enabled
if client.Enabled("new-feature", userID, false) {
// Show new feature
}
// With default true (fail open)
if client.Enabled("beta-access", userID, true) {
// Grant beta access
}Get the variant for an A/B test experiment or percentage rollout.
Parameters:
flagName(string): Name of the experiment flaguserID(string, required): User identifierdefaultVariant(string): Default variant if flag not found (e.g., "control")
Returns: string - Variant name (e.g., "control", "variant_a", "variant_b")
Note: Returns the defaultVariant if the flag is disabled or API is unreachable.
Example:
// A/B test
variant := client.Variant("pricing-experiment", userID, "control")
switch variant {
case "variant_a":
// Show variant A
case "variant_b":
// Show variant B
default:
// Show control
}
// Percentage rollout
variant := client.Variant("new-api-rollout", userID, "control")
if variant == "enabled" {
useNewAPI()
} else {
useOldAPI()
}Track a conversion event or user action.
Parameters:
eventName(string): Name of the event (e.g., "purchase", "signup", "click")userID(string, required): User identifieropts(TrackOptions): Optional tracking optionsFlagName(string): Flag name to associate with eventVariant(string): Variant the user was assigned to (for A/B test attribution)Metadata(map[string]interface{}): Additional metadata
Returns: Nothing (fails silently, logs errors)
Example:
// Track conversion with variant attribution (recommended for A/B tests)
variant := client.Variant("pricing-experiment", userID, "control")
// ... later when user converts ...
client.Track("purchase", userID, setbit.TrackOptions{
FlagName: "pricing-experiment",
Variant: variant,
Metadata: map[string]interface{}{
"amount": 99.99,
"currency": "USD",
},
})
// Track without flag association
client.Track("signup", userID, setbit.TrackOptions{
Metadata: map[string]interface{}{
"source": "organic",
},
})
// Track simple event
client.Track("button_click", userID, setbit.TrackOptions{})customClient := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
},
}
client, _ := setbit.NewClient(setbit.Config{
APIKey: "pk_your_api_key",
HTTPClient: customClient,
})logger := log.New(os.Stdout, "setbit: ", log.LstdFlags)
client, _ := setbit.NewClient(setbit.Config{
APIKey: "pk_your_api_key",
Logger: logger,
})client, _ := setbit.NewClient(setbit.Config{
APIKey: "pk_your_api_key",
BaseURL: "https://flags.yourcompany.com",
})The SDK is designed to fail open - if the API is unreachable or returns an error, methods return the specified default values rather than blocking your application.
// If API fails, returns false (safe default)
enabled := client.Enabled("risky-feature", userID, false)
// If API fails, returns "control" (safe default)
variant := client.Variant("experiment", userID, "control")
// Track fails silently (logs error but doesn't block)
client.Track("event", userID, setbit.TrackOptions{})Always provide a user ID for all flag evaluations. This is required for:
- Analytics and reporting
- Billing (MAU tracking)
- Consistent variant assignment in A/B tests
// β
Good - user ID provided
if client.Enabled("feature", userID, false) {
// ...
}
// β Bad - empty user ID
if client.Enabled("feature", "", false) {
// This will still work but won't be tracked properly
}// For new features, default to false (conservative)
if client.Enabled("experimental-feature", userID, false) {
// Only enable if API confirms
}
// For stable features, default to true (progressive)
if client.Enabled("stable-feature", userID, true) {
// Enable even if API is down
}Create one client instance and reuse it throughout your application:
// Initialize once
var flagClient *setbit.Client
func init() {
var err error
flagClient, err = setbit.NewClient(setbit.Config{
APIKey: os.Getenv("SETBIT_API_KEY"),
Tags: map[string]string{
"env": os.Getenv("ENV"),
},
})
if err != nil {
log.Fatal(err)
}
}
// Reuse everywhere
func handler(w http.ResponseWriter, r *http.Request) {
if flagClient.Enabled("feature", getUserID(r), false) {
// ...
}
}client, _ := setbit.NewClient(setbit.Config{
APIKey: "pk_your_api_key",
Tags: map[string]string{
"env": "production", // Environment
"app": "api", // Application/service name
"team": "backend", // Team ownership
"region": "us-east-1", // Geographic region
},
})Run the test suite:
go test -vRun tests with coverage:
go test -v -coverSee example.go for a complete working example.
Run the example:
go run example.go- Go 1.21 or higher
- No external dependencies (uses only Go standard library)
MIT License - see LICENSE file for details
- π Documentation
- π¬ GitHub Issues
- π§ Email: support@setbit.io
Contributions are welcome! Please feel free to submit a Pull Request.