Telemetry

August 14, 2026 · View on GitHub

Privacy Policy - [PAGE]

Event tracking respects user privacy settings and can be disabled through the application settings. No personally identifiable information is collected without explicit user consent.

Event Tracking

Thunderbolt uses PostHog for analytics to track user interactions and application usage. All events follow a structured naming convention for better organization and analysis.

Event properties must never include prompts, responses, API keys, or other user-authored content. Use non-secret scalar identifiers such as model_id, model_name, and provider; a final egress scrub removes any property named apiKey before sending.

Event Naming Convention

Events follow the pattern: <feature>_<action>

  • Feature: The main area of the application (e.g., chat, task, automation)
  • Action: The specific action being performed (e.g., send_prompt, add, create)

Event Categories

Chat & Messaging (chat_*)

  • chat_send_prompt - User sends a message to the AI (with trace_id, model_id, model_name, provider, length, and prompt_number)
  • chat_send_prompt_overflow - User attempts a prompt that exceeds the model context (with the same scalar model properties, length, and prompt_number)
  • chat_receive_reply - AI generates a response (with trace_id, engine, model_id, model_name, provider, length, and reply_number)
  • chat_auto_retry - A built-in turn schedules an automatic retry (with trace_id, engine, turn-stable model_id/model_name/provider, attempt, max_retries, and reason)
  • chat_retry_success - An automatically retried built-in turn succeeds (with trace_id, engine, turn-stable model_id/model_name/provider, and attempts)
  • chat_retries_exhausted - A built-in turn stops retrying (with trace_id, engine, turn-stable model_id/model_name/provider, attempts, and reason)
  • Retry reason uses the stable error class. Pi-engine errors classify 408, 429, and 5xx statuses embedded by pi-ai as timeout, rate-limit, and provider; other or unrecognized errors remain unknown.
  • chat_turn_completed - One privacy-safe summary per built-in turn, including trace_id, actual engine, scalar model/provider identifiers, outcome/error class, attempts/retry layers/retry reasons, phase timings, user-perceived TTFT, step/tool counts, capped tool timings, and total duration. TTFT is measured when the first non-empty text or reasoning delta reaches the adapter response stream, after translator/smoothing overhead. MCP calls use the fixed tool label mcp; user-authored server-name-derived identifiers are never emitted.
  • tinfoil_attestation - A Tinfoil client attestation succeeds, fails, or times out (with outcome, duration_ms, client, optional error_name, and, for turn acquisitions, trace_id, engine, model_id, and provider)
  • chat_select - User selects a chat thread
  • chat_new_clicked - User creates a new chat
  • chat_delete - User deletes a chat
  • chat_clear_all - User clears all chats

Model Management (model_*)

  • model_select - User selects a different AI model

Settings (settings_*)

  • settings_theme_set - User changes the application theme
  • settings_name_set - User sets their preferred name initially
  • settings_name_update - User updates their preferred name
  • settings_name_clear - User clears their preferred name
  • settings_location_set - User sets their location initially
  • settings_location_update - User updates their location
  • settings_localization_update - User updates localization settings (temperature, wind speed, precipitation, time format, language)
  • settings_database_reset - User resets the application database
  • settings_data_collection_enabled - User enables data collection
  • settings_data_collection_disabled - User disables data collection

Task Management (task_*)

  • task_add - User adds a new task
  • task_mark_complete - User marks a task as complete
  • task_update_text - User edits task text
  • task_reorder - User reorders tasks
  • task_search - User searches through tasks

Automation (automation_*)

  • automation_modal_create_open - Create automation modal opens
  • automation_create - New automation is created
  • automation_modal_edit_open - Edit automation modal opens
  • automation_update - Existing automation is updated
  • automation_run - Automation is executed
  • automation_delete_clicked - Delete automation button is clicked
  • automation_delete_confirmed - Automation deletion is confirmed

Content View & Preview (content_view_*, preview_*)

  • content_view_open - Content view opens (with properties: view_type, tool_name for object views, sideview_type for sideviews). MCP object views use the fixed tool_name value mcp.
  • content_view_close - Content view closes (with property: view_type)
  • preview_open - Preview webview opens from a link click
  • preview_close - Preview webview closes
  • preview_copy_url - User copies URL from preview header
  • preview_open_external - User opens preview URL in external browser

UI & Navigation (ui_*)

  • ui_shortcut_use - User uses a keyboard shortcut
  • ui_sidebar_open - Sidebar opens
  • ui_sidebar_close - Sidebar closes

Startup Performance (app_*)

Diagnostic events for investigating app initialization time. All timing values are whole milliseconds measured from navigation start (performance.timeOrigin).

  • app_init_timing - Fired once per initialization run, after the init pipeline completes. Properties:
    • bundle_evaluated_ms - entry bundle downloaded, parsed and evaluated
    • app_mounted_ms - first render of the root React component
    • step0_fetch_config_msstep8_initialize_posthog_ms - duration of each init step (including step2b_db_ready_ms — the first trivial query that pays PowerSync's deferred ready gate — plus step4b_run_data_migrations_ms and step6_create_http_client_ms)
    • init_total_ms - total pipeline duration
    • init_run - run counter (greater than 1 means the user retried after an init error)
    • initial_sync_outcome - how the initial-sync gate resolved: disabled, synced, timed_out or failed
    • sync_enabled, platform - segmentation context
  • app_chat_ready - Fired at most once per session when the first chat finishes hydrating (with chat_ready_ms). Together with app_init_timing, this captures the user-perceived time to a usable chat.

Sync Diagnostics (sync_*)

Diagnostic events for debugging sync issues (especially iOS). All events include shared context: platform, ps_config, ps_connected, ps_connecting, ps_has_synced, ps_last_synced_at, ps_uploading, ps_downloading, uptime_ms.

  • sync_connect - PowerSync connected successfully
  • sync_connect_error - PowerSync connection failed (with error)
  • sync_disconnect - PowerSync disconnected (with trigger: 'user' or 'reconnect')
  • sync_reconnect_start - Reconnect attempt started (with trigger: 'visibility' or 'manual')
  • sync_reconnect_success - Reconnect succeeded (with optional hidden_duration_ms)
  • sync_reconnect_error - Reconnect failed (with error, trigger)
  • sync_visibility_change - App visibility changed (with state, hidden_duration_ms, will_reconnect, ms_since_last_download)
  • sync_credentials_fetch - Token refresh succeeded (with expires_in_ms)
  • sync_credentials_error - Token refresh failed (with status, error_code, had_token)
  • sync_upload - CRUD upload succeeded (with operation_count)
  • sync_upload_error - CRUD upload failed (with error, operation_count)
  • sync_status_change - PowerSync connected↔disconnected transition (with prev_connected, ms_since_last_change)

Implementation

Events are tracked using the trackEvent function from src/lib/posthog.tsx:

import { trackEvent } from '@/lib/posthog'

// Track a simple event
trackEvent('chat_send_prompt')

// Track an event with properties
trackEvent('chat_send_prompt', {
  model_id: 'model-row-id',
  model_name: 'gpt-4',
  provider: 'openai',
  length: 150,
})

Type Safety

All event names are typed using the EventType union type, ensuring:

  • Only valid event names can be used
  • Autocomplete support in IDEs
  • Compile-time error checking for typos

Adding New Events

To add a new event:

  1. Add the event name to the EventType union in src/lib/analytics.tsx
  2. Use the <feature>_<action> naming convention
  3. Add the tracking call in the appropriate component
  4. Include relevant properties for analytics insights
  5. Update this file to document it