Funnels, activation and adoption
A funnel shows where people drop off on the way to value, and which fix would help most. This lesson teaches you to define and read a funnel, pick an activation moment and measure time to value, and measure adoption of an internal tool in a way you can trust, including the stock transfers that can make a headline adoption number look better than the work on the dock.
By the end you can
- Read step and end-to-end conversion, and find the step where a fix adds the most
- Define a funnel precisely: unit, steps, order, conversion window and cohort
- Choose an activation event and measure time to value
- Measure internal-tool adoption by breadth, depth and persistence, and spot a mix effect in a headline number
- Write the SQL for a funnel and for an adoption split
The everyday picture
In January, 100 people join a neighbourhood gym. Eighty come once. Fifty come five times. By March, thirty still come every week. The sign at the door says "100 members". The trainer knows the real number is thirty.
The trainer learns more from where people stopped than from the sign. Twenty never came at all: maybe nobody gave them the locker code. Thirty came once and stopped: maybe the first session was confusing or too hard. Each drop has its own cause and its own fix, and fixing the first session might keep more people than any new machine.
There is a workplace version too. When a company buys a gym pass for every employee, "members" is 100% on day one, and it says nothing about who is getting fitter. Internal software works the same way: everyone has the app, and the useful question is how much of the work they do in it.
How a funnel works
A funnel counts how many people (or stores, or orders) reach each step on the way to a goal. Two rates come out of it. The step rate is the share of the previous step that reaches this one. The end-to-end rate is the share of everyone who started that reaches the end. The end-to-end rate is all the step rates multiplied together.
Here is the Store app's adoption funnel across Mangrove's 320 stores in the first month of the receiving rollout. "Fully adopted" means a store is still receiving deliveries in the app four weeks after it started.
Two questions decide where to work. Where is the biggest drop? In stores, step 3: 97 stores signed in and never received a delivery in the app. Where would the same effort add the most? Raise any step rate by 10 points and the end-to-end result is multiplied by (new rate ÷ old rate). That ratio is largest where the rate is lowest. Ten points at step 3 (60% to 70%) multiplies the end by 1.17 and adds about 13 fully adopted stores. Ten points at step 2 (80% to 90%) multiplies it by 1.125 and adds about 10.
Fully adopted now: 320 x 0.95 x 0.80 x 0.60 x 0.70 x 0.75 = 76.6 stores
+10 points at step 3 (60 -> 70%): 76.6 x 70/60 = 89.4 (+12.8)
+10 points at step 4 (70 -> 80%): 76.6 x 80/70 = 87.5 (+10.9)
+10 points at step 5 (75 -> 85%): 76.6 x 85/75 = 86.8 (+10.2)
+10 points at step 2 (80 -> 90%): 76.6 x 90/80 = 86.2 (+9.6)
+5 points at step 1 (95 -> 100%): 76.6 x 100/95 = 80.6 (+4.0)Points are not equally easy to win at every step, so treat this as the first cut. And a funnel tells you where people stop, never why. For the why, go and look: visit five stores that signed in and never received in the app, and watch a delivery arrive.
Quick check
Step 1 converts at 95% and step 3 at 60%. You can raise either by 5 points. Which adds more fully adopted stores?
Every step affects everyone after it, so position doesn't matter; the multiplier does. Five points at 60% is an 8.3% relative rise; five points at 95% is 5.3%. The same points are worth more where the rate is low.
Define the funnel before you read it
Two people can build "the adoption funnel" from the same data and get different answers, because a funnel has five settings. Write them down before anyone reads a number.
- Unit. Count stores, staff or deliveries, whichever matches the decision. Rollout waves and training visits are decided per store; a training video is judged per person. The simulator below lets you switch between stores and staff.
- Steps. Each step is one specific event with a precise definition, such as "first supplier delivery received in the app by a person at the store". Events and their definitions are the subject of Instrumentation.
- Order. Must the steps happen in order? Mixpanel's funnels, for example, require the steps in order by default and offer an "any order" option.
- Conversion window. How long a user has to get from the first step to the last. Mixpanel's default is 7 days. For a store rollout, four weeks from go-live is more realistic.
- Cohort. Group people by when they started. A store that went live yesterday can't have reached "still using at week 4" yet.
The cohort setting causes the most common funnel mistake. If you mix stores that went live four weeks ago with stores that went live this week, the later steps look terrible, because most stores haven't had time to get there. Count only units old enough to have completed the window, or show one funnel per start week, the same way you read cohorts in Retention and cohorts.
And when a definition changes, say so on the chart. Changing the window from 7 to 30 days can lift a funnel's end-to-end rate overnight with no change in anyone's behaviour.
Quick check
Three weeks into a rollout, the funnel says only 20% of live stores are "still using at week 4". Wave 2 went live last week. What is wrong?
After three weeks, even the earliest stores haven't reached week 4, so the 20% is an artefact of the window. Changing the unit doesn't fix it. Pausing on this number would be a decision made on a definition error.
Activation and time to value
Activation is the moment a new user first gets the core value. A good activation event is early, specific and predictive: people who reach it are much more likely to stay than people who don't. Amplitude's write-up of north star metrics notes, for example, that in its early days Facebook tracked how many new users added seven friends in their first ten days: an early, specific action tied to the value of the product.
To find yours:
- List early actions that might matter: first order, first on-time delivery, first repeat order, adding an address, saving a list.
- Compare people who were still active at week 4 with people who weren't. Which early action separates them most?
- Prefer an action the product can help people reach. "Placed a second order within 14 days" is useful; "lives near a store" is not something onboarding can change.
- Treat it as a hypothesis. Heavy users do everything, so many actions correlate with staying. The test is causal: help more people reach the event (better onboarding, a nudge) and check whether retention follows (Experiments).
Time to value is how long activation takes, usually as a median. For the Mangrove app it is the time from install to the first on-time delivery, the "30 minutes, really?" moment. Every hour of that time is a chance to drop out: an empty first screen, a slot that's full, an item cut from the order. Onboarding that shortens it is the subject of pm-32.
For the Store app, value arrives with the first delivery received in the app instead of on paper. If a store goes live on Monday and its first app receipt is on Thursday, staff have spent three days on paper, and the old habit has had three more days to win. The funnel's step 3 is the activation step, and the time from go-live to that first receipt is the time to value. That is why the rollout plan in Launching puts a trainer in the store for the first delivery.
Adoption of internal tools
Store staff can't uninstall the Store app, but they can keep the paper on the side. So "staff who logged in" says little; head office can make it 100% with one email. Measure adoption as the share of the work done in the tool, in four dimensions:
- Breadth: stores where receiving in the app is switched on and staff are signed in.
- Depth: the share of each store's deliveries received in the app.
- Frequency: every delivery, every shift, including the 6 am delivery when the trained person isn't on.
- Persistence: still at that depth at week 4 and week 12, after the trainer has left.
Then measure the workaround that should die, as in pm-11: paper goods received note pads ordered from the print room, photos of delivery notes in chat groups. If the app says 90% and the print room still sends 400 pads a month, believe the print room.
Two definitions decide whether the adoption number is honest. First, who did the work. Count a delivery as received in the app only when a person scanned it at the store. Some systems close an unreceived stock transfer automatically after a day or two; an auto-closed receipt is the opposite of adoption, and it must not be counted as one. Second, which deliveries are in the denominator, which is where stock transfers come in.
Each Mangrove store gets about 4 supplier deliveries a day and about 2 stock transfers from its DC. A transfer arrives with an electronic transfer note, so receiving it in the app is one barcode scan, and nearly every one (about 98%) is received in the app. A supplier delivery is the hard case: the driver's paperwork, line-by-line checks, quantities that don't match the purchase order. If one headline number mixes the two, it rises and falls with the mix of deliveries as well as with what staff do. Statisticians call the extreme version of this Simpson's paradox.
The fix is in the reporting, not the arithmetic. Report adoption by delivery type, lead with supplier deliveries, keep transfers as a separate line, and show the counts next to the rates so a change in mix is visible. If you need one headline for a slide, use the supplier rate and say so.
Quick check
The week after a festival, the headline "deliveries received in the app" falls 6 points, and the head of operations asks why stores stopped using the app. Supplier deliveries were at 60% in the app both weeks. What happened?
If the supplier rate is unchanged and transfers are nearly always in the app, fewer transfers means a lower headline with identical behaviour. A data bug is always worth ruling out, but the split already explains the whole change.
Try it. The simulator starts with the step rates above (95%, 80%, 60%, 70%, 75%): 77 of 320 stores fully adopted. Each step shows what "Improve this step by 10 points" would add before you press it; compare them, then press the best one and see the new biggest drop. Press "Reset the rates" and try the worst one. Finally, switch Count to Staff to see the same funnel for 1,920 people.
- The best 10-point fix is at the lowest rate, and here that is also the biggest drop. When those two differ, the lowest rate usually wins.
- One step at 0% stops the whole funnel. In a rollout, that is the store where nobody was trained for the early delivery.
Do it
Build an adoption funnel and an honest adoption definition for a feature or tool you are rolling out.
Pick the unit and the eligible group
Choose the unit your decisions are made in. Include only units old enough to have completed the window.
Write each step as one event
Name the event, its source and its exact definition. Set the order and the conversion window.
Pull the counts and find the leak
Compute step rates and the end-to-end rate. Find the biggest drop and the step where 10 points adds most.
Go and see why
Visit or call five users who stopped at the leaky step. Write down what they did instead.
Define "adopted" as real work
Count work done by a person in the tool, split by type of work, and add the workaround that should disappear as a check.
Markdown# Adoption funnel: Store app receiving (wave 1 and 2) Unit: store. Eligible: stores live 4+ weeks (160). Window: 4 weeks from go-live. | # | Step | Event and source | Stores | Step rate | |---|--------------------------------|------------------------------------------|--------|-----------| | 1 | App installed | 2+ handhelds have the app (device mgmt) | 152 | 95% | | 2 | Staff signed in | staff_signed_in, both receivers | 122 | 80% | | 3 | First delivery in app | first supplier GRN, received_via = app | 73 | 60% | | 4 | Five deliveries in app | 5 supplier GRNs in the app | 51 | 70% | | 5 | Still using at week 4 | 80%+ of week-4 supplier GRNs in the app | 38 | 75% | Leak: step 3. Store visits (5): early deliveries with no trained person; pack sizes that don't match the PO; handheld not charged. Fix to test in wave 3: train both receivers, pack-size conversion, charging rule. "Adopted" means: 80%+ of SUPPLIER deliveries received in the app by a person at the dock, 4 weeks in a row. Transfers reported on a separate line. Auto-closed receipts never count. Check: paper GRN pads ordered per month. Guardrail: minutes from truck arrival to GRN posted must not rise.
Bring it to your team
Ask these whenever a funnel or an adoption number is on the screen.
- What is the unit, the window, and who is included? Has any of it changed since last time?
- Are we mixing people who started this week with people who started a month ago?
- Which step has the lowest rate, and has anyone watched a user stop there?
- Does "adopted" count work done in the tool, or log-ins?
- What is in the denominator? Would the number change if the mix of work changed?
- Which workaround should be disappearing, and is it?
Red flags
- An adoption target met by a mandate to log in.
- One headline percentage with no counts and no split by type.
- System auto-closes or rep-entered orders counted as user adoption.
- A funnel whose definition changed without a note on the chart.
- A fix chosen from the funnel alone, with nobody having talked to a user.
Practice
Write the funnel query
Six stores are rolling out the Store app. store_app_event(site_id, event, occurred_on) holds app_installed and staff_signed_in events (a store can sign in on many days). grn(id, site_id, received_via, received_on) holds goods received notes, with received_via either app or paper. Return one row with the columns stores, installed, signed_in, received_1 (stores with at least one GRN received in the app) and received_3 (at least three). Count stores, not rows. If you need a refresher on count(DISTINCT …) and CTEs, see SQL you'll actually use.
CREATE TABLE site (id int PRIMARY KEY, site_code text NOT NULL); CREATE TABLE store_app_event (site_id int NOT NULL, event text NOT NULL, occurred_on date NOT NULL); CREATE TABLE grn (id int PRIMARY KEY, site_id int NOT NULL, received_via text NOT NULL, received_on date NOT NULL); INSERT INTO site VALUES (1, 'S001'), (2, 'S002'), (3, 'S003'), (4, 'S004'), (5, 'S005'), (6, 'S006'); INSERT INTO store_app_event VALUES (1, 'app_installed', '2026-09-01'), (2, 'app_installed', '2026-09-01'), (3, 'app_installed', '2026-09-02'), (4, 'app_installed', '2026-09-02'), (5, 'app_installed', '2026-09-03'), (1, 'staff_signed_in', '2026-09-01'), (1, 'staff_signed_in', '2026-09-02'), (1, 'staff_signed_in', '2026-09-03'), (2, 'staff_signed_in', '2026-09-02'), (3, 'staff_signed_in', '2026-09-03'), (3, 'staff_signed_in', '2026-09-04'), (4, 'staff_signed_in', '2026-09-04'); INSERT INTO grn VALUES (1, 1, 'app', '2026-09-02'), (2, 1, 'app', '2026-09-03'), (3, 1, 'app', '2026-09-04'), (4, 1, 'app', '2026-09-05'), (5, 2, 'app', '2026-09-03'), (6, 2, 'paper', '2026-09-03'), (7, 2, 'app', '2026-09-04'), (8, 2, 'app', '2026-09-05'), (9, 3, 'app', '2026-09-04'), (10, 3, 'paper', '2026-09-04'), (11, 3, 'paper', '2026-09-05'), (12, 3, 'paper', '2026-09-06'), (13, 4, 'paper', '2026-09-05'), (14, 4, 'paper', '2026-09-06'), (15, 5, 'paper', '2026-09-05'), (16, 5, 'paper', '2026-09-06');
-- Store app funnel: one row, one column per step
SELECT (SELECT count(*) FROM site) AS stores,
(SELECT count(*) FROM store_app_event WHERE event = 'app_installed') AS installed,
(SELECT count(*) FROM store_app_event WHERE event = 'staff_signed_in') AS signed_in;
[{"stores": 6, "installed": 5, "signed_in": 4, "received_1": 3, "received_3": 2}]
Show a solution
WITH app_receipts AS ( -- one row per store: GRNs received in the app
SELECT site_id, count(*) AS n
FROM grn
WHERE received_via = 'app'
GROUP BY site_id
)
SELECT
(SELECT count(*) FROM site) AS stores,
(SELECT count(DISTINCT site_id) FROM store_app_event
WHERE event = 'app_installed') AS installed,
(SELECT count(DISTINCT site_id) FROM store_app_event
WHERE event = 'staff_signed_in') AS signed_in, -- DISTINCT: S001 signed in 3 times
(SELECT count(*) FROM app_receipts WHERE n >= 1) AS received_1,
(SELECT count(*) FROM app_receipts WHERE n >= 3) AS received_3;The starter counts event rows, so a store that signs in every day counts many times and the funnel can even get wider at a later step. A funnel counts units. Here the biggest drop is between "signed in" (4) and "three in the app" (2), which is the same leak as the 320-store funnel.
Split the headline adoption number
The table delivery(id, site_id, source, received_via) holds one week's deliveries for a few stores. source is supplier or transfer; received_via is app, paper or auto (closed automatically by the system, which is not adoption). The starter computes the dashboard's single headline. Return one row per source with deliveries, in_app (received by a person in the app) and in_app_pct rounded to one decimal.
CREATE TABLE delivery (id int PRIMARY KEY, site_id int NOT NULL, source text NOT NULL, received_via text NOT NULL); INSERT INTO delivery VALUES (1, 1, 'supplier', 'app'), (2, 1, 'supplier', 'app'), (3, 1, 'supplier', 'paper'), (4, 1, 'transfer', 'app'), (5, 1, 'transfer', 'auto'), (6, 2, 'supplier', 'app'), (7, 2, 'supplier', 'paper'), (8, 2, 'supplier', 'paper'), (9, 2, 'transfer', 'app'), (10, 3, 'supplier', 'app'), (11, 3, 'supplier', 'app'), (12, 3, 'supplier', 'paper'), (13, 3, 'supplier', 'app'), (14, 3, 'transfer', 'app'), (15, 3, 'transfer', 'app');
-- The dashboard headline: everything not on paper counts as "in app"
SELECT count(*) AS deliveries,
count(*) FILTER (WHERE received_via <> 'paper') AS in_app,
round(100.0 * count(*) FILTER (WHERE received_via <> 'paper') / count(*), 1) AS in_app_pct
FROM delivery;
[{"source": "supplier", "deliveries": 10, "in_app": 6, "in_app_pct": 60.0}, {"source": "transfer", "deliveries": 5, "in_app": 4, "in_app_pct": 80.0}]
Show a solution
SELECT source,
count(*) AS deliveries,
count(*) FILTER (WHERE received_via = 'app') AS in_app, -- auto is not adoption
round(100.0 * count(*) FILTER (WHERE received_via = 'app') / count(*), 1) AS in_app_pct
FROM delivery
GROUP BY source;The starter's headline is 11 of 15, 73.3%, because it mixes the two sources and counts the auto-closed transfer. Split and cleaned, supplier deliveries, the hard part, are at 60%.
Check yourself
New partner shops: 600 invited, 480 installed the Partner app (80%), 240 placed a first order in it (50%), 192 placed a third (80%). You can fund one improvement worth about 10 points at one step. Where?
Ten points multiplies the end by 60 ÷ 50 = 1.2 at the first order, against 90 ÷ 80 = 1.125 at either other step, so 192 becomes about 230 there and about 216 elsewhere. The first order also has the biggest drop here (240 shops), so both rules agree. Position in the funnel doesn't matter; the rate does, and spreading the effort thin gives up the best multiplier.
The week after the analytics team changed the funnel's conversion window from 7 to 30 days, the Mangrove app's sign-up-to-first-order rate jumped from 24% to 31%. The growth lead wants to credit the new onboarding, which shipped the same week. What do you say?
A longer window lets more people complete the funnel without anyone behaving differently. You can only credit the onboarding after comparing like with like, ideally against a control group. Splitting credit is a guess, and retention doesn't make the funnel question go away.
Head office tells every store manager to sign in to the Store app daily. "Staff signed in" goes to 100%. The share of supplier deliveries received in the app stays at 61%. What should the monthly adoption report lead with?
Sign-ins measure obedience to an instruction, not work done in the tool. Depth on the hard work (supplier deliveries) is the honest adoption number, and the workaround count confirms it. Including transfers would blur it with a mix that changes every festival.
Flashcards
Key takeaways
- A funnel's end-to-end rate is its step rates multiplied. The same 10 points add most where the rate is lowest.
- Define unit, steps, order, window and cohort before reading a funnel, and note every definition change on the chart.
- Activation is the first moment of core value; pick an early event that predicts staying, then prove it by moving it.
- Internal-tool adoption is the share of real work done in the tool by a person, checked against the dying workaround.
- Split headline adoption by type of work. A change in mix, such as festival stock transfers, can move it with no change in behaviour.
Sources and further reading
- Funnels: advanced (conversion window, step order, uniques and totals), Mixpanel documentation
- Every Product Needs a North Star Metric, Amplitude blog, 2024 (Facebook's seven friends in ten days)
- Alistair Croll and Benjamin Yoskovitz, Lean Analytics, O'Reilly, 2013
- Samuel Hulick, The Elements of User Onboarding, UserOnboard, 2014