Appendix A

FOR YOUR ANALYST

The formulas behind the three calculators, and three queries every store should be able to run.

The formulas

ForFormulaNotes
Visitors per versionn = 16 × p(1 − p) / d²p: current conversion rate. d: absolute change to detect. 95% confidence, 80% power; use 21 for 90% power.
Smallest detectable liftL = √(16(1 − p) / (p × n))Relative lift, for n visitors per version.
Power at nΦ(d × √(n / (2p(1 − p))) − 1.96)n is visitors per version. Φ is the standard normal cumulative distribution function.
False winners(1 − s)(α/2) / ((1 − s)(α/2) + s × power)s: share of ideas that work. α: two-sided threshold. Kohavi, Deng and Vermeer, 2022.
Split checkχ² = Σ (observed − expected)² / expectedOne degree of freedom for two versions. Flag p < 0.0005.
Two-version resultz = (pB − pA) / √(p̄(1 − p̄)(1/nA + 1/nB))p̄: pooled conversion rate, for the p-value. The range is for the ratio pB/pA: exp(ln(pB/pA) ± 1.96√((1 − pA)/xA + (1 − pB)/xB)) − 1, where x is orders. The verdict follows the range.

Randomize and count at the same level. If the tool assigns visitors, analyze visitors, not sessions or page views. A visitor who comes back five times is one visitor, and counting their sessions separately makes the result look more certain than it is.

The funnel by device

-- sessions reaching each step, last 28 days, by device
-- events: one row per event, with session_id, device, name, ts
SELECT device,
       COUNT(DISTINCT session_id)                                         AS sessions,
       COUNT(DISTINCT session_id) FILTER (WHERE name = 'view_item')       AS viewed_product,
       COUNT(DISTINCT session_id) FILTER (WHERE name = 'add_to_cart')     AS added_to_cart,
       COUNT(DISTINCT session_id) FILTER (WHERE name = 'begin_checkout')  AS began_checkout,
       COUNT(DISTINCT session_id) FILTER (WHERE name = 'add_shipping_info') AS entered_shipping,
       COUNT(DISTINCT session_id) FILTER (WHERE name = 'add_payment_info') AS entered_payment,
       COUNT(DISTINCT session_id) FILTER (WHERE name = 'purchase')        AS purchased
FROM events
WHERE ts >= CURRENT_DATE - INTERVAL '28 days'
GROUP BY device;

The event names follow Google Analytics 4’s recommended ecommerce events; rename them to match your setup. The syntax is Postgres; in BigQuery, write COUNT(DISTINCT IF(name = 'add_to_cart', session_id, NULL)). Divide each column by the one before to get each step’s pass rate, and compare phones with desktop step by step. Express wallets can skip the shipping and payment events, so a step above 100% means an event is missing, not a miracle.

The split check

-- visitors assigned to each version, counted once each
SELECT variant, COUNT(DISTINCT visitor_id) AS visitors
FROM exposures
WHERE experiment_id = 'pdp-delivery-date'
GROUP BY variant;

Put the two counts into the reader in chapter 5. Run the check daily in the first days of any test, not only at the end: a broken split caught on day two costs two days.

Page traffic for the traffic table

-- visitors, orders and conversion for visitors who saw a page type
SELECT page_type,
       COUNT(DISTINCT s.visitor_id) AS visitors,
       COUNT(DISTINCT o.order_id)   AS orders,
       COUNT(DISTINCT o.order_id)::numeric
         / COUNT(DISTINCT s.visitor_id) AS orders_per_visitor
FROM page_views s
LEFT JOIN orders o
  ON o.visitor_id = s.visitor_id
 AND o.ordered_at BETWEEN s.viewed_at AND s.viewed_at + INTERVAL '1 day'
WHERE s.viewed_at >= CURRENT_DATE - INTERVAL '28 days'
GROUP BY page_type
ORDER BY visitors DESC;

This counts an order toward a page if it came within a day of the visit. That’s an approximation, and a generous one, but it’s the right shape for deciding which pages can carry a test.

This is one chapter of The Honest Test, which is free and readable in full on a single page with no form in front of it.