Files
OpenHands/src
Rohit Malhotraandopenhands e2615344df feat: add first-use telemetry tracking with consent (#138)
* feat: add first-use telemetry tracking with consent

- Add telemetry service with consent management (src/services/telemetry.ts)
- Add useTelemetry React hook for easy integration (src/hooks/use-telemetry.ts)
- Add TelemetryConsentBanner component with i18n support
- Add local development server for testing (scripts/telemetry-dev-server.mjs)
- Add comprehensive tests for telemetry service and hook
- Export telemetry utilities from library index
- Respect DO_NOT_TRACK environment variable for privacy
- Uses localhost:8080 endpoint for development

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: address PR review feedback

- Make TELEMETRY_ENDPOINT configurable via VITE_TELEMETRY_ENDPOINT env var
- Make POSTHOG_API_KEY configurable via VITE_POSTHOG_API_KEY env var
- Add validation to skip telemetry if API key not configured (except localhost)
- Fix DO_NOT_TRACK to work in browser environments using VITE_DO_NOT_TRACK
- Also respect browser's navigator.doNotTrack standard
- Update consent banner hint text to reference correct env var
- Add documentation comments for all configuration options

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: hardcode PostHog credentials for centralized telemetry

- Use OpenHands PostHog project API key for all library users
- Use PostHog US Cloud endpoint (https://us.i.posthog.com/capture)
- Remove environment variable configuration for endpoint/API key
- Telemetry now automatically sends to centralized project when consent granted
- Users can still opt out via UI, VITE_DO_NOT_TRACK, or browser DNT setting

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: use separate PostHog API keys for dev and production

- Dev environment: phc_kBtz5nKmxVRRQ7HtPwr2QX9eMC5j65zE86QKocVNwb4U
- Production: phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK
- Automatically selects key based on import.meta.env.DEV

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: use single production PostHog API key everywhere

Simplify by using the same API key for all environments.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: rename telemetry events

- library_first_use → canvas_install
- library_session_start → canvas_new_session

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: migrate telemetry to PostHog SDK

Replace raw HTTP requests with PostHog SDK for:
- Automatic event batching
- Built-in retry logic with exponential backoff
- Offline support (queues events, sends when back online)
- Automatic session tracking
- Better device/browser info enrichment

Benefits:
- More reliable event delivery
- Reduced network requests
- Cleaner code with less manual state management
- Future-proof for feature flags, session replay, etc.

Co-authored-by: openhands <openhands@all-hands.dev>

* refactor: remove redundant hasTrackedFirstUse state in hook

The trackFirstUse() function already has built-in deduplication via
localStorage, so the local React state was unnecessary. Simplified
the hook and added a comment explaining the deduplication mechanism.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: remove obsolete telemetry dev server

The local dev server was used when telemetry used raw HTTP requests
to a configurable endpoint. Now that we use the PostHog SDK with
the real PostHog endpoint, this is no longer needed.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: remove trailing comma in package.json

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: address PR review feedback

- Make POSTHOG_API_KEY configurable via VITE_POSTHOG_API_KEY env var
- Make POSTHOG_HOST configurable via VITE_POSTHOG_HOST env var
- Add session deduplication using sessionStorage to prevent duplicate
  canvas_new_session events from multiple hook instances
- Clear sessionStorage in clearTelemetryData()

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: use dynamic imports for PostHog SSR compatibility

- Convert top-level posthog-js import to dynamic import for SSR safety
- Add getPostHog() lazy loader that only imports in browser context
- Make setTelemetryConsent, clearTelemetryData, getPostHogInstance async
- Update documentation to clarify default telemetry destination
- Update tests for async function signatures

This ensures the library works correctly in SSR frameworks (Next.js, Remix,
etc.) that might import this module server-side.

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: add telemetry consent banner to app layout

The consent banner now appears on all pages until the user explicitly
accepts or declines telemetry. This ensures users are always prompted
for consent on their first visit regardless of which page they land on.

Co-authored-by: openhands <openhands@all-hands.dev>

* refactor: update telemetry consent banner to modal style

- Changed from bottom banner to centered modal overlay (matching OpenHands)
- Uses ModalBackdrop, ModalBody, BaseModalTitle, BaseModalDescription
- Single checkbox with 'Confirm preferences' button pattern
- Full-screen overlay blocks interaction until user makes a choice
- Added i18n keys: TELEMETRY$SEND_ANONYMOUS_DATA, TELEMETRY$CONFIRM_PREFERENCES

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: ensure PostHog is initialized before tracking events

- Made grantConsent/denyConsent in useTelemetry hook async to ensure
  PostHog initialization completes before state update triggers tracking
- Updated tests for async consent functions
- This fixes a race condition where trackFirstUse() could be called before
  PostHog's opt_in_capturing() had been executed

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-07 13:18:01 -04:00
..
2026-05-07 12:50:05 -04:00
2026-05-07 12:50:05 -04:00