Mobile App Analytics Engineering
Instrument mobile applications for actionable analytics. Covers event taxonomy design, user journeys, retention metrics, funnel analysis, privacy-preserving analytics, and the patterns that transform raw events into product insights.
Mobile analytics is different from web analytics. Users install, use, and uninstall. Sessions span days, not minutes. Offline usage is common. Privacy regulations restrict tracking. Good mobile analytics tracks what matters — user journeys, retention, and value — without drowning in vanity metrics.
Event Taxonomy
# Design a consistent event naming convention
# Format: {category}_{action}_{target}
# User lifecycle events
events = {
# Onboarding
"app_opened_first_time": {"source": "install"},
"onboarding_started": {},
"onboarding_step_completed": {"step": "int", "step_name": "string"},
"onboarding_completed": {"duration_seconds": "int"},
"onboarding_skipped": {"at_step": "int"},
# Core actions
"search_performed": {"query": "string", "results_count": "int"},
"item_viewed": {"item_id": "string", "category": "string"},
"item_added_to_cart": {"item_id": "string", "price": "float"},
"checkout_started": {"cart_value": "float", "item_count": "int"},
"purchase_completed": {"order_id": "string", "total": "float", "payment_method": "string"},
# Engagement
"feature_used": {"feature_name": "string", "context": "string"},
"notification_received": {"type": "string"},
"notification_opened": {"type": "string", "delay_seconds": "int"},
"share_initiated": {"content_type": "string", "platform": "string"},
# Technical
"error_occurred": {"error_code": "string", "screen": "string"},
"performance_metric": {"screen": "string", "load_time_ms": "int"},
"crash_detected": {"exception": "string", "stack_trace": "string"},
}
Key Metrics
Acquisition:
Install rate: Downloads / App Store impressions
Cost per install: Ad spend / Installs
Organic vs paid ratio: Organic installs / Total installs
Activation:
Onboarding completion rate: Completed / Started
Time to first key action: Median time from install to first [purchase/post/etc.]
Day 1 retention: % of users who return day after install
Retention:
Day 1/7/30 retention: % returning on day N
Rolling 7-day retention: Active in last 7 days / Active 14-7 days ago
Cohort retention curves: Retention by install week
Healthy benchmarks:
Day 1: 25-40%
Day 7: 10-20%
Day 30: 5-10%
(Top apps: 2-3x these numbers)
Revenue:
ARPU: Revenue / Active Users
ARPPU: Revenue / Paying Users
Conversion rate: Paying users / Active users
LTV: Lifetime value per user (predicted revenue over lifetime)
Engagement:
DAU/MAU ratio: Daily active / Monthly active (stickiness)
Sessions per day: Average sessions per active user
Session duration: Median session length
Feature adoption: % of users using feature X
Implementation
// iOS Analytics SDK wrapper (Swift)
class AnalyticsManager {
static let shared = AnalyticsManager()
private var providers: [AnalyticsProvider] = []
private var userProperties: [String: Any] = [:]
func configure() {
providers = [
FirebaseAnalyticsProvider(),
MixpanelProvider(),
]
}
func identify(userId: String, properties: [String: Any]) {
userProperties = properties
providers.forEach { $0.identify(userId: userId, properties: properties) }
}
func track(_ event: String, properties: [String: Any] = [:]) {
// Enrich with standard properties
var enriched = properties
enriched["platform"] = "ios"
enriched["app_version"] = Bundle.main.appVersion
enriched["os_version"] = UIDevice.current.systemVersion
enriched["timestamp"] = ISO8601DateFormatter().string(from: Date())
enriched["session_id"] = SessionManager.shared.currentSessionId
// Send to all providers
providers.forEach { $0.track(event, properties: enriched) }
// Local logging for debugging
#if DEBUG
print("📊 Analytics: \(event) \(enriched)")
#endif
}
func trackScreen(_ screenName: String) {
track("screen_viewed", properties: [
"screen_name": screenName,
"previous_screen": NavigationTracker.shared.previousScreen ?? "none",
])
}
}
Anti-Patterns
| Anti-Pattern | Consequence | Fix |
|---|---|---|
| Track everything | Data noise, storage costs, analysis paralysis | Track decisions, not clicks |
| No event naming convention | Inconsistent data, impossible to query | Standardized taxonomy |
| Client-side only analytics | Lost events, ad blockers, offline gaps | Server-side event validation |
| Vanity metrics (total downloads) | Misleading growth narrative | Focus on retention and activation |
| No cohort analysis | Cannot detect if product is improving | Weekly cohort retention curves |
Mobile analytics is not about collecting data — it is about collecting the right data, structuring it consistently, and using it to make better product decisions.