Free data template
A/B test readout
Conversion per variant, the lift, a confidence interval and a plain-language verdict.
It opens with this template loaded and runs in your browser. You don't need an account to use it; a free account saves your work and exports it.
The job it does
When an experiment ends and someone asks "did B win?": a readout you can paste into the decision doc. It comes with its own checks, so after you change it you can see at a glance that it still does the job.
How to use it with your own data
Remove the sample experiment CSV and load your results as experiment.csv (columns variant, visitors, conversions; A is the control).
What's inside
This is the template exactly as the Data Lab opens it, read-only. Open it to run it, change it and export it.
- 2 notebook cells
- Your own CSV files
- CSV file: experiment (2 rows)
An experiment ended and someone asks "did B win?" This readout gives the conversion rate per variant, the lift, a 95% confidence interval for the difference, the p-value, and a verdict in plain words you can paste into the decision doc.
The sample: 10,000 visitors each saw the old checkout (A) and the new one (B).
Your own data: remove the experiment CSV file (Data panel), load yours as experiment.csv (columns variant, visitors, conversions; A is the control) and Run. The criteria pin the sample's numbers: change them to yours, or remove them.
- The notebook runs top to bottom without errors
- lift_pct equals 16 ± 0.01
- p_value equals 0.0123 ± 0.001
- readout has 2 rows
- A bar chart plots rate_pct
import math
# Your own data: replace the "experiment" CSV (columns variant, visitors, conversions; A is the control).
exp = experiment.set_index("variant")
a, b = exp.loc["A"], exp.loc["B"]
rate_a = a["conversions"] / a["visitors"]
rate_b = b["conversions"] / b["visitors"]
lift_pct = float((rate_b - rate_a) / rate_a * 100)
# a two-sided z-test on the difference, and its 95% confidence interval
diff = rate_b - rate_a
se = math.sqrt(rate_a * (1 - rate_a) / a["visitors"] + rate_b * (1 - rate_b) / b["visitors"])
z = diff / se
p_value = float(2 * (1 - 0.5 * (1 + math.erf(abs(z) / math.sqrt(2)))))
ci_low_pts, ci_high_pts = round((diff - 1.96 * se) * 100, 2), round((diff + 1.96 * se) * 100, 2)
readout = experiment.assign(rate_pct=(experiment["conversions"] / experiment["visitors"] * 100).round(2))
readout# The verdict in plain words, for the decision doc
if p_value < 0.05 and ci_low_pts > 0:
verdict = f"B wins: conversion {lift_pct:.1f}% higher (B minus A is {ci_low_pts} to {ci_high_pts} points, p = {p_value:.3f})."
elif p_value < 0.05:
verdict = f"B loses: conversion {lift_pct:.1f}% lower (p = {p_value:.3f})."
else:
verdict = f"No clear winner: the difference ({lift_pct:.1f}%) could be chance (p = {p_value:.2f}). Keep A or run longer."
print(verdict)
chart(readout, x="variant", y="rate_pct", kind="bar", title="Conversion rate (%)")The lesson behind it
Learn why it works, with a podcast and a quiz for each lesson.
More data templates
Simple forecast
A trend plus weekly pattern fitted to daily sales, the next 4 weeks forecast and a check against the last weeks.
KPI dashboard notebook
Weekly revenue, orders, average basket and active customers, with a chart per KPI.