Skip to content

feat: send install funnel events to PostHog - #26

Merged
arunim2405 merged 2 commits into
mainfrom
feat/posthog-install-funnel
Oct 30, 2026
Merged

arunim2405 merged 2 commits into
mainfrom
feat/posthog-install-funnel

Conversation

@arunim2405

@arunim2405 arunim2405 commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds product analytics to the connect flow and login so we can see where installs stop. A saved PostHog funnel tracks the steps: MCP wizard install funnel.

Step Event Fires when
1 mcp_install_started Connect or login starts (command, auth mode, scope, interactive)
2 mcp_install_logged_in A credential is in hand: a new OAuth grant, an API key, or a saved credential (reused_saved_credential), plus sg_org, sg_region
3 mcp_install_completed At least one agent got the server (agents, failed count, scope, skills installed and failed count, org, region)
– mcp_install_login_failed Browser sign-in failed; error code only (cancelled, timeout, or a standard OAuth code; anything else is sent as oauth_error)

Implementation

  • src/sg/telemetry.ts: no new dependency. A node:https POST to eu.i.posthog.com with the public, write-only phc_ key. It never throws. On timeout the socket is destroyed, so a stalled connection or TLS handshake can't keep the CLI running. Events are personless ($process_person_profile: false).
  • Distinct ID: a random UUID in ~/.config/add-sg-mcp/telemetry-id, not tied to the credential.
  • Never sent: keys, tokens, file paths or error messages.
  • Every event is awaited, because fail(), Ctrl-C and some later steps (no supported agent, cancelled picker) call process.exit, which would drop a request still in flight. All events share one 2-second budget per run, so analytics adds at most 2 seconds in total.
  • Opt-out: DO_NOT_TRACK=1 or SG_NO_TELEMETRY=1. tests/run.mjs and the binary smoke-test job set it.
  • README "Usage analytics" section, CHANGELOG 1.3.0, version bump to 1.3.0.

Notes

  • --auth oauth (preview) has no sign-in step, so it never sends step 2. Those runs show as drop-offs at step 2.
  • The funnel filters on command = connect: a non-interactive login stops after step 2 by design and would otherwise count as a drop-off.
  • The funnel has the test-account filter off: the project's filter matches on person email, which these personless events don't have.
  • One test mcp_install_started event from local verification is already in prod.

Test plan

  • bun run build, bun run typecheck, bun run test (23/23 files)
  • New tests/sg-telemetry.test.ts: opt-out parsing, persisted ID, payload shape, opted-out track sends nothing, OAuth reason allowlist, and a stalled endpoint is cut off with its socket closed (passes on Node and Bun; fails if the socket isn't destroyed)
  • Sent a request with an invalid key to PostHog under Node and Bun: it returns in about 0.6s and the process exits right away
  • Ran the CLI locally and confirmed mcp_install_started arrived in PostHog with the expected properties
  • After release: confirm all three steps appear in the funnel from a real grant install

🤖 Generated with Claude Code

arunim2405 and others added 2 commits October 29, 2026 17:02
The connect flow and login send mcp_install_started, mcp_install_logged_in
and mcp_install_completed (plus mcp_install_login_failed with the error
code) so we can see where installs stop. Events go straight to PostHog EU
with the public project key, a 2s timeout and an anonymous per-machine ID;
they never carry keys, tokens, paths or error messages. DO_NOT_TRACK=1 or
SG_NO_TELEMETRY=1 turns them off; tests and binary smoke tests set it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Send only standard OAuth error codes as the login-failure reason; any
  other value becomes oauth_error, since it can echo broker or user text.
- Send through node:https and destroy the socket on timeout, so a stalled
  connection or TLS handshake cannot keep the CLI alive. All events share
  one two-second budget per run instead of two seconds each.
- Await every event, so logged_in is no longer lost when a later step
  calls process.exit (no supported agent, cancelled picker).
- skills_installed now reflects the skills that actually installed, and
  failed_skill_count reports the failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@arunim2405
arunim2405 merged commit 66070a0 into main Oct 30, 2026
8 checks passed
@arunim2405
arunim2405 deleted the feat/posthog-install-funnel branch October 30, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant