---
title: "PLG Instrumentation for Mobile: Activation Funnels and the Cohort Metrics That Predict Revenue"
published: true
description: "Engineer the PLG measurement layer for mobile — activation event taxonomy, feature flag cohort wiring, and funnel queries that separate engagement from value delivery."
tags: mobile, architecture, android, postgresql
canonical_url: https://mvpfactory.co/blog/plg-instrumentation-mobile-activation-funnels
---
What we will build
By the end of this post you will have a working instrumentation layer for product-led growth on mobile: a three-tier event taxonomy that separates engagement from value delivery, a feature flag schema that survives join-time queries, and two SQL funnels that expose exactly where your onboarding leaks.
Let me show you a pattern I use in every PLG audit. Most mobile teams track button_tapped and call it a day. That produces the most dangerous metric in mobile analytics: a falsely high activation rate.
Prerequisites
- An event pipeline (Amplitude, Segment, or a custom Kafka → warehouse setup)
- Feature flag tooling with variant metadata (LaunchDarkly, Unleash, or similar)
- A SQL-queryable warehouse (Snowflake, BigQuery, or PostgreSQL)
- Engineering and product aligned on what "got value" means for your app
Step 1 — Build the three-tier event taxonomy
Partition your schema into tiers before writing a single tracking call:
| Tier | Event type | Example | PLG signal |
|---|---|---|---|
| 1 | Exposure | feature_viewed |
Reach |
| 2 | Engagement | feature_interacted |
Intent |
| 3 | Value realization | first_export_completed |
Activation |
Tier 3 events are your activation gates. "Completed onboarding" is not a value realization event. "Shared a result with a teammate" might be. This distinction requires a cross-functional session — product, engineering, and revenue all need to agree before you write code.
Step 2 — Embed feature flag metadata directly in event payloads
The docs do not mention this, but the flag_name and flag_variant fields belong in every event fired during an active experiment. Do not rely on server-side joins at query time.
Here is the minimal schema to get this working:
{
"event": "report_shared",
"user_id": "usr_abc123",
"timestamp": "2026-09-09T10:42:00Z",
"properties": {
"feature_flag": "new_share_flow_v2",
"flag_variant": "treatment",
"session_depth": 3,
"days_since_signup": 2,
"recipient_count": 2
}
}
This is non-negotiable. You need to join flag exposure to value realization at query time without a fragile lookup table.
Step 3 — Query flag rollouts against activation, not retention
The standard mistake is evaluating a flag rollout by 7-day retention of treated vs. control. That tells you whether the variant retained users — not whether it moved them to the value tier.
SELECT
flag_variant,
COUNT(DISTINCT user_id) AS exposed_users,
COUNT(DISTINCT CASE WHEN event = 'report_shared' THEN user_id END) AS activated_users,
ROUND(
COUNT(DISTINCT CASE WHEN event = 'report_shared' THEN user_id END) * 100.0
/ COUNT(DISTINCT user_id), 2
) AS activation_rate_pct
FROM events
WHERE flag_name = 'new_share_flow_v2'
AND timestamp >= DATEADD(day, -14, CURRENT_DATE)
GROUP BY flag_variant;
(PostgreSQL/BigQuery: replace DATEADD(day, -14, CURRENT_DATE) with CURRENT_DATE - INTERVAL '14 days'.)
Step 4 — Build the leaky funnel query
Model activation as an ordered sequence of value checkpoints:
signup → profile_complete → first_core_action → value_realization → invite_sent
WITH funnel AS (
SELECT
user_id,
MIN(CASE WHEN event = 'signup' THEN timestamp END) AS t_signup,
MIN(CASE WHEN event = 'first_core_action' THEN timestamp END) AS t_core,
MIN(CASE WHEN event = 'report_shared' THEN timestamp END) AS t_value
FROM events
WHERE timestamp >= DATEADD(day, -30, CURRENT_DATE)
GROUP BY user_id
)
SELECT
COUNT(*) AS signups,
COUNT(t_core) AS reached_core,
COUNT(t_value) AS activated,
AVG(DATEDIFF(minute, t_signup, t_core)) AS avg_minutes_to_core,
AVG(DATEDIFF(minute, t_core, t_value)) AS avg_minutes_core_to_value
FROM funnel;
Here is the gotcha that will save you hours: avg_minutes_core_to_value is where most teams find their biggest leak. If that number exceeds 48 hours, your onboarding is deferring the aha moment until churn has already begun.
Gotchas
Flat event models produce false confidence. Teams that separated "feature exposure" from "value realization" events in audits of three subscription mobile apps saw 2–3x more predictive power on 30-day retention than those using a flat model.
7-day retention is a lagging indicator. Replace it with D3 activation rate — the percentage of signups who hit a Tier 3 event within 72 hours — as your primary PLG health metric. Users who activate within 72 hours convert to paid at 2–4x higher rates within 30 days.
Missing flag metadata breaks cohort analysis. If flag_name isn't in the event payload at fire time, you cannot reconstruct the cohort cleanly after the fact. Embed it always, not just for experiments you think will matter.
Three metrics to track weekly
- D3 activation rate — % of signups hitting a Tier 3 event within 72 hours
- Activation-to-expansion rate — % of activated users who upgrade or expand seats within 30 days
- Flag-cohort retention delta — retention difference between activated users in treatment vs. control, isolated by flag variant
Conclusion
The gap between a stagnant activation rate and compounding expansion revenue comes down to taxonomy precision, flag metadata discipline, and the right funnel queries. Define your Tier 3 events cross-functionally, embed flag context in every payload, and swap 7-day retention for D3 activation rate as your primary health metric before your next rollout.
Docs worth bookmarking: Segment Spec, LaunchDarkly event tracking, dbt funnel patterns.
Top comments (0)