Conversion Funnel Optimization Questions
Analyzing and improving a bounded, ordered conversion path: mapping the sequence of steps a user takes from acquisition through one terminal conversion or activation event (signup, first purchase, first paid order, trial-to-paid, onboarding to first-success), computing step-to-step and overall conversion rates and drop-off, and diagnosing where and why users fall out. Covers the SQL and query techniques for computing funnel metrics at scale (stage-by-stage conversion tables, time-to-conversion and time-to-first-value, cohort LTV measured within a funnel window, path analysis across non-linear user journeys, event instrumentation and data-quality practices for funnel tracking), attribution modeling for crediting conversions across channels and touchpoints (first-touch, last-touch, linear, time-decay, Markov-chain, and Shapley-value approaches) and customer acquisition cost by channel, and the experiment design and statistics used to validate funnel changes (A/B and multi-armed-bandit test design, sample-size and power calculations, quasi-experimental methods such as difference-in-differences and synthetic control when randomization is not possible, and testing whether a single funnel-stage drop is a real, statistically significant shift rather than noise). Also covers diagnosing UX and flow friction that causes drop-off (checkout, signup, and onboarding friction points) and prioritizing a program of funnel-improvement experiments (impact and effort frameworks such as RICE or ICE, guardrail metrics, roadmap sequencing). Distinct from User Retention and Engagement, which covers what an already-converted or already-activated user does afterward: repeat usage over time, cohort retention curves, DAU/WAU/MAU, churn, and reactivation. A question belongs here if it concerns a user's first, bounded pass toward one conversion or activation event; it belongs to User Retention and Engagement if it concerns recurring behavior after that event. General-purpose rolling-window anomaly and change-point detection techniques (CUSUM, Bayesian change-point, seasonality-aware baselines) for monitoring any metric over time belong to the companion topic Advanced SQL: Metric Monitoring, Anomaly Detection, and Data Correctness at Scale, not here.
How would you model and measure conversion when users follow many different non-linear paths to the same outcome (multi-path journeys)? Describe at least three analytical methods or visualizations you would use and explain when each is appropriate.
Sample Answer
Direct answer
When conversion happens through many different non-linear paths, no single visualization or model captures the whole picture, so a strong answer names several complementary methods rather than one. A practical combination is: sequence clustering to compress the combinatorial explosion of raw paths into a small number of journey archetypes, Markov chain transition modeling to quantify how much each step actually matters to conversion probability, a Sankey (flow) diagram to communicate the biggest branch points to stakeholders, and graph centrality analysis on the journey graph to find structurally important bottleneck steps. Each answers a different question: "what are the common shapes of the journey," "how much does this step matter probabilistically," "where do people visually go," and "which steps sit on the most paths."
Structured elaboration
1. Sequence / path clustering (n-gram or edit-distance based). Represent each user's journey as an ordered sequence of step tokens (for example [landing, search, product, cart, exit]). Two clustering approaches are common: (a) extract fixed-length n-grams (bigrams, trigrams of consecutive steps) and cluster users by the n-gram frequency profile of their journey, or (b) compute pairwise sequence-similarity (Levenshtein / edit distance, or a weighted alignment that penalizes step substitution and skipping differently) and run hierarchical or k-means-on-embeddings clustering directly on full sequences. Output is a small number of "journey archetypes" (for example "browse then buy," "search then compare then abandon," "direct to cart via a promo link") instead of thousands of literally distinct raw paths. When appropriate: this is the right first move whenever the number of distinct raw paths is too large to enumerate or eyeball directly, which is exactly the "many different non-linear paths" case the question describes; it turns an intractable long tail into a workable number of groups you can report conversion rates for and design interventions around.
2. Markov chain transition modeling. Treat each distinct step (plus two absorbing states, Convert and Drop-off) as a state in a first-order Markov chain. Estimate the transition matrix P empirically: Pij is the fraction of times users at step i moved next to step j, counted directly from the event log. From P you can compute, for any state, the probability of eventually reaching the Convert absorbing state (a standard absorbing-Markov-chain calculation), and the removal effect of a step: rerun the same absorption calculation with that step's outgoing edges rerouted straight to Drop-off, and compare the resulting overall conversion probability to the baseline. A large drop signals a step that is structurally load-bearing for conversion, even if it does not look important by raw traffic volume alone. When appropriate: use this when you need a quantitative, probabilistic answer to "how much does step X matter," not just a picture of where people go; the real limitation to name is the first-order (memoryless) assumption, that the next step depends only on the current step and not on the fuller history, which is a simplification for genuinely non-linear journeys where earlier steps can shape later behavior (a higher-order or second-order Markov model, conditioning on the last two steps instead of one, is the direct extension when memorylessness is clearly violated in the data).
3. Sankey / flow diagram. Aggregate all users' step-to-step transitions into edge weights (counts or percentages) between a bounded set of named steps or page-groups, and render as a flow diagram whose band width encodes volume. When appropriate: this is a communication tool more than an analytical one; it is the right choice when the audience is stakeholders who need to see, at a glance, where the biggest branches and biggest drop-offs are, and it works best when the step set is small and grouped (dozens of raw URLs collapsed into a handful of page-types), since a flow diagram with hundreds of distinct nodes becomes unreadable.
4. Graph centrality analysis on the journey graph. Build a directed, weighted graph where nodes are steps and edges are observed transition frequencies, then compute standard centrality measures: in-degree and out-degree for raw traffic through a node, a PageRank-style score for a node's structural importance across the whole graph (a node reached mostly through other important nodes scores high even with modest direct traffic), and betweenness centrality to find nodes that lie on the largest number of shortest paths between entry points and the conversion state (bridge or bottleneck nodes). When appropriate: use this when the question is "which touchpoints matter structurally across the whole tangled graph of paths," distinct from the Markov chain's focus on probability of conversion; centrality is agnostic to conversion outcome and instead measures a node's role in connecting the graph, which is useful for finding a page that, if it broke, would disconnect many otherwise-unrelated journeys.
Worked example
A small illustrative event log for six users moving through steps Landing, Search, Product, Cart, Checkout, Convert, and Exit:
| User | Path |
|---|---|
| 1 | Landing -> Search -> Product -> Cart -> Checkout -> Convert |
| 2 | Landing -> Product -> Cart -> Checkout -> Convert |
| 3 | Landing -> Search -> Product -> Exit |
| 4 | Landing -> Search -> Product -> Cart -> Exit |
| 5 | Landing -> Product -> Exit |
| 6 | Landing -> Search -> Product -> Cart -> Checkout -> Convert |
Applying the four methods to this tiny log: sequence clustering would group users 1 and 6 into a "full search-led path" archetype, users 3 and 4 into a "search-led abandon" archetype, and users 2 and 5 as a "direct-to-product" archetype, three clusters instead of six distinct raw paths, each with its own conversion rate (2/2 = 100% for the search-led-converters cluster, 0/2 for the search-led-abandon cluster). Markov modeling: counting every step-to-step transition in the table directly, Product is reached by all six users and its outgoing transitions split Cart 4 times and Exit 2 times, so P(Product→Cart)=4/6≈0.667 and P(Product→Exit)=2/6≈0.333; of the four users who reach Cart, three continue to Checkout and one exits, so P(Cart→Checkout)=3/4=0.75. The removal effect of Search (rerouting Search's traffic straight to Exit instead of letting it continue to Product) would show a large modeled conversion drop here, since four of the six users route through Search on the way to Product, and three of this sample's three converters (users 1, 2, 6) reach Product either via Search or directly. A Sankey diagram of this log would visually show the widest band leaving Landing splitting into Search (4 of 6 users) and direct-to-Product (2 of 6), both bands merging back into a single wide band at Product, then narrowing through Cart and Checkout into Convert. Centrality: Product has the highest in-degree (all six paths pass through it, versus four through Search and four through Cart) and would score highest on betweenness, since it sits on the path between every entry route and every outcome, making it the single structural bottleneck node in this graph regardless of which branch a user took to reach it.
Trade-offs and pitfalls
- Sequence clustering is sensitive to how you tokenize steps: too fine-grained (every distinct URL) and clusters fragment into noise; too coarse (collapsing meaningfully different pages into one token) and you lose the branching structure you were trying to capture. Group steps at a level that matches a real product decision (page-type, not raw URL).
- The Markov chain's removal effect is a modeled counterfactual, not an experimental result. It answers "what does the model predict would happen," which is a reasonable prioritization signal but not a substitute for actually testing the change; treat a large removal effect as a strong hypothesis to test, not as proof.
- A common mistake is picking exactly one of these methods and treating it as the whole analysis. A Sankey diagram alone tells you nothing about statistical significance or counterfactual impact; a Markov model alone gives no intuitive picture for a stakeholder review. The methods are complementary, not substitutes for each other.
- Loops and repeated steps (a user revisiting
Productmultiple times) need an explicit policy before any of these methods can run cleanly, either collapse consecutive repeats into one token before clustering and Markov estimation, or keep them and accept that the state space and path count both grow; decide this before building rather than discovering it mid-analysis. - All four methods assume the step taxonomy itself is stable and correctly instrumented; if steps are inconsistently logged (see event-instrumentation practices for funnel tracking more broadly), every one of these techniques will confidently model noise as structure.
Write an ANSI SQL query to compute 'time to first value' (TTFV) where TTFV = time difference between the 'sign_up' event and the first 'key_action' event for each user. Table: events(user_id, event_name, event_timestamp). Describe how you will treat users who never perform the key action and how you compute median TTFV across the user base.
Sample Answer
Direct answer
Compute time to first value (TTFV, the elapsed time between a user's sign_up event and their FIRST key_action event) with a join between each user's earliest sign_up and their earliest key_action, treat users who never fire a key_action as right-censored (they have no observed TTFV, not a TTFV of infinity or zero), and compute the median only over the uncensored users, since the censored users' true (eventual, or never) conversion time is unknown and including them would require an assumption the data does not support.
Structured elaboration
Right-censoring, defined precisely for this case. A user is right-censored when the event that would let you measure their TTFV (the key_action) has not happened by the time you are looking at the data, and might never happen, or might still happen later; you cannot distinguish "will never convert" from "hasn't converted YET" purely from the absence of a key_action event. This is the same right-censoring problem that shows up whenever a metric is measured against an event that has not necessarily resolved yet.
Two defensible ways to handle censored users, and why "drop" is the simpler default here. Option 1: exclude censored users entirely from the median calculation, computing median TTFV only over users who HAVE converted. This is simple, always well-defined, and answers "for users who do eventually get to value, how long does it typically take," a genuinely useful operational question (does onboarding get people to value fast). Option 2: treat censored users' TTFV as right-censored data in a formal survival-analysis sense (Kaplan-Meier estimation), which can estimate a median time-to-event even in the presence of censoring, PROVIDED enough of the censored users would eventually convert; if a large fraction never will, a survival-analysis median may not even exist (the survival curve never crosses 50%). For most product-analytics reporting, Option 1 (drop and report the censoring rate alongside the median) is the more interpretable and more commonly used default; Option 2 is worth reaching for when the actual question is closer to "estimate the true underlying time-to-convert distribution accounting for the fact that some of today's non-converters will convert tomorrow," a more specialized ask.
Computing median TTFV. Extract each user's TTFV (as a numeric delta, hours or days) via SQL for only the users who have a key_action event, then compute the median in application code (Python's statistics.median, or an equivalent) over that list; this is simpler and equally legitimate compared to a SQL-native percentile function, and avoids relying on a warehouse-specific percentile syntax that varies across engines.
Worked example
Schema: events(user_id, event_name, event_timestamp). Seven synthetic users: five convert at varying speeds (2, 5, 10, 26, and 100 hours), one (u2) fires key_action TWICE (the query must use the FIRST occurrence, not a later duplicate), and two (u5, u7) never fire key_action at all, right-censored.
CREATE TABLE events (user_id TEXT, event_name TEXT, event_timestamp TIMESTAMP);
INSERT INTO events VALUES
('u1','sign_up','2026-07-01 00:00:00'),
('u1','key_action','2026-07-01 02:00:00'),
('u2','sign_up','2026-07-01 00:00:00'),
('u2','key_action','2026-07-02 02:00:00'),
('u2','key_action','2026-07-03 02:00:00'), -- duplicate, later occurrence; must NOT be used
('u3','sign_up','2026-07-01 00:00:00'),
('u3','key_action','2026-07-01 05:00:00'),
('u4','sign_up','2026-07-01 00:00:00'),
('u4','key_action','2026-07-05 04:00:00'),
('u5','sign_up','2026-07-01 00:00:00'), -- never fires key_action: right-censored
('u6','sign_up','2026-07-01 00:00:00'),
('u6','key_action','2026-07-01 10:00:00'),
('u7','sign_up','2026-07-01 00:00:00'); -- never fires key_action: right-censored
-- One row per user: sign_up_ts, first_key_action_ts (NULL if never performed,
-- i.e. right-censored), and ttfv_hours (NULL for censored users).
WITH signups AS (
SELECT user_id, MIN(event_timestamp) AS sign_up_ts
FROM events
WHERE event_name = 'sign_up'
GROUP BY user_id
),
first_key_action AS (
-- MIN() here is the dedup: a user who fires key_action multiple times
-- (u2) only has the EARLIEST occurrence counted toward TTFV.
SELECT user_id, MIN(event_timestamp) AS key_action_ts
FROM events
WHERE event_name = 'key_action'
GROUP BY user_id
)
SELECT
s.user_id,
s.sign_up_ts,
k.key_action_ts,
CASE WHEN k.key_action_ts IS NOT NULL
THEN ROUND((julianday(k.key_action_ts) - julianday(s.sign_up_ts)) * 24, 2)
ELSE NULL
END AS ttfv_hours,
CASE WHEN k.key_action_ts IS NULL THEN 1 ELSE 0 END AS is_censored
FROM signups s
LEFT JOIN first_key_action k ON k.user_id = s.user_id
ORDER BY s.user_id;
Output (actually executed against SQLite; julianday() is SQLite's date-arithmetic function, the equivalent of TIMESTAMP_DIFF in BigQuery):
user_id sign_up_ts key_action_ts ttfv_hours censored
u1 2026-07-01 00:00:00 2026-07-01 02:00:00 2.0 0
u2 2026-07-01 00:00:00 2026-07-02 02:00:00 26.0 0
u3 2026-07-01 00:00:00 2026-07-01 05:00:00 5.0 0
u4 2026-07-01 00:00:00 2026-07-05 04:00:00 100.0 0
u5 2026-07-01 00:00:00 NULL NULL 1
u6 2026-07-01 00:00:00 2026-07-01 10:00:00 10.0 0
u7 2026-07-01 00:00:00 NULL NULL 1
u2's key_action_ts correctly resolves to 26 hours (the FIRST occurrence), not a later duplicate the raw event log also contains.
import statistics
ttfv_hours = [2.0, 26.0, 5.0, 100.0, None, 10.0, None] # u1..u7, in that order (None = censored)
uncensored_deltas = [v for v in ttfv_hours if v is not None]
censored_count = sum(1 for v in ttfv_hours if v is None)
median_ttfv = statistics.median(uncensored_deltas)
print(f"Uncensored users: {len(uncensored_deltas)}, censored (never converted): {censored_count}")
print(f"Uncensored TTFV values (hours), sorted: {sorted(uncensored_deltas)}")
print(f"Median TTFV (uncensored only): {median_ttfv} hours")
print(f"Right-censoring rate: {censored_count / len(ttfv_hours):.2%}")
Output (actually executed):
Uncensored users: 5, censored (never converted): 2
Uncensored TTFV values (hours), sorted: [2.0, 5.0, 10.0, 26.0, 100.0]
Median TTFV (uncensored only): 10.0 hours
Right-censoring rate: 28.57%
With an odd count of 5 uncensored values, the median is simply the middle value once sorted, 10.0 hours; reporting the 28.57% right-censoring rate ALONGSIDE the median is what keeps this number honest, since a median TTFV computed only over the 71% who converted says nothing about the users who have not, and a reader seeing "median TTFV = 10 hours" without that context could wrongly assume most users convert quickly.
Complexity
Both CTEs are O(n) single-pass aggregations over the events table (one GROUP BY each), so the SQL portion is O(n) in the number of relevant sign_up and key_action rows; the LEFT JOIN is O(n) given an index or hash join on user_id. Computing the median in Python over the extracted per-user deltas is O(mlogm) for a sort-based median (statistics.median) where m is the number of uncensored users, negligible compared to the SQL aggregation at realistic scale, but note that this only works when the number of uncensored users is small enough to comfortably extract to application memory; at very large scale, a SQL-native approximate-percentile function is the better choice.
Edge cases
- A user who fires
key_actionbefore ever firingsign_up(a data-quality anomaly, perhaps a pre-signup guest action logged under the same eventual user_id): the query as written would still compute a negativettfv_hours, since it takes a raw difference without a floor at zero; a production version should validatekey_action_ts >= sign_up_tsand flag or exclude violations rather than silently reporting a negative TTFV. - A user with NO
sign_upevent at all (perhaps a data-pipeline gap): absent entirely from thesignupsCTE and therefore absent from the whole result, which is correct, since TTFV is undefined without a sign_up anchor. - Ties in the median calculation with an EVEN count of uncensored users:
statistics.medianaverages the two middle values, standard practice, worth confirming your chosen median implementation does the same rather than picking one of the two arbitrarily.
Trade-offs and pitfalls
- Common mistake: computing "median TTFV" over ALL users, including censored ones, by substituting some large sentinel value (or the observation-window length) for their missing TTFV. This silently biases the median toward whatever sentinel was chosen and produces a number that changes depending on an arbitrary implementation detail rather than reflecting anything real about user behavior.
- Reporting the median alone without the censoring rate is incomplete. A median TTFV of 10 hours over a 95%-converted population tells a very different story than the same 10-hour median over a 30%-converted population; the censoring rate is not optional context, it changes what the median-TTFV number is even evidence OF.
- A near-identical generic 'median time from first touch to purchase' variant of this same question, without the TTFV/key-action framing specifically, uses the identical dedup-and-censoring technique, only the two event names change (first touch, purchase, instead of sign_up, key_action); nothing about the right-censoring handling or the median computation needs to change for that variant.
Compute required sample size for an A/B test where baseline conversion is 10% and you want to detect a 10% relative lift (i.e., increase to 11% absolute), with 80% power and a 5% two-sided significance level. Show the formula, calculation steps, and final sample size per variant. Explain approximations and caveats.
Sample Answer
Direct answer
For a baseline conversion rate of 10% and a target 10% relative lift (an absolute increase to 11%), at 80% power and a 5% two-sided significance level, the required sample size is 14,751 users per variant (29,502 total), computed with the standard two-proportion z-test sample-size formula and verified in code rather than looked up. The two biggest caveats to state alongside that number: the formula assumes a fixed sample size decided in advance and analyzed once (not repeatedly peeked at), and it assumes exactly one comparison, running the same kind of test many times across funnel steps and segments requires correcting the significance threshold, which materially increases the required sample size.
Structured elaboration
The formula. For detecting a difference between baseline conversion rate p1 and target rate p2, with two-sided significance level α and power 1−β, the required sample size per variant is
n=(p2−p1)2(zα/22pˉ(1−pˉ)+zβp1(1−p1)+p2(1−p2))2where pˉ=(p1+p2)/2 is the pooled average rate used for the critical-value term, zα/2 is the standard normal critical value for the chosen two-sided significance level, and zβ is the standard normal value corresponding to the chosen power.
Every calculation step, for p1=0.10, p2=0.11, α=0.05, power =0.80:
- zα/2=z0.025=1.9600 (the value beyond which 2.5% of the standard normal distribution lies on each tail, for a 5% two-sided test)
- zβ=z0.20=0.8416 (the value corresponding to 80% power)
- pˉ=(0.10+0.11)/2=0.105
- Critical-value term: zα/22pˉ(1−pˉ)=1.9600×2×0.105×0.895=1.9600×0.1880=1.9600×0.4335=0.8497
- Power term: zβp1(1−p1)+p2(1−p2)=0.8416×0.10×0.90+0.11×0.89=0.8416×0.09+0.0979=0.8416×0.1879=0.8416×0.4335=0.3648
- Sum, squared, over (p2−p1)2=0.012=0.0001: n=(0.8497+0.3648)2/0.0001=1.21452/0.0001=1.4751/0.0001=14,751 (rounding the intermediate sum up slightly at each displayed step; the exact, unrounded computation below gives 14,750.79, rounded up to 14,751)
Final answer: n = 14,751 per variant, 29,502 total across both variants.
Approximations and caveats in the formula itself. This is the normal (Wald-style) approximation to the binomial, accurate for the sample sizes this kind of calculation typically produces, but technically an approximation, not an exact result; some practitioners add a small continuity correction for extra conservatism, which this answer omits since the effect is negligible at n in the thousands. The formula also assumes a FIXED sample size decided before the test starts and analyzed exactly once at the end; a test monitored continuously and stopped as soon as significance is first observed (without a formal sequential-testing correction) will falsely "succeed" far more often than the stated 5% significance level implies, because repeated looks each carry their own chance of a false positive.
Worked example
All arithmetic verified in Python (statistics.NormalDist, no external library required), not by hand or by eyeballing z-scores:
import math
from statistics import NormalDist
nd = NormalDist()
def sample_size_two_proportion(p1, p2, alpha=0.05, power=0.8):
z_alpha = nd.inv_cdf(1 - alpha / 2)
z_beta = nd.inv_cdf(power)
p_bar = (p1 + p2) / 2
term1 = z_alpha * math.sqrt(2 * p_bar * (1 - p_bar))
term2 = z_beta * math.sqrt(p1 * (1 - p1) + p2 * (1 - p2))
n = ((term1 + term2) ** 2) / ((p2 - p1) ** 2)
return n, math.ceil(n)
print("Primary (10% -> 11%):", sample_size_two_proportion(0.10, 0.11))
print("Companion (5% -> 6%):", sample_size_two_proportion(0.05, 0.06))
m = 10
print(f"Bonferroni-corrected, m={m} concurrent tests:",
sample_size_two_proportion(0.10, 0.11, alpha=0.05 / m))
Output (actually executed):
Primary (10% -> 11%): (14750.79046904495, 14751)
Companion (5% -> 6%): (8157.731447849276, 8158)
Bonferroni-corrected, m=10 concurrent tests: (25019.652834268625, 25020)
Companion instance, at different baseline and lift numbers. For a baseline of 5% detecting a 20% relative lift (to 6% absolute), holding power and significance fixed at the same 80% and 5% two-sided, the required sample size is 8,158 per variant, noticeably smaller than the primary case despite testing a comparable relative lift, because the absolute gap between the two rates (1 percentage point in both cases) sits on a smaller baseline variance term at 5% than at 10%.
Multiplicity: what changes when many tests run concurrently
Running this same kind of sample-size-and-significance calculation independently across many funnel steps and many segments (checking, say, 10 different step-by-segment slices in the same rollout) inflates the true chance of at least one false positive far above the nominal 5% significance level per test; with 10 independent tests each run at 5%, the chance of at least one false "significant" result by pure chance is 1−(1−0.05)10≈40%, not 5%. Two standard corrections address this, with different trade-offs:
- Bonferroni correction. Divide the target significance level by the number of comparisons, αcorrected=α/m, and use THAT corrected alpha in the sample-size formula's zα/2 term. This is simple and conservative (it controls the probability of ANY false positive across all m tests, the family-wise error rate), but it is a strict, often overly cautious correction, and it directly and substantially inflates the required sample size, computed above: for m=10, αcorrected=0.005, giving zα/2=2.8070 instead of 1.9600, and the required sample size rises to 25,020 per variant, a 1.696x inflation over the uncorrected 14,751.
- Benjamini-Hochberg procedure. Instead of fixing a single stricter alpha for every test in advance, this method controls the false discovery rate (FDR, the expected proportion of "significant" results that are actually false positives, rather than the probability of any false positive at all) by ranking all m tests' p-values after the data is collected and comparing each rank's p-value to a rank-dependent threshold. It is meaningfully more powerful than Bonferroni for the same nominal error-control target, since it does not treat every test as if it needed the full worst-case correction, but its correction is inherently a function of the actual observed p-values, not a single fixed number known before the study runs, so it is typically applied at the ANALYSIS stage after data collection rather than used directly, in closed form, to size the study in advance the way Bonferroni's fixed corrected alpha can be.
Trade-offs and pitfalls
- The Bonferroni-inflated sample size (25,020 per variant for 10 concurrent tests) is a real operational cost, not just an abstract statistical nicety; a team that runs many simultaneous funnel-step experiments without planning for this will either under-power every individual test or need to accept a much longer data-collection window, and this trade-off should be surfaced to stakeholders before the rollout, not discovered afterward when none of the ten tests reach significance.
- A common mistake is applying a multiplicity correction to the significance threshold used for ANALYSIS while never adjusting the sample-size calculation that determined how long the test would run, which produces an experiment that was never actually powered to detect the effect at the stricter, corrected threshold it will be judged against.
- Continuously monitoring a running test and stopping the moment it crosses significance, without a sequential-testing correction, invalidates the 5% significance-level guarantee this calculation is built on; if early stopping is operationally necessary, use a sequential testing method (such as a group-sequential design with pre-specified alpha spending) rather than an ad hoc "check daily, stop when significant" practice layered on top of a fixed-sample-size calculation.
- The formula's power term uses p1 and p2's own individual variances (the more standard, slightly more accurate approach), while the critical-value term uses the pooled pˉ; a simplified version some calculators use applies pˉ to BOTH terms, which is a reasonable approximation when p1 and p2 are close together (verified directly: this simplification gives 14,752 for the primary case here, versus 14,751 with the more precise unpooled power term, a 0.01% difference) but diverges more as the two rates get further apart, so know which version a given calculator or teammate is using before comparing numbers.
A spike in mobile checkout drop-off occurred on 2025-01-15. As the BI analyst on-call, outline the immediate 24-hour triage steps you would take: which dashboards and queries to run, slices to inspect, logs to request from engineering, and how you'd communicate status to product and ops teams.
Sample Answer
Direct answer
The on-call analyst's job in the first 24 hours is triage, not root-cause certainty: confirm the spike is real, narrow it to a specific slice fast, hand engineering a concrete, checkable lead rather than a vague "checkout is broken," and keep product and ops continuously updated on status rather than waiting for a finished analysis. The single most important early decision is whether this is a genuine product regression or a data/reporting artifact, since that determines who needs to be paged and how urgently.
Structured elaboration
Dashboards and queries, in order.
- Sanity check first: is the spike real? Compare the dashboard's drop-off number against a raw event count for the same day (or an independent source, like a payment provider's own transaction log, if one is readily available). A dashboard-only drop with flat raw counts points toward a reporting or instrumentation bug, not a real user-facing problem, and changes everything downstream.
- The existing mobile checkout funnel dashboard, filtered to the spike date versus a trailing baseline (the prior 1-2 weeks on the same weekday, to control for normal day-of-week variation), to confirm which specific step's conversion rate actually dropped rather than assuming the whole funnel is affected uniformly.
- An ad hoc query segmenting the affected step's drop-off by OS, app version or build number, and payment method, to check for a platform- or version-specific pattern before escalating.
Slices to inspect. Device/OS version, app build number (specifically checking whether a mobile app release shipped on or just before 2025-01-15), payment method, geography, and new-versus-returning user. A drop concentrated in one app version is a very different, and much faster, diagnosis than a drop spread evenly across the whole mobile population.
The data-issue-versus-product-regression decision point. This is the single fork that most determines what happens next, and it should be made explicitly, not assumed: if raw event counts genuinely dropped (step 1 above) and the timing correlates with a recent release, treat it as a likely product regression and escalate to engineering with release-rollback urgency. If the dashboard number dropped but an independent raw count did not, treat it as a data-quality incident, real user impact is likely much smaller or absent, and the fix path routes to whoever owns the reporting pipeline rather than to a release rollback decision, though it still needs same-day resolution for reporting integrity. Making this call quickly, and stating it explicitly in the first status update, prevents the classic failure mode of an entire team mobilizing around a "broken checkout" that turns out to be a broken dashboard.
Logs to request from engineering. Client-side error or crash logs for the mobile checkout screens specifically, filtered to the spike window; server-side error rate and latency for the checkout and payment endpoints over the same window; payment-gateway decline or error logs, since a spike in declines looks identical to a UX-driven drop-off in a conversion dashboard but has a completely different fix; and the deploy/release log for anything shipped to the mobile app or checkout backend in the day or two before the spike.
Communicating status to product and ops. The two audiences need different things from the same underlying facts: product needs to know user impact and whether there's a clear path to a fix, ops needs to know operational severity and whether this should be escalated as a formal incident. Send a short, timestamped update as soon as the data-versus-regression call is made, even before a root cause is confirmed: what's confirmed so far, what's still being checked, the current best hypothesis, and when the next update will come. Waiting for a complete analysis before the first communication is a common mistake in a 24-hour triage window; a stakeholder needs a status now, even an incomplete one, more than a perfect answer several hours later.
Worked example
A near-identical version of this same triage, at a slightly longer 48-hour window: a signup drop-off spike immediately following a product release. The same decision point applies directly, check whether raw signup-attempt counts (not just the reported signup-completion rate) also dropped. If raw attempts stayed flat while completions dropped, that is consistent with a product regression in the signup flow itself introduced by the release (a broken validation rule, a form field that stopped submitting correctly on one platform), and the release becomes the primary suspect requiring an urgent rollback conversation with engineering. If raw attempts themselves also dropped, that points further upstream, toward an acquisition, traffic-routing, or tracking-pixel issue introduced by the same release rather than a signup-form bug specifically, which changes who gets paged first. In both the checkout and signup versions of this scenario, the release timeline is the fastest lead precisely because it turns "something in this whole complex flow" into "check what specifically changed in this one deploy."
Trade-offs and pitfalls
- Escalating to a full incident and paging multiple teams before confirming the spike is even real (versus a reporting artifact) wastes real organizational attention and erodes trust in future pages; the sanity check against a raw or independent count is cheap and should always come first.
- Waiting to communicate until the full root cause is known, rather than sending an early, honest "here's what we know and don't know yet" update, is the most common way this kind of triage damages stakeholder trust, not the eventual accuracy of the diagnosis itself.
- Jumping straight to "it must be the release" without checking whether raw event counts (not just the reported rate) actually moved risks chasing a regression that doesn't exist, when the real cause is a dashboard or pipeline issue introduced by the same release, a subtly different problem with a completely different fix.
- This triage is deliberately scoped to the first 24 (or 48) hours; if the sanity checks and slice analysis do not converge on a clear lead within that window, the right move is to hand off to a fuller diagnostic program (instrumentation validation, deeper exploratory analysis, a prioritized experiment queue) rather than continuing an open-ended ad hoc investigation past the point where the on-call triage format is still the right tool.
Your freemium product converts 2% of free users to paid. Propose a prioritized sequence of product changes and experiments you would run over 6 months to move conversion to 5%. For each experiment include hypothesis, primary metric, and success threshold.
Sample Answer
Direct answer
Moving free-to-paid conversion from 2% to 5% is a 150% relative increase, too large to bet on any single test, so the right deliverable is a sequenced, 6-month roadmap of experiments, front-loaded with the highest-confidence, lowest-effort changes to build early evidence and momentum, escalating toward bigger, riskier swings once the cheap wins are exhausted. Every experiment in the sequence needs its own stated hypothesis, primary metric, and success threshold, and the roadmap as a whole needs an honest, explicit check on whether the cumulative target is actually achievable in the stated window, which is a distinct and necessary part of the answer, not just the list of experiments itself.
Structured elaboration
Why sequencing, not just a list, matters. Running experiments in priority order rather than in parallel or arbitrary order does two things a flat list does not: it lets each experiment's real result inform whether the next one's underlying assumption still holds (an onboarding-friction fix that under-performs suggests the team's theory of what's blocking conversion needs revision before investing in a bigger, related bet), and it produces early, credible wins that justify continued investment in the later, more expensive experiments to skeptical stakeholders.
Sequencing logic used below. Early months prioritize changes that are cheap to build, fast to measure, and target a well-understood friction point (signup and first-session experience) where a positive result is likely and the downside of a negative result is small. Later months escalate to changes that require more engineering investment, take longer to reach a valid read (a trial-length experiment cannot conclude faster than the trial itself), or touch acquisition mix rather than only in-product behavior. This is the same confidence-versus-effort logic behind formal prioritization frameworks like RICE (reach, impact, confidence, effort) or ICE (impact, confidence, ease); here that logic is applied directly to produce an ordering, not re-derived as its own separate framework.
Alternative ways to arrive at a similar sequence, worth naming briefly. The same prioritized-experiment-sequence approach applies directly if the target metric were a B2B activation rate moving from 20% to 35% instead of a freemium-to-paid rate moving from 2% to 5%: the sequencing LOGIC (cheap and high-confidence first, expensive and uncertain later) does not change, only the specific experiments shift toward B2B-relevant activation levers (a guided admin setup wizard, a dedicated onboarding call for larger accounts) instead of freemium in-product prompts. A second, equally valid way to derive a sequence is customer-journey mapping: lay out every touchpoint from signup through billing (signup, first login, first key action, the upgrade moment, checkout) and design one experiment per touchpoint, rather than ranking by confidence and effort; this tends to produce a similar set of experiments organized by WHERE in the journey they sit rather than by WHEN to run them, which is a useful alternate lens when communicating the roadmap to stakeholders who think in journey stages.
Worked example
| Month | Experiment | Hypothesis | Primary metric | Success threshold |
|---|---|---|---|---|
| 1 | Contextual, usage-triggered upgrade prompt (replacing a generic "Upgrade" navigation link with a prompt shown when a user hits a specific usage limit) | Prompting at the moment a user feels a real constraint converts better than a passive, always-available link, because the prompt arrives when willingness to pay is highest | Free-to-paid conversion rate among prompted users vs. a held-out control shown the old generic link | At least a 1-percentage-point (pp) absolute lift in free-to-paid conversion for the prompted cohort, measured over a 30-day post-prompt window |
| 2 | Personalized onboarding email sequence, tailored to which features a user actually touched in their first session | A sequence referencing the user's own observed usage converts better than a generic feature-tour sequence, because it demonstrates relevance instead of asking the user to self-identify their use case | 30-day free-to-paid conversion rate, personalized vs. generic sequence, among users who opened at least one email | 0.5pp absolute lift, with email open rate not degrading (a guardrail, since a lift driven by only the most-engaged users opening more emails would not be a true win) |
| 3 | Time-boxed full-feature premium trial (rather than the standard permanently-gated freemium experience) offered to users showing engagement signals correlated with past conversions | Removing feature-gating uncertainty for a genuinely engaged cohort converts better than asking them to infer premium value from a gated experience | Trial-to-paid conversion rate among trial-eligible users who accept the trial | Trial-to-paid conversion rate of at least 25% (chosen against the team's own historical baseline for comparable time-boxed trials elsewhere in the product, not invented here) |
| 4 | Pricing/paywall page redesign clarifying the specific value gap between free and paid tiers (a feature-comparison layout replacing a plan-name-only comparison) | A paywall that names the SPECIFIC feature or limit a user is about to hit converts better than one that just lists plan names and prices | Paywall-view-to-checkout-start conversion rate | At least a 2pp absolute lift in paywall-to-checkout-start rate |
| 5 | App-store listing update (revised screenshots and description leading with the premium value proposition, rather than only the free feature set) | Attracting a higher-intent installer population at the acquisition step raises free-to-paid conversion among NEW cohorts, without requiring any change to in-product behavior for existing users | Free-to-paid conversion rate among users acquired via the app store, comparing cohorts acquired after the listing change to a matched pre-change cohort | At least a 0.5pp absolute lift in free-to-paid conversion specifically within the app-store-acquired cohort |
| 6 | Guided setup checklist for a specific high-value user segment (mirroring the same lever a B2B-marketplace merchant-activation program would use to raise activation), sized with an explicit sample-size calculation | A short, structured setup checklist shown to new users in this segment raises their activation-to-paid conversion by making the path to first value explicit rather than self-directed | Segment-specific free-to-paid conversion rate, checklist-shown vs. control | A 3-percentage-point absolute lift, from an assumed 8% segment baseline to 11%, detected at 80% power and 5% two-sided significance |
The month-6 sample-size calculation, worked explicitly (compact version: applied directly below using the standard two-proportion formula, without re-deriving it from first principles). Using the standard two-proportion sample-size formula
n=(p2−p1)2(zα/22pˉ(1−pˉ)+zβp1(1−p1)+p2(1−p2))2with p1=0.08, p2=0.11, zα/2=1.9600 (5% two-sided significance), and zβ=0.8416 (80% power), the computed sample size is 1,499 users per arm (2,998 total), actually computed in Python rather than estimated:
import math
from statistics import NormalDist
nd = NormalDist()
p1, p2, alpha, power = 0.08, 0.11, 0.05, 0.8
z_alpha, z_beta = nd.inv_cdf(1 - alpha/2), nd.inv_cdf(power)
p_bar = (p1 + p2) / 2
n = ((z_alpha*math.sqrt(2*p_bar*(1-p_bar)) + z_beta*math.sqrt(p1*(1-p1)+p2*(1-p2)))**2) / (p2-p1)**2
print(f"n per arm (raw) = {n:.2f}, ceil = {math.ceil(n)}, total = {2*math.ceil(n)}")
Output (actually executed): n per arm (raw) = 1498.39, ceil = 1499, total = 2998. This is what actually determines whether month 6 is even a realistically completable experiment: if this segment has materially fewer than roughly 3,000 eligible new users across the month, the experiment as designed cannot reach a conclusive read in the available time, and either the effect size being tested for needs to be larger (accepting the risk of missing a real but smaller effect) or the experiment needs to run longer than the single month slotted for it in this roadmap.
Trade-offs and pitfalls
- The arithmetic reality of the target deserves explicit acknowledgment. Moving from 2% to 5% free-to-paid conversion is a 150% relative increase; even optimistic individual experiments in a reasonably mature product typically produce single-digit-to-low-teens percent RELATIVE lifts each, not 150% in aggregate from six experiments. A senior answer states this tension directly rather than presenting the roadmap as guaranteed to hit the target: either the current 2% baseline reflects specific, large, fixable frictions (plausible if the product is young or has known major UX gaps, in which case bigger individual lifts are genuinely achievable), or the 5% target itself needs to be revisited as the roadmap's early results come in, with the sequencing designed to surface that reality quickly (front-loading experiments) rather than only in month 6.
- Each experiment's success threshold should be tied to what the CUMULATIVE roadmap needs to add up to the target, not chosen independently per experiment; a set of individually "successful" experiments that each clear their own small threshold can still fall well short of the 2%-to-5% goal if nobody checked the arithmetic adds up across all six.
- A common mistake is running all six experiments as fully independent, non-interacting bets; several of these (the upgrade prompt, the personalized emails, the paywall redesign) touch overlapping parts of the same conversion moment and can interact (a redesigned paywall changes the context the upgrade prompt is shown in), so later experiments in the sequence should account for the compounding effect of earlier shipped changes rather than being designed and analyzed in isolation as if the product were unchanged.
- The app-store-listing experiment (month 5) is measurement-different from the others in a way worth flagging: because it changes acquisition mix rather than in-product behavior, its "success" metric is necessarily cohort-based (comparing users acquired before versus after the change) rather than a randomized A/B split of existing users, which is a weaker causal design and more vulnerable to confounds like seasonality; treat its result with correspondingly more caution than the randomized in-product experiments.
Unlock Full Question Bank
Get access to all 46 Conversion Funnel Optimization interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.