{"id":20313709,"url":"https://github.com/posthog/posthog-go","last_synced_at":"2026-01-17T16:15:19.182Z","repository":{"id":41183102,"uuid":"242238816","full_name":"PostHog/posthog-go","owner":"PostHog","description":"Official PostHog Go library","archived":false,"fork":false,"pushed_at":"2025-04-02T20:42:12.000Z","size":221,"stargazers_count":27,"open_issues_count":19,"forks_count":22,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-08T12:50:51.879Z","etag":null,"topics":["event-tracking","experimentation","feature-flags","go","golang","official","posthog"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PostHog.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-21T22:05:23.000Z","updated_at":"2025-04-02T19:29:40.000Z","dependencies_parsed_at":"2024-02-21T14:52:38.538Z","dependency_job_id":"6fc1e617-99be-4aec-a911-f9cb86901205","html_url":"https://github.com/PostHog/posthog-go","commit_stats":{"total_commits":56,"total_committers":9,"mean_commits":6.222222222222222,"dds":0.5357142857142857,"last_synced_commit":"24dfed35d71a284119f02403b36423ba4c0c8c0f"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PostHog%2Fposthog-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PostHog%2Fposthog-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PostHog%2Fposthog-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PostHog%2Fposthog-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PostHog","download_url":"https://codeload.github.com/PostHog/posthog-go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248650416,"owners_count":21139672,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["event-tracking","experimentation","feature-flags","go","golang","official","posthog"],"created_at":"2024-11-14T18:12:27.652Z","updated_at":"2026-01-17T16:15:19.161Z","avatar_url":"https://github.com/PostHog.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PostHog Go\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/posthog/posthog-go.svg)](https://pkg.go.dev/github.com/posthog/posthog-go)\n![min. Go Version](https://img.shields.io/github/go-mod/go-version/PostHog/posthog-go?label=min.%20Go%20version%20)\n\nPlease see the main [PostHog docs](https://posthog.com/docs). See the [Go SDK Docs](https://posthog.com/docs/libraries/go).\n\n## Quickstart\n\nInstall posthog to your gopath\n\n```bash\n$ go get github.com/posthog/posthog-go\n```\n\nGo 🦔!\n\n```go\npackage main\n\nimport (\n    \"os\"\n    \"github.com/posthog/posthog-go\"\n)\n\nfunc main() {\n    client := posthog.New(os.Getenv(\"POSTHOG_API_KEY\")) // This value must be set to the project API key in PostHog\n    // alternatively, you can do\n    // client, _ := posthog.NewWithConfig(\n    //     os.Getenv(\"POSTHOG_API_KEY\"),\n    //     posthog.Config{\n    //         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\n    //         Endpoint:       \"https://us.i.posthog.com\",\n    //     },\n    // )\n    defer client.Close()\n\n    // Capture an event\n    client.Enqueue(posthog.Capture{\n      DistinctId: \"test-user\",\n      Event:      \"test-snippet\",\n      Properties: posthog.NewProperties().\n        Set(\"plan\", \"Enterprise\").\n        Set(\"friends\", 42),\n    })\n\n    // Add context for a user\n    client.Enqueue(posthog.Identify{\n      DistinctId: \"user:123\",\n      Properties: posthog.NewProperties().\n        Set(\"email\", \"john@doe.com\").\n        Set(\"proUser\", false),\n    })\n\n    // Link user contexts\n    client.Enqueue(posthog.Alias{\n      DistinctId: \"user:123\",\n      Alias: \"user:12345\",\n    })\n\n    // Capture a pageview\n    client.Enqueue(posthog.Capture{\n      DistinctId: \"test-user\",\n      Event:      \"$pageview\",\n      Properties: posthog.NewProperties().\n        Set(\"$current_url\", \"https://example.com\"),\n    })\n\n    // Capture an error / exception\n    client.Enqueue(posthog.NewDefaultException(\n      time.Now(),\n      \"distinct-id\",\n      \"Error title\",\n      \"Error Description\",\n    ))\n\n    // Create a logger which automatically captures warning logs and above\n    baseLogHandler := slog.NewTextHandler(os.Stdout, \u0026slog.HandlerOptions{Level: slog.LevelInfo})\n    logger := slog.New(posthog.NewSlogCaptureHandler(baseLogHandler, client,\n      posthog.WithMinCaptureLevel(slog.LevelWarn),\n      posthog.WithDistinctIDFn(func(ctx context.Context, r slog.Record) string {\n        // for demo purposes, real applications should likely pull this value from the context.\n        return \"my-user-id\"\n      }),\n    })\n    logger.Warn(\"Log that something broke\", \"error\", fmt.Errorf(\"this is a dummy scenario\"))\n\n    // Capture event with calculated uuid to deduplicate repeated events.\n    // The library github.com/google/uuid is used\n    key := myEvent.Id + myEvent.Project\n    uid := uuid.NewSHA1(uuid.NameSpaceX500, []byte(key)).String()\n    client.Enqueue(posthog.Capture{\n      Uuid: uid,\n      DistinctId: \"test-user\",\n      Event:      \"$pageview\",\n      Properties: posthog.NewProperties().\n        Set(\"$current_url\", \"https://example.com\"),\n    })\n\n    // Check if a feature flag is enabled\n    isMyFlagEnabled, err := client.IsFeatureEnabled(\n            FeatureFlagPayload{\n                Key:        \"flag-key\",\n                DistinctId: \"distinct_id_of_your_user\",\n            })\n\n    if isMyFlagEnabled == true {\n        // Do something differently for this user\n    }\n}\n```\n\n## Development\n\nMake sure you have Go installed (macOS: `brew install go`, Linx / Windows: https://go.dev/doc/install).\n\nTo build the project:\n\n```bash\n# Install dependencies\nmake dependencies\n\n# Run tests and build\nmake build\n\n# Just run tests\nmake test\n```\n\n## Testing Locally\n\nYou 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.\n\n```Go\nmodule example/posthog-go-app\n\ngo 1.22.5\n\nrequire github.com/posthog/posthog-go v0.0.0-20240327112532-87b23fe11103\n\nrequire github.com/google/uuid v1.3.0 // indirect\n\nreplace github.com/posthog/posthog-go =\u003e /path-to-your-local/posthog-go\n```\n\n## Examples\n\nCheck out the [examples](examples/README.md) for more detailed examples of how to use the PostHog Go client.\n\n## Running the examples\n\nThe examples demonstrate different features of the PostHog Go client. To run all examples:\n\n### Option 1: Using .env file (Recommended)\n\n```bash\n# Copy the example .env file and fill in your credentials\ncd examples\ncp .env.example .env\n# Edit .env with your actual API keys\n\n# Run all examples\ngo run *.go\n```\n\n### Option 2: Using environment variables\n\n```bash\n# Set your PostHog API keys and endpoint (optional)\nexport POSTHOG_PROJECT_API_KEY=\"your-project-api-key\"\nexport POSTHOG_PERSONAL_API_KEY=\"your-personal-api-key\"\nexport POSTHOG_ENDPOINT=\"https://app.posthog.com\"  # Optional, defaults to http://localhost:8000\n\n# Run all examples\ngo run examples/*.go\n```\n\nThis will run:\n\n- Feature flags example\n- Capture events example\n- Capture events with feature flag options example\n\n### Prerequisites\n\nBefore running the examples, you'll need to:\n\n1. Have a PostHog instance running (default: http://localhost:8000)\n\n   - You can modify the endpoint by setting the `POSTHOG_ENDPOINT` environment variable\n   - If not set, it defaults to \"http://localhost:8000\"\n\n2. Set up the following feature flags in your PostHog instance:\n\n   - `multivariate-test` (a multivariate flag)\n   - `simple-test` (a simple boolean flag)\n   - `multivariate-simple-test` (a multivariate flag)\n   - `my_secret_flag_value` (a remote config flag with string payload)\n   - `my_secret_flag_json_object_value` (a remote config flag with JSON object payload)\n   - `my_secret_flag_json_array_value` (a remote config flag with JSON array payload)\n\n3. Set your PostHog API keys as environment variables:\n   - `POSTHOG_PROJECT_API_KEY`: Your project API key (starts with `phc_...`)\n   - `POSTHOG_PERSONAL_API_KEY`: Your personal API key (starts with `phx_...`)\n\n## Releasing\n\nReleases are semi-automated via GitHub Actions. When a PR with the `release` and a version bump label is merged to `master`, the release workflow is triggered.\n\nYou'll need an approval from a PostHog engineer. If you're an employee, you can see the request in the [#approvals-client-libraries](https://app.slack.com/client/TSS5W8YQZ/C0A3UEVDDNF) channel.\n\n### Release Process\n\n1. **Create your PR** with the changes you want to release\n2. **Add the `release` label** to the PR\n3. **Add a version bump label** that should be either `bump-patch`, `bump-minor` or `bump-major`\n4. **Merge the PR** to `master`\n\nOnce merged, the following happens automatically:\n\n1. A Slack notification is sent to the client libraries channel requesting approval\n2. A maintainer approves the release in the GitHub `Release` environment\n3. The version is bumped in `version.go` based on the version label (`patch`, `minor`, or `major`, extracted from the label)\n4. The `CHANGELOG.md` is updated with a link to the full changelog\n5. Changes are committed and pushed to `master`\n6. A git tag is created (e.g., `v1.8.0`)\n7. A GitHub release is created with the changelog content\n8. Slack is notified of the successful release\n\nReleases are installed directly from GitHub.\n\n## Event Delivery and Retry Behavior\n\nThe PostHog Go client includes automatic retry logic for handling transient network failures. Understanding when events are delivered vs dropped helps ensure reliable analytics.\n\n### Events Are Delivered (Not Dropped)\n\nThe client automatically retries on network errors and will successfully deliver events when:\n\n- **Transient network failures** - EOF errors, connection resets, TCP drops that recover within retry attempts\n- **Server temporarily unavailable** - If the server starts responding before max retries are exhausted\n- **Connection drops at any stage** - Whether after connect, during headers, or while sending body\n\nExample scenarios that recover successfully:\n\n- Server closes connection without response (EOF) but succeeds on retry\n- TCP connection dropped after partial body read\n- Temporary network interruption lasting a few seconds\n\n### Events Are Dropped\n\nEvents will be permanently lost in these scenarios:\n\n| Scenario                       | Behavior                                                                       |\n| ------------------------------ | ------------------------------------------------------------------------------ |\n| **Max retries exceeded**       | After 10 failed attempts, events are dropped and `Failure` callback is invoked |\n| **Client closed during retry** | If `client.Close()` is called while retrying, pending events are dropped       |\n| **Non-retryable errors**       | JSON marshalling failures cause immediate drop (no retry)                      |\n| **HTTP 4xx responses**         | Client errors (e.g., invalid API key) are not retried                          |\n\n### Configuring Retry Behavior\n\nYou can customize retry timing via the `RetryAfter` config option:\n\n```go\nclient, _ := posthog.NewWithConfig(\n    \"api-key\",\n    posthog.Config{\n        RetryAfter: func(attempt int) time.Duration {\n            // Custom backoff: 100ms, 200ms, 400ms, ...\n            return time.Duration(100\u003c\u003cattempt) * time.Millisecond\n        },\n    },\n)\n```\n\nTo limit the number of retries (default is 9 retries = 10 total attempts):\n\n```go\nclient, _ := posthog.NewWithConfig(\n    \"api-key\",\n    posthog.Config{\n        MaxRetries: posthog.Ptr(3), // 3 retries = 4 total attempts\n    },\n)\n```\n\nSetting `MaxRetries` to 0 means only one attempt with no retries (disable retries):\n\n```go\nposthog.Config{\n    MaxRetries: posthog.Ptr(0), // 3 retries = 4 total attempts\n},\n```\n\n### Monitoring Event Delivery\n\nUse the `Callback` interface to track successes and failures:\n\n```go\ntype MyCallback struct{}\n\nfunc (c *MyCallback) Success(msg posthog.APIMessage) {\n    log.Printf(\"Event delivered: %v\", msg)\n}\n\nfunc (c *MyCallback) Failure(msg posthog.APIMessage, err error) {\n    log.Printf(\"Event dropped: %v, error: %v\", msg, err)\n    // Optionally: persist to disk, send to dead-letter queue, etc.\n}\n\nclient, _ := posthog.NewWithConfig(\"api-key\", posthog.Config{\n    Callback: \u0026MyCallback{},\n})\n```\n\n## Questions?\n\n### [Visit the community forum.](https://posthog.com/questions)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposthog%2Fposthog-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fposthog%2Fposthog-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposthog%2Fposthog-go/lists"}