Stats & Product Analytics for Analysts
Back to A/B Testing in Practice

Anatomy of an A/B Test Result

Reading a real test dashboard. The five numbers that matter and the ten that don't.

3 minutesReading
🎯 Free Guest Mode: You are learning for free. Sign in to save your completion progress and quiz answers.

Focus on: Sample Size per arm, Primary Lift Point Estimate, 95% Confidence Interval, p-value, and Guardrail Status.

A/B test results evaluation in Python

import numpy as np
from statsmodels.stats.proportion import proportions_ztest, confint_proportions_2indep

# Sample: 14-day experiment results
# Control: 1,420 converted / 20,000 visitors (7.10%)
# Treatment: 1,580 converted / 20,000 visitors (7.90%)
n_c, conv_c = 20000, 1420
n_t, conv_t = 20000, 1580

p_c = conv_c / n_c
p_t = conv_t / n_t
abs_lift = p_t - p_c
rel_lift = abs_lift / p_c

z_stat, p_value = proportions_ztest([conv_t, conv_c], [n_t, n_c])
ci_low, ci_high = confint_proportions_2indep(conv_t, n_t, conv_c, n_c, alpha=0.05)

print(f"Control Rate:   {p_c:.2%}")
print(f"Treatment Rate: {p_t:.2%}")
print(f"Absolute Lift:  {abs_lift:+.2%} (Relative: {rel_lift:+.2%})")
print(f"95% CI on Lift: [{ci_low:+.2%}, {ci_high:+.2%}]")
print(f"P-value:        {p_value:.4f}")

mde = 0.005 # 0.5pp
if p_value < 0.05 and ci_low > 0 and abs_lift >= mde:
    print("🚀 VERDICT: SHIP IT. Clears statistical significance and MDE bar.")
else:
    print("🛑 VERDICT: DO NOT SHIP.")

Takeaway

Five numbers tell the real story. Ignore noisy daily fluctuation graphs.

Loading progress...