Please see the main PostHog docs.
Specifically, the Go integration details.
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", "[email protected]").
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",
))
// 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"))
// 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
}
}Make sure you have Go installed (macOS: brew install go, Linx / Windows: https://go.dev/doc/install).
To build the project:
# Install dependencies
make dependencies
# Run tests and build
make build
# Just run tests
make testYou can run your Go app against a local build of posthog-go by making the following change to your go.mod file for whichever your app, e.g.
module example/posthog-go-app
go 1.22.5
require github.com/posthog/posthog-go v0.0.0-20240327112532-87b23fe11103
require github.com/google/uuid v1.3.0 // indirect
replace github.com/posthog/posthog-go => /path-to-your-local/posthog-goCheck 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_...)
Before creating a release make sure you have installed gh and authenticated via gh auth login
To release a new version of the PostHog Go client, follow these steps:
- Update the version in the
version.gofile - Update the changelog in
CHANGELOG.md - Once your changes are merged into main, create a new tag and release with the new version
git tag v1.4.7
git push --tags
gh release create v1.4.7 --generate-notesReleases are installed directly from GitHub.
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{},
})