- Most app teams track ~40 metrics. They review 4. The other 36 fill dashboards and never inform a decision.
- The working set is 12 metrics across 5 layers: acquisition, activation, engagement, retention/monetization, technical.
- Day-1 retention is the harshest single number in your dashboard, and the one most tightly correlated with everything downstream.
- In React Native, 4 instrumentation failure modes make your numbers lie: deep-link sessions, app-state timeouts, offline-event flushing, and over-eventing.
- Pick your core 8–12 metrics by stage. Give each one a named owner. Delete the rest.
The vanity-metric trap
A vanity metric is any number that goes up reliably but doesn't help you decide anything.
Total downloads is the classic example. Downloads only grow. An app with 1M downloads and 2% Day-30 retention is, by any honest measure, smaller than an app with 50k downloads and 35% Day-30 retention.
Three questions to run every metric through before you instrument it:
- What decision will this number inform? If "we'll know how we're doing," it's vanity.
- Who owns that decision? No owner → nobody acts on it.
- How often will they review it? "Occasionally" means you built a screensaver.
A metric that survives all three is worth instrumenting. Almost nothing else is.
The 12 metrics that actually matter
Acquisition layer
1. Install conversion rate. Of every 100 people who land on your App Store listing, how many install? Baselines: 25–30% organic, 30–40% paid. Below 20% you have a creative problem, not a traffic problem.
2. CAC (by channel). Useful only as a ratio with LTV. Healthy LTV:CAC is ~3:1 for consumer subscription apps. Below that, growth is a tax on the business.
Activation layer
3. Day-1 retention. Of users who installed yesterday, how many came back today? Industry average 25–30%. Top decile clears 50%. This is the harshest number in your dashboard.
4. Time to first value (TTFV). How long until a new user does the thing your app is for? Highest leverage on Day-1 retention.
Engagement layer
5. DAU/MAU stickiness. Healthy: 0.20. Daily habit: 0.50+. Productivity tools: 0.15–0.25. Ecommerce often under 0.10 (and that's fine if LTV supports it).
6. Session length + sessions per user. Watch them together. Length down + frequency stable = users achieving the goal faster (good). Frequency down + length stable = retention problem in disguise.
7. Key feature adoption rate. Pick 2–3 features that cause retention. Track the % of new users who reach each in their first week. This turns "improve onboarding" into a specific testable bet.
Retention and monetization layer
8. Day-7 and Day-30 retention. Day-1 = onboarding worked. Day-7 = value was real. Day-30 = value was recurring. Track as cohorts.
9. Churn rate. Healthy monthly: 5%. Trouble: 10%. Bucket has a hole: 15%+.
10. ARPU and LTV. LTV justifies CAC. Be honest about assumptions — if your "12-month LTV" comes from 3 months of data, you are projecting, not measuring.
Technical performance layer
11. Crash-free sessions. Google Play flags >1.09% crash rate as "bad behavior." Aim for 99.5%+ as the floor.
12. Cold start time. Cold-starts >2.5s correlate measurably with worse first-session retention. Most under-tracked, highest-leverage metric on the list.
Pick your core 8–12 by stage
| Stage | Pre-launch (≤1k users) | Growth (1k–100k) | Scale (100k+) |
|---|---|---|---|
| Acquisition | Install conv rate | CAC by channel | LTV:CAC ratio |
| Activation | Time to first value | Day-1 retention | Day-1 by source |
| Engagement | Key feature adoption | DAU/MAU | Session length + freq |
| Retention/Money | Day-7 retention | Day-7, Day-30 cohorts | Churn, ARPU |
| Technical | Crash-free sessions | Cold start time | All + ANR rate |
Rule: max 2 metrics per layer at any one time, each with a named owner. No owner → delete.
React Native instrumentation: the 4 failure modes
This is where most apps get the numbers wrong.
1. The deep-link problem
When a user opens your app from a push notification or marketing URL, your analytics SDK may register a fresh session before your deep-link handler decides which screen to show.
// ❌ Wrong: tracking from componentDidMount / useEffect on each screen
useEffect(() => {
analytics.track('screen_view', { screen: 'home' });
}, []);
// ✅ Right: track from navigation library's listener
import { useNavigationState } from '@react-navigation/native';
const state = useNavigationState((s) => s);
useEffect(() => {
const route = state?.routes?.[state.index];
if (route) analytics.track('screen_view', { screen: route.name, params: route.params });
}, [state?.index]);
Otherwise your funnel will be off by one step on every deep-linked session, and you'll spend a quarter optimizing the wrong screen.
2. The app-state problem
A user backgrounds your app for 90 seconds to check a text, then comes back. Most SDKs default to a 30s session timeout, so your dashboard now reports 2 sessions where the user experienced 1.
// Be explicit about your session definition
import mixpanel from 'mixpanel-react-native';
mixpanel.init('TOKEN', {
// Document this next to every "sessions" chart you publish
trackAutomaticEvents: true,
// Mixpanel defaults to 30s — bump to 5 min for habit apps,
// keep tight for transactional flows
});
Decide your session definition explicitly and document it next to every "sessions" chart you publish.
3. The offline-events problem
A user logs a workout on the subway. Your analytics SDK queues the event and flushes it when connectivity returns — 30 minutes later.
// ❌ Wrong: using only event_timestamp
SELECT date_trunc('hour', event_timestamp), count(*)
FROM events WHERE name = 'workout_completed'
GROUP BY 1;
// ✅ Right: store BOTH timestamps, pick per query
analytics.track('workout_completed', {
workout_type: 'cardio',
client_timestamp: new Date().toISOString(), // when user did it
// server adds event_timestamp on receipt
});
// Then query by client_timestamp for "when did users do this"
// and event_timestamp for "when did our system see it"
If you build dashboards off event_timestamp instead of client_timestamp, your "workouts per hour" chart will spike at the times people emerge from underground.
4. The over-eventing problem
It's tempting to track every tap. Don't.
// Start with this minimal schema, expand only when justified
analytics.track('screen_view', { screen });
analytics.track('feature_action', { feature_name, action });
analytics.track('conversion', { type, value });
Each unnecessary event adds payload, drains battery, costs money at scale (most tools charge per event), and dilutes the events that matter. Start tight. Add events only when you can answer "what decision will this inform."
The default RN stack in 2026
For most React Native apps:
- Firebase Analytics for free baseline + Crashlytics for crash reporting
- One product-analytics tool: Mixpanel, Amplitude, or PostHog (pick one, instrument it well)
- Attribution SDK (AppsFlyer, Adjust) only if running paid acquisition
Don't run three product-analytics tools at once. Pick one and instrument it well.
The point
The best mobile app analytics setup isn't the one with the most dashboards. It's the one with the fewest dashboards that drive real decisions.
Pick the 12 metrics above as a starting menu. Narrow to the 8–12 that match your stage. Give each one an owner. Instrument them carefully enough that the numbers your team argues over are actually the numbers your users experienced.
For the longer write-up — including the full FAQ and the "why AI-built apps make analytics non-optional from day one" angle — see the RapidNative blog.
What's the metric you removed from your dashboard that you should have removed sooner? Drop it in the comments — I'm collecting the screensaver metrics indie devs ship by default for a follow-up.
Top comments (0)