Please see the main PostHog docs. See the Go SDK Docs.
Install posthog to your gopath
go get github.com/posthog/posthog-goGo 🦔!
package main
import (
"os"
"github.com/posthog/posthog-go"
)
func main() {
client := posthog.New(os.Getenv("POSTHOG_API_KEY")) // This value must be set to the project API key in PostHog
// alternatively, you can do
// client, _ := posthog.NewWithConfig(
// os.Getenv("POSTHOG_API_KEY"),
// posthog.Config{
// PersonalApiKey: "your personal API key", // Set this to your personal API token you want feature flag evaluation to be more performant. This will incur more costs, though
// Endpoint: "https://us.i.posthog.com",
// },
// )
defer client.Close()
// Capture an event
client.Enqueue(posthog.Capture{
DistinctId: "test-user",
Event: "test-snippet",
Properties: posthog.NewProperties().
Set("plan", "Enterprise").
Set("friends", 42),
})
// Add context for a user
client.Enqueue(posthog.Identify{
DistinctId: "user:123",
Properties: posthog.NewProperties().
Set("email", "john@doe.com").
Set("proUser", false),
})
// Link user contexts
client.Enqueue(posthog.Alias{
DistinctId: "user:123",
Alias: "user:12345",
})
// Capture a pageview
client.Enqueue(posthog.Capture{
DistinctId: "test-user",
Event: "$pageview",
Properties: posthog.NewProperties().
Set("$current_url", "https://example.com"),
})
// Capture an error / exception
client.Enqueue(posthog.NewDefaultException(
time.Now(),
"distinct-id",
"Error title",
"Error Description",
))
// Capture an error with custom properties
client.Enqueue(posthog.Exception{
DistinctId: "distinct-id",
Timestamp: time.Now(),
Properties: posthog.Properties{
"environment": "production",
"retry_count": 3,
},
ExceptionList: []posthog.ExceptionItem{
{Type: "Error title", Value: "Error Description"},
},
})
// Create a logger which automatically captures warning logs and above
baseLogHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})
logger := slog.New(posthog.NewSlogCaptureHandler(baseLogHandler, client,
posthog.WithMinCaptureLevel(slog.LevelWarn),
posthog.WithDistinctIDFn(func(ctx context.Context, r slog.Record) string {
// for demo purposes, real applications should likely pull this value from the context.
return "my-user-id"
}),
})
logger.Warn("Log that something broke", "error", fmt.Errorf("this is a dummy scenario"))
// Optionally forward all slog attributes as event properties
loggerWithProps := slog.New(posthog.NewSlogCaptureHandler(baseLogHandler, client,
posthog.WithDistinctIDFn(func(ctx context.Context, r slog.Record) string {
return "my-user-id"
}),
posthog.WithPropertiesFn(posthog.SlogAttrsAsProperties),
))
loggerWithProps.Error("Payment failed", "payment_id", "pay_123", "amount", 99.99)
// Capture event with calculated uuid to deduplicate repeated events.
// The library github.com/google/uuid is used
key := myEvent.Id + myEvent.Project
uid := uuid.NewSHA1(uuid.NameSpaceX500, []byte(key)).String()
client.Enqueue(posthog.Capture{
Uuid: uid,
DistinctId: "test-user",
Event: "$pageview",
Properties: posthog.NewProperties().
Set("$current_url", "https://example.com"),
})
// Check if a feature flag is enabled
isMyFlagEnabled, err := client.IsFeatureEnabled(
FeatureFlagPayload{
Key: "flag-key",
DistinctId: "distinct_id_of_your_user",
})
if isMyFlagEnabled == true {
// Do something differently for this user
}
}See CONTRIBUTING.md for local setup, build, and test instructions.
Check out the examples for more detailed examples of how to use the PostHog Go client.
The examples demonstrate different features of the PostHog Go client. To run all examples:
# Copy the example .env file and fill in your credentials
cd examples
cp .env.example .env
# Edit .env with your actual API keys
# Run all examples
go run *.go# Set your PostHog API keys and endpoint (optional)
export POSTHOG_PROJECT_API_KEY="your-project-api-key"
export POSTHOG_PERSONAL_API_KEY="your-personal-api-key"
export POSTHOG_ENDPOINT="https://app.posthog.com" # Optional, defaults to http://localhost:8000
# Run all examples
go run examples/*.goThis will run:
- Feature flags example
- Capture events example
- Capture events with feature flag options example
Before running the examples, you'll need to:
-
Have a PostHog instance running (default: http://localhost:8000)
- You can modify the endpoint by setting the
POSTHOG_ENDPOINTenvironment variable - If not set, it defaults to "http://localhost:8000"
- You can modify the endpoint by setting the
-
Set up the following feature flags in your PostHog instance:
multivariate-test(a multivariate flag)simple-test(a simple boolean flag)multivariate-simple-test(a multivariate flag)my_secret_flag_value(a remote config flag with string payload)my_secret_flag_json_object_value(a remote config flag with JSON object payload)my_secret_flag_json_array_value(a remote config flag with JSON array payload)
-
Set your PostHog API keys as environment variables:
POSTHOG_PROJECT_API_KEY: Your project API key (starts withphc_...)POSTHOG_PERSONAL_API_KEY: Your personal API key (starts withphx_...)
The PostHog Go client includes automatic retry logic for handling transient network failures. Understanding when events are delivered vs dropped helps ensure reliable analytics.
The client automatically retries on network errors and will successfully deliver events when:
- Transient network failures - EOF errors, connection resets, TCP drops that recover within retry attempts
- Server temporarily unavailable - If the server starts responding before max retries are exhausted
- Connection drops at any stage - Whether after connect, during headers, or while sending body
Example scenarios that recover successfully:
- Server closes connection without response (EOF) but succeeds on retry
- TCP connection dropped after partial body read
- Temporary network interruption lasting a few seconds
Events will be permanently lost in these scenarios:
| Scenario | Behavior |
|---|---|
| Max retries exceeded | After 10 failed attempts, events are dropped and Failure callback is invoked |
| Client closed during retry | If client.Close() is called while retrying, pending events are dropped |
| Non-retryable errors | JSON marshalling failures cause immediate drop (no retry) |
| HTTP 4xx responses | Client errors (e.g., invalid API key) are not retried |
You can customize retry timing via the RetryAfter config option:
client, _ := posthog.NewWithConfig(
"api-key",
posthog.Config{
RetryAfter: func(attempt int) time.Duration {
// Custom backoff: 100ms, 200ms, 400ms, ...
return time.Duration(100<<attempt) * time.Millisecond
},
},
)To limit the number of retries (default is 9 retries = 10 total attempts):
client, _ := posthog.NewWithConfig(
"api-key",
posthog.Config{
MaxRetries: posthog.Ptr(3), // 3 retries = 4 total attempts
},
)Setting MaxRetries to 0 means only one attempt with no retries (disable retries):
posthog.Config{
MaxRetries: posthog.Ptr(0), // 3 retries = 4 total attempts
},Use the Callback interface to track successes and failures:
type MyCallback struct{}
func (c *MyCallback) Success(msg posthog.APIMessage) {
log.Printf("Event delivered: %v", msg)
}
func (c *MyCallback) Failure(msg posthog.APIMessage, err error) {
log.Printf("Event dropped: %v, error: %v", msg, err)
// Optionally: persist to disk, send to dead-letter queue, etc.
}
client, _ := posthog.NewWithConfig("api-key", posthog.Config{
Callback: &MyCallback{},
})