# Analytics Integration Documentation ## Overview The Memoro app uses a multi-platform analytics system with **PostHog** for mobile (iOS/Android) and **Umami** for web. This document describes all tracked events, implementation details, and best practices. ## Architecture ### Service Layer - **MultiPlatformAnalyticsService** (`/features/analytics/services/multiPlatformAnalytics.ts`) - Routes analytics calls to the appropriate service based on platform - PostHog for mobile (iOS/Android) - Umami for web ### Key Components - **AnalyticsProvider** - Initializes analytics on app start - **AnalyticsNavigationTracker** - Automatic screen tracking via Expo Router - **useAnalytics** - Hook for tracking events - **useScreenTracking** - Hook for manual screen tracking - **useFeatureFlag** - Hook for PostHog feature flags (mobile only) ## Configuration ### PostHog (Mobile) - v3.x - **API Key**: Set in `EXPO_PUBLIC_POSTHOG_KEY` - **Host**: `https://eu.i.posthog.com` (EU datacenter) - **Auto-capture**: Enabled for lifecycle events - **Debug Mode**: Enabled in development - **Initialization**: Automatic in constructor (no `initAsync()` needed) - **Methods**: Synchronous (no `async/await` required) ### Umami (Web) - **Website ID**: Set in `EXPO_PUBLIC_UMAMI_WEBSITE_ID` - **Script URL**: `https://umami.manacore.ai/script.js` ## Tracked Events ### 🎙️ Recording Events #### `recording_started` Fired when user starts a recording ```typescript { blueprint_id: string, space_id: string | null, languages: string[], language_count: number, is_append: boolean, theme: 'light' | 'dark' } ``` #### `recording_stopped` Fired when recording is stopped (manual or automatic) ```typescript { duration_seconds: number, reason: 'manual' | 'auto' | 'error', blueprint_id: string | null, space_id: string | null, has_result: boolean } ``` #### `recording_failed` Fired when recording fails ```typescript { error_type: 'insufficient_credits' | 'permission_denied' | 'network_error', blueprint_id: string | null, space_id: string | null, can_ask_again?: boolean // For permission errors } ``` #### `recording_permission_retry` Fired when user retries after permission denial ```typescript { blueprint_id: string | null, space_id: string | null } ``` ### 📝 Memo Events #### `memo_viewed` Fired when a memo is opened ```typescript { memo_id: string, source: 'direct_navigation' | 'list' | 'search', is_translated: boolean } ``` #### `memo_shared` Fired when user shares a memo ```typescript { memo_id: string, has_transcript: boolean, has_memories: boolean } ``` #### `memo_deleted` Fired when a memo is deleted ```typescript { memo_id: string, has_transcript: boolean, duration_seconds: number | null } ``` #### `memo_pinned` / `memo_unpinned` Fired when pin status changes ```typescript { memo_id: string } ``` #### `transcript_copied` Fired when transcript is copied to clipboard ```typescript { memo_id: string, transcript_length: number } ``` ### 📋 List & Search Events #### `memo_list_filtered` Fired when filters are applied to memo list ```typescript { filter_type: 'tags' | 'space' | 'date', tag_count?: number, tag_ids?: string[] } ``` #### `memo_searched` Fired when user performs a search ```typescript { query_length: number, has_results: boolean } ``` #### `memo_bulk_action` Fired for bulk operations on multiple memos ```typescript { action: 'delete' | 'add_tag' | 'remove_tag' | 'move_space', memo_count: number, tag_id?: string, space_id?: string } ``` ### 🤖 AI Processing Events #### `blueprint_selected` Fired when user selects a blueprint ```typescript { blueprint_id: string | null, is_standard: boolean, space_id: string | null } ``` #### `blueprint_applied` Fired when blueprint processing completes ```typescript { memo_id: string, blueprint_id: string, mana_cost: number, processing_time_ms: number } ``` #### `question_asked` Fired when user asks a question about a memo ```typescript { memo_id: string, question_length: number, mana_cost: 5 // Fixed cost } ``` #### `memos_combined` Fired when multiple memos are combined ```typescript { memo_count: number, blueprint_id: string, has_prompt: boolean, mana_cost: number // 5 per memo } ``` #### `memo_reprocessed` Fired when memo is reprocessed with new settings ```typescript { memo_id: string, language: string, has_blueprint: boolean, blueprint_id?: string } ``` #### `memo_translated` Fired when memo is translated ```typescript { memo_id: string, target_language: string } ``` ### 💳 Subscription & Credits Events #### `subscription_page` Screen view for subscription page ```typescript { is_b2b: boolean } ``` #### `subscription_purchase_attempted` Fired when user initiates purchase ```typescript { plan_id: string, plan_type: 'individual' | 'team' | 'enterprise', billing_cycle: 'monthly' | 'yearly', credits: number, price: number } ``` #### `subscription_purchased` Fired on successful purchase ```typescript { plan_id: string, plan_type: 'individual' | 'team' | 'enterprise', billing_cycle: 'monthly' | 'yearly', credits: number, price: number } ``` #### `subscription_restore_attempted` / `subscription_restore_completed` Fired during purchase restoration flow ### 📱 Screen Tracking Automatic screen tracking via `AnalyticsNavigationTracker`: - `recording_screen` - Home/Recording tab - `memos_list` - Memos tab - `memo_detail` - Individual memo view - `subscription_page` - Subscription/credits page - `settings` - Settings page - `profile` - User profile Each screen event includes: ```typescript { path: string, // URL path timestamp: string, focused_at?: string // For manual tracking } ``` ### ⚡ Performance Events #### `memo_load_time` Tracks memo loading performance ```typescript { memo_id: string, duration_ms: number } ``` ### 🔥 Error Tracking #### `error_occurred` Generic error tracking ```typescript { error_name: string, error_message: string, error_stack?: string, // Only in dev screen?: string, action?: string, user_id?: string } ``` ## Implementation Examples ### Basic Event Tracking ```typescript import { useAnalytics } from '~/features/analytics'; function MyComponent() { const { track } = useAnalytics(); const handleAction = () => { // Note: track() is synchronous in PostHog v3 track('custom_event', { property1: 'value', property2: 123 }); }; } ``` ### Screen Tracking ```typescript import { useScreenTracking } from '~/features/analytics'; function MyScreen() { // Automatic screen tracking useScreenTracking('my_screen', { tab: 'main', source: 'navigation' }); } ``` ### Error Tracking ```typescript import { trackError } from '~/features/analytics'; try { // Some operation } catch (error) { trackError(track, error, { screen: 'memo_detail', action: 'load_data', memo_id: id }); } ``` ### Performance Tracking ```typescript import { trackPerformance } from '~/features/analytics'; const startTime = Date.now(); // ... operation ... trackPerformance(track, 'operation_name', Date.now() - startTime, { additional_context: 'value' }); ``` ### Feature Flags (Mobile Only) ```typescript import { useFeatureFlag } from '~/features/analytics'; function MyComponent() { const showNewFeature = useFeatureFlag('new-feature-flag'); if (showNewFeature) { return ; } return ; } ``` ## PostHog Dashboard Setup ### Recommended Dashboards #### 1. User Journey Funnel Create a funnel visualization: 1. `recording_started` 2. `recording_stopped` 3. `memo_viewed` 4. `memo_shared` #### 2. Feature Adoption Track usage of key features: - Blueprint usage (non-standard selections) - AI features (questions, reprocessing, translation) - Collaboration (space usage, sharing) #### 3. Error Monitoring - Group `recording_failed` by `error_type` - Track `error_occurred` by screen and action - Monitor permission denial rates #### 4. Performance Metrics - `memo_load_time` percentiles (P50, P95, P99) - Track by device type and network conditions #### 5. Engagement Metrics - Daily/Weekly/Monthly Active Users - Session duration - Actions per session - Retention cohorts ### Key Metrics to Monitor 1. **Recording Success Rate** - `recording_stopped` / `recording_started` - Identify drop-off points 2. **AI Feature Usage** - Questions per user - Blueprint adoption rate - Mana consumption patterns 3. **User Retention** - Day 1, 7, 30 retention - Feature-specific retention 4. **Error Rate** - Errors per user - Error types distribution - Recovery success rate ## Privacy & Compliance ### Data Collected - No PII in event properties by default - User IDs are anonymized - Device info for debugging - Usage patterns and feature adoption ### GDPR Compliance - PostHog hosted in EU (eu.i.posthog.com) - User consent required before tracking - Option to opt-out in settings - Data retention policies applied ## Testing Analytics ### Development Testing 1. Enable debug mode: Events logged to console 2. Use PostHog Live Events view for real-time monitoring 3. Test event in dev settings: `/app/(protected)/settings.tsx` 4. PostHog v3: Methods are synchronous, no need for await ### Production Validation 1. Check PostHog dashboard for event flow 2. Verify event properties are correct 3. Monitor for any tracking errors 4. Validate funnel completion rates ## Troubleshooting ### Events Not Appearing 1. Check API key configuration 2. Verify PostHog instance is created successfully 3. Check network connectivity 4. Look for console errors 5. Ensure `flush()` is called in dev (synchronous) ### PostHog v3 Specific Issues - **`initAsync is not a function`**: PostHog v3 doesn't have `initAsync()`. Initialization happens in the constructor. - **Async methods**: All PostHog v3 methods are synchronous. Don't use `await`. - **TypeScript errors**: Ensure types match synchronous signatures (return `void` not `Promise`) ### Missing Properties 1. Verify property names match schema 2. Check for undefined values 3. Ensure proper async/await usage ### Performance Issues 1. Batch events when possible 2. Use sampling for high-frequency events 3. Optimize property payload size ## Future Enhancements ### Planned Additions - [ ] Session replay integration - [ ] Heatmaps for UI interactions - [ ] Custom user properties - [ ] Revenue tracking - [ ] A/B testing framework - [ ] Crash reporting integration - [ ] Network performance tracking - [ ] Battery usage monitoring ### Potential Events - Audio playback events (play, pause, seek) - Memory creation/edit events - Tag management events - Space collaboration events - Network status changes - App background/foreground transitions ## Contact & Support For analytics questions or to request new events: - Create an issue in the repository - Contact the development team - Check PostHog documentation: https://posthog.com/docs ## Technical Implementation Details ### PostHog v3 React Native SDK #### Initialization ```typescript // PostHog v3 - Initialization happens in constructor this.posthog = new PostHog(apiKey, { host: 'https://eu.i.posthog.com', debug: __DEV__, captureApplicationLifecycleEvents: true, captureDeepLinks: true, recordScreenViews: true, flushInterval: 30, flushAt: 20, maxQueueSize: 1000, disableAutoCapture: false, enableLogs: __DEV__, }); // No initAsync() needed - ready to use immediately ``` #### Method Signatures (Synchronous) ```typescript // All methods are synchronous in v3 posthog.identify(userId: string, properties?: object): void posthog.capture(event: string, properties?: object): void posthog.screen(name: string, properties?: object): void posthog.reset(): void posthog.flush(): void ``` #### Common Pitfalls - ❌ Don't use `await posthog.initAsync()` - doesn't exist - ❌ Don't use `await posthog.capture()` - synchronous - ✅ Do use `posthog.flush()` in dev for immediate sending - ✅ Do handle errors with try-catch around constructor ### Service Architecture ```typescript // analyticsService.ts class PostHogAnalyticsService implements AnalyticsService { private posthog: any = null; private initialized = false; async initialize() { // Create instance (initialization happens here) this.posthog = new PostHog(key, options); this.initialized = true; // Test event with small delay setTimeout(() => { this.posthog.capture('posthog_initialized', {...}); }, 100); } // All methods are synchronous wrappers track(event: string, properties?: object): void { if (!this.initialized) return; this.posthog.capture(event, properties); if (__DEV__) this.posthog.flush(); } } ``` --- *Last updated: 2025-01-09* *Version: 1.1.0* *PostHog SDK: v3.x*