Skip to content

PostHog/posthog-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

246 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

PostHog Go

Go Reference min. Go Version

Please see the main PostHog docs. See the Go SDK Docs.

Quickstart

Install posthog to your gopath

go get github.com/posthog/posthog-go

Go 🦔!

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
    }
}

Contributing

See CONTRIBUTING.md for local setup, build, and test instructions.

Examples

Check out the examples for more detailed examples of how to use the PostHog Go client.

Running the examples

The examples demonstrate different features of the PostHog Go client. To run all examples:

Option 1: Using .env file (Recommended)

# 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

Option 2: Using environment variables

# 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/*.go

This will run:

  • Feature flags example
  • Capture events example
  • Capture events with feature flag options example

Prerequisites

Before running the examples, you'll need to:

  1. Have a PostHog instance running (default: http://localhost:8000)

    • You can modify the endpoint by setting the POSTHOG_ENDPOINT environment variable
    • If not set, it defaults to "http://localhost:8000"
  2. 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)
  3. Set your PostHog API keys as environment variables:

    • POSTHOG_PROJECT_API_KEY: Your project API key (starts with phc_...)
    • POSTHOG_PERSONAL_API_KEY: Your personal API key (starts with phx_...)

Event Delivery and Retry Behavior

The PostHog Go client includes automatic retry logic for handling transient network failures. Understanding when events are delivered vs dropped helps ensure reliable analytics.

Events Are Delivered (Not Dropped)

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 Are Dropped

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

Configuring Retry Behavior

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
},

Monitoring Event Delivery

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{},
})

Questions?

Packages

 
 
 

Contributors

Languages