ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

Mobile Analytics: Measuring What Users Actually Do

Implement mobile analytics that reveal real user behavior, not vanity metrics. Covers event design, user journey tracking, funnel analysis, session recording, privacy compliance, and building an analytics architecture that scales from prototype to millions of users.

Mobile analytics answers the question every product team asks but rarely answers well: what do users actually do in the app? Not what you designed them to do. Not what the user research suggested they would do. What they actually do — where they tap, where they hesitate, where they abandon, and where they convert.

Good analytics transforms product decisions from opinion-based debates into data-informed conversations.


Event Design

The Event Taxonomy

Structure events consistently across the app:

Category:  The feature area
Action:    What happened
Label:     Additional context (optional)
Value:     Numeric measurement (optional)
// Consistent event naming convention
Analytics.track("order_created", [
    "order_id": "ORD-456",
    "item_count": 3,
    "total": 249.99,
    "payment_method": "apple_pay",
    "coupon_applied": true
])

Analytics.track("product_viewed", [
    "product_id": "PROD-123",
    "category": "electronics",
    "source": "search_results",
    "position": 4
])

Analytics.track("checkout_step_completed", [
    "step": "shipping_address",
    "step_number": 2,
    "time_on_step_seconds": 45
])

Event Naming Conventions

✅ Good: snake_case, verb_past_tense
  order_created, product_viewed, cart_item_added, payment_failed

❌ Bad: inconsistent case, present tense, vague
  OrderCreated, view_product, click, buttonPress

What to Track

Always track:

  • Screen views (every screen transition)
  • Key business events (purchases, registrations, subscriptions)
  • Error states (crashes, API failures, validation errors)
  • User journey milestones (onboarding complete, first purchase)

Track strategically:

  • Feature engagement (which features are actually used?)
  • Performance events (app launch time, screen render time)
  • Search queries (what are users looking for?)
  • Notification interactions (open rate, dismiss rate)

Never track:

  • Passwords or authentication tokens
  • Personal health or financial data (without explicit consent and compliance)
  • Continuous location tracking (without clear user value and consent)

User Journey Tracking

Funnel Analysis

Define conversion funnels and measure drop-off:

Checkout Funnel (last 30 days):
  Cart Viewed:          10,000  (100%)
  Checkout Started:      4,200  (42%)    ← 58% drop-off
  Shipping Entered:      3,800  (38%)    ← 10% drop-off
  Payment Entered:       3,400  (34%)    ← 11% drop-off
  Order Confirmed:       2,800  (28%)    ← 18% drop-off

The biggest drop-off (58%) is between viewing the cart and starting checkout. This is where product investment should focus.

Cohort Analysis

Group users by their first action date and track retention:

              Day 1    Day 7    Day 14   Day 30
Jan cohort:   100%     42%      28%      18%
Feb cohort:   100%     45%      31%      22%
Mar cohort:   100%     51%      35%      25%  ← Improving!

The March cohort retains better — likely due to onboarding improvements shipped in late February.

Session Replay

Record user sessions (screen recordings with interactions) for qualitative analysis:

// Session replay integration
SessionReplay.configure(
    sampleRate: 0.05,  // Record 5% of sessions
    maskSensitiveViews: true,  // Automatically mask text inputs
    maxSessionLength: 600  // 10 minutes max
)

Session replays reveal behavior that event data cannot: confusion, hesitation, repeated taps on non-interactive elements, and rage taps (rapid tapping indicating frustration).


Analytics Architecture

Client-Side Collection

┌──────────────┐
│   App UI     │
│  (Events)    │
└──────┬───────┘

┌──────▼───────┐
│ Analytics SDK │
│  (Buffer)    │
└──────┬───────┘
       │ batch (every 30s or 20 events)
┌──────▼───────┐
│  Analytics   │
│  Endpoint    │
└──────────────┘

Event Buffer and Batching

Do not send events individually. Buffer and batch:

class AnalyticsBuffer {
    private val buffer = mutableListOf<AnalyticsEvent>()
    private val maxBufferSize = 20
    private val flushInterval = 30_000L // 30 seconds
    
    fun track(event: AnalyticsEvent) {
        buffer.add(event)
        if (buffer.size >= maxBufferSize) {
            flush()
        }
    }
    
    private fun flush() {
        if (buffer.isEmpty()) return
        
        val batch = buffer.toList()
        buffer.clear()
        
        // Send batch to server
        api.sendEvents(batch).onFailure {
            // Persist to disk for retry
            persistToLocalStorage(batch)
        }
    }
}

Offline Event Queuing

Events generated offline are queued locally and sent when connectivity returns:

func trackEvent(_ event: AnalyticsEvent) {
    // Always save locally first
    localStore.save(event)
    
    // Attempt to send if online
    if networkMonitor.isConnected {
        uploadPendingEvents()
    }
}

func uploadPendingEvents() {
    let pending = localStore.getPending()
    api.sendBatch(pending) { result in
        if case .success = result {
            localStore.markSent(pending)
        }
    }
}

Privacy Compliance

// iOS: App Tracking Transparency
import AppTrackingTransparency

func requestTracking() {
    ATTrackingManager.requestTrackingAuthorization { status in
        switch status {
        case .authorized:
            Analytics.enableFullTracking()
        case .denied, .restricted:
            Analytics.enableAnonymousOnly()
        case .notDetermined:
            break
        }
    }
}

Data Minimization

  • Collect the minimum data needed for the analysis
  • Anonymize user identifiers where possible
  • Set data retention policies (delete raw events after 90 days)
  • Provide data export and deletion APIs for GDPR/CCPA compliance

Server-Side Analytics

For privacy-sensitive applications, send minimal events from the client and enrich server-side:

Client sends:   { event: "purchase", order_id: "456" }
Server enriches: { event: "purchase", order_id: "456", 
                   revenue: 249.99, category: "electronics",
                   user_segment: "returning", cohort: "2026-01" }

User attributes and business data stay on the server. The client only reports actions.


Tool Selection

ToolStrengthsBest For
Firebase AnalyticsFree, Google ecosystem, predictiveStartups, Google-heavy stacks
AmplitudeBest product analytics UI, cohortsProduct-led growth teams
MixpanelEvent-level drill-down, funnelsDetailed behavior analysis
PostHogOpen source, self-hostablePrivacy-conscious organizations
SegmentEvent router to multiple toolsMulti-tool analytics stacks

Anti-Patterns

Anti-PatternConsequenceFix
Tracking everythingData bloat, no signal in noiseDefine event taxonomy, track strategically
No naming conventionInconsistent data, broken funnelsEnforce naming standards in code review
Individual event sendsBattery drain, network overheadBuffer and batch
No offline queuingLost events during poor connectivityPersist events locally, sync when online
Ignoring privacy regulationsLegal risk, user trust erosionATT/consent frameworks, data minimization

Analytics is not about data volume — it is about data quality. A thousand well-designed events that align with your product questions are worth more than a million undifferentiated event streams. Start with the questions your product team needs answered, then instrument the events that answer them.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →