Etsy · Data Science
Checkout Redesign A/B Test
The work
Etsy Checkout Redesign A/B Test Analysis
Author: Senior Product Analyst, Checkout Team
Date: September 2025
Dataset Window: September 2, 2025 – September 29, 2025Executive Summary & Final Launch Recommendation
Recommendation: CHANGE & RETEST (PHASED LAUNCH)
- Desktop Launch: LAUNCH IMMEDIATELY to 100% of Desktop users.
- Mobile & Tablet Launch: DO NOT LAUNCH. Maintain Mobile/Tablet users on the Control checkout.
- Next Steps: Conduct mobile usability auditing, investigate mobile form friction / payment integration issues, fix touch UX bugs, and launch a dedicated Mobile A/B retest.
Summary of Key Findings:
- Experiment Data Integrity: Out of 31,000 unique assigned users, 284 users (0.92%) were assigned to both control and treatment groups (cross-device/cookie tracking leakage). A total of 85 pre-assignment orders and 19 mixed-user orders were identified and removed. Post-cleaning, 30,716 clean users (15,339 Control vs. 15,377 Treatment) and 2,566 valid post-assignment orders were analyzed.
- No Sample Ratio Mismatch (SRM): The clean user split is 49.94% Control vs 50.06% Treatment (chi2 = 0.047, p = 0.8283), matching the planned 50/50 split.
- Overall Aggregated Results (Masked Divergence): At the aggregate level, conversion rate rose from 7.26% to 7.73% (+0.47 pp, +6.47% relative), but this overall change is not statistically significant (p = 0.1180) due to large, opposing effects by device type.
- Massive Device Divergence (Key Insight):
- Desktop Users (+34.3% Rel Lift): Conversion rate surged from 7.54% to 10.13% (+2.59 pp, Z = 5.60, p < 0.0001). Revenue Per User (RPU) jumped from $5.38 to $7.28 (+$1.90 RPU).
- Mobile Users (-23.0% Rel Drop): Conversion rate collapsed from 7.07% to 5.45% (-1.63 pp, Z = -3.86, p = 0.0001). RPU dropped from $4.95 to $3.94 (-$1.01 RPU).
- Tablet Users (-22.9% Rel Drop): Conversion rate fell from 6.61% to 5.10% (-1.51 pp, p = 0.1064).
- Financial Impact Comparison (Test Cohort Scale: ~30.7k Monthly Users):
- Full Launch (All Devices): Estimated monthly net gain of +$12,612 (95% CI: [-$1,889, +$27,113]). High variance and CI crosses zero because mobile losses offset desktop gains.
- Phased Launch (Desktop Only): Estimated monthly net revenue gain of +$28,455 (95% CI: [+$17,509, +$39,401]) — capturing 100% of desktop upside while completely eliminating mobile revenue loss.
- In [1]:
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from scipy import stats import os # Visual styling plt.style.use('seaborn-v0_8-whitegrid' if 'seaborn-v0_8-whitegrid' in plt.style.available else 'default') plt.rcParams['font.sans-serif'] = 'Arial' plt.rcParams['figure.dpi'] = 150 print('Libraries successfully imported!') 1. Experiment Data Validation & Integrity Checks
Before performing statistical analysis, we inspect the datasets for:
- Users assigned to multiple variants (mixed users).
- Orders placed before user assignment timestamps.
- Assignments outside the experiment time window.
- Sample Ratio Mismatch (SRM) against the 50/50 target split.
- In [2]:
ass_path = r'checkout-redesign-ab-test-datasets/checkout-redesign-ab-test/assignments.csv' ord_path = r'checkout-redesign-ab-test-datasets/checkout-redesign-ab-test/orders.csv' ass = pd.read_csv(ass_path) ord_df = pd.read_csv(ord_path) ass['assigned_at'] = pd.to_datetime(ass['assigned_at']) ord_df['ordered_at'] = pd.to_datetime(ord_df['ordered_at']) print(f"Raw Assignments rows: {len(ass):,}") print(f"Raw Unique users: {ass['user_id'].nunique():,}") print(f"Raw Orders rows: {len(ord_df):,}") print(f"Raw Unique buyers: {ord_df['user_id'].nunique():,}") # 1. Mixed user identification v_counts = ass.groupby('user_id')['variant'].nunique() mixed_users = set(v_counts[v_counts > 1].index) print(f"\n[CHECK 1] Users assigned to BOTH control & treatment: {len(mixed_users):,}") # 2. Pre-assignment orders ass_sorted = ass.sort_values(['user_id', 'assigned_at']) first_ass = ass_sorted.groupby('user_id').first().reset_index() ord_merged = ord_df.merge(first_ass[['user_id', 'assigned_at', 'variant']], on='user_id', how='left') pre_ass_orders = ord_merged[ord_merged['ordered_at'] < ord_merged['assigned_at']] print(f"[CHECK 2] Total orders placed BEFORE assignment: {len(pre_ass_orders):,}") # Clean Data Filtering clean_users = ass_sorted[~ass_sorted['user_id'].isin(mixed_users)].groupby('user_id').first().reset_index() clean_orders = ord_df.merge(clean_users[['user_id', 'variant', 'assigned_at']], on='user_id', how='inner') valid_orders = clean_orders[clean_orders['ordered_at'] >= clean_orders['assigned_at']].copy() print(f"\n=== POST-CLEANING SUMMARY ===") print(f"Clean Assigned Users: {len(clean_users):,}") print(f"Valid Post-Assignment Orders: {len(valid_orders):,}") print(f"Removed Users: {len(mixed_users):,}") print(f"Removed Orders: {len(ord_df) - len(valid_orders):,} (19 mixed-user orders + 85 pre-assignment orders)") - In [3]:
# Sample Ratio Mismatch (SRM) Test n_c = (clean_users['variant'] == 'control').sum() n_t = (clean_users['variant'] == 'treatment').sum() total_n = n_c + n_t chi2, p_val_srm = stats.chisquare([n_c, n_t], [total_n/2, total_n/2]) print(f"Control Users: {n_c:,} ({n_c/total_n:.2%})") print(f"Treatment Users: {n_t:,} ({n_t/total_n:.2%})") print(f"Chi-Square Stat: {chi2:.4f}, p-value: {p_val_srm:.4f}") if p_val_srm > 0.01: print("SUCCESS: No Sample Ratio Mismatch (SRM) detected. Traffic split is consistent with 50/50.") else: print("WARNING: SRM detected!") 2. Overall Primary & Secondary Metrics Analysis
- Primary Metric: Conversion Rate (% of assigned users who placed at least 1 order post-assignment).
- Secondary Metrics: Average Order Value (AOV) per order, Revenue Per User (RPU).
- In [4]:
# Aggregate orders per user user_orders = valid_orders.groupby('user_id').agg( n_orders=('order_id', 'count'), total_revenue=('order_value', 'sum') ).reset_index() df = clean_users.merge(user_orders, on='user_id', how='left') df['n_orders'] = df['n_orders'].fillna(0).astype(int) df['total_revenue'] = df['total_revenue'].fillna(0.0) df['converted'] = (df['n_orders'] > 0).astype(int) # Metric Stats c_df = df[df['variant'] == 'control'] t_df = df[df['variant'] == 'treatment'] c_ord = valid_orders[valid_orders['variant'] == 'control'] t_ord = valid_orders[valid_orders['variant'] == 'treatment'] # 1. Conversion Rate cr_c = c_df['converted'].mean() cr_t = t_df['converted'].mean() diff_cr = cr_t - cr_c rel_cr = diff_cr / cr_c se_cr = np.sqrt(cr_c*(1-cr_c)/len(c_df) + cr_t*(1-cr_t)/len(t_df)) z_cr = diff_cr / se_cr p_cr = 2 * (1 - stats.norm.cdf(abs(z_cr))) ci_cr = [diff_cr - 1.96*se_cr, diff_cr + 1.96*se_cr] # 2. AOV aov_c = c_ord['order_value'].mean() aov_t = t_ord['order_value'].mean() diff_aov = aov_t - aov_c t_stat_aov, p_aov = stats.ttest_ind(t_ord['order_value'], c_ord['order_value'], equal_var=False) se_aov = np.sqrt(c_ord['order_value'].var()/len(c_ord) + t_ord['order_value'].var()/len(t_ord)) ci_aov = [diff_aov - 1.96*se_aov, diff_aov + 1.96*se_aov] # 3. RPU rpu_c = c_df['total_revenue'].mean() rpu_t = t_df['total_revenue'].mean() diff_rpu = rpu_t - rpu_c t_stat_rpu, p_rpu = stats.ttest_ind(t_df['total_revenue'], c_df['total_revenue'], equal_var=False) se_rpu = np.sqrt(c_df['total_revenue'].var()/len(c_df) + t_df['total_revenue'].var()/len(t_df)) ci_rpu = [diff_rpu - 1.96*se_rpu, diff_rpu + 1.96*se_rpu] print('=== OVERALL METRICS COMPARISON ===') print(f'Conversion Rate: Control = {cr_c:.4%}, Treatment = {cr_t:.4%}') print(f' Abs Lift: {diff_cr:+.4%} ({diff_cr*100:+.2f} pp), Rel Lift: {rel_cr:+.2%}') print(f' 95% CI: [{ci_cr[0]:+.4%}, {ci_cr[1]:+.4%}], Z-stat = {z_cr:.4f}, p-val = {p_cr:.4f}') print(f'Average Order Value (AOV): Control = ${aov_c:.2f}, Treatment = ${aov_t:.2f}') print(f' Abs Lift: ${diff_aov:+.2f}, Rel Lift: {diff_aov/aov_c:+.2%}') print(f' 95% CI: [${ci_aov[0]:+.2f}, ${ci_aov[1]:+.2f}], t-stat = {t_stat_aov:.4f}, p-val = {p_aov:.4f}') print(f'Revenue Per User (RPU): Control = ${rpu_c:.2f}, Treatment = ${rpu_t:.2f}') print(f' Abs Lift: ${diff_rpu:+.2f}, Rel Lift: {diff_rpu/rpu_c:+.2%}') print(f' 95% CI: [${ci_rpu[0]:+.2f}, ${ci_rpu[1]:+.2f}], t-stat = {t_stat_rpu:.4f}, p-val = {p_rpu:.4f}') 3. Segment Breakdown & Multiple Testing Correction
We analyze conversion rate and revenue performance by device type (Desktop, Mobile, Tablet) and visitor type (New vs. Returning), accounting for multiple testing.
- In [5]:
def run_segment_analysis(df_input, valid_orders_input, group_col): results = [] for cat in sorted(df_input[group_col].unique()): sub = df_input[df_input[group_col] == cat] sub_orders = valid_orders_input[valid_orders_input['user_id'].isin(sub['user_id'])] c_sub = sub[sub['variant'] == 'control'] t_sub = sub[sub['variant'] == 'treatment'] n_c, n_t = len(c_sub), len(t_sub) cr_c, cr_t = c_sub['converted'].mean(), t_sub['converted'].mean() diff_cr = cr_t - cr_c rel_cr = diff_cr / cr_c if cr_c > 0 else 0 se_cr = np.sqrt(cr_c*(1-cr_c)/n_c + cr_t*(1-cr_t)/n_t) z_cr = diff_cr / se_cr if se_cr > 0 else 0 p_cr = 2 * (1 - stats.norm.cdf(abs(z_cr))) rpu_c, rpu_t = c_sub['total_revenue'].mean(), t_sub['total_revenue'].mean() diff_rpu = rpu_t - rpu_c results.append({ 'Segment': cat, 'Control Users': n_c, 'Treatment Users': n_t, 'Control Conv': cr_c, 'Treatment Conv': cr_t, 'Abs Conv Lift (pp)': diff_cr * 100, 'Rel Conv Lift (%)': rel_cr * 100, 'Z-stat': z_cr, 'p-value': p_cr, 'Control RPU': rpu_c, 'Treatment RPU': rpu_t, 'RPU Diff ($)': diff_rpu }) return pd.DataFrame(results) dev_results = run_segment_analysis(df, valid_orders, 'device') dev_results['Bonferroni Sig (alpha=0.0167)'] = dev_results['p-value'] < (0.05 / 3) print('=== DEVICE SEGMENT BREAKDOWN ===') print(dev_results[['Segment', 'Control Conv', 'Treatment Conv', 'Abs Conv Lift (pp)', 'Rel Conv Lift (%)', 'p-value', 'Bonferroni Sig (alpha=0.0167)', 'RPU Diff ($)']]) - In [6]:
vtype_results = run_segment_analysis(df, valid_orders, 'visitor_type') print('=== VISITOR TYPE BREAKDOWN ===') print(vtype_results[['Segment', 'Control Conv', 'Treatment Conv', 'Abs Conv Lift (pp)', 'Rel Conv Lift (%)', 'p-value', 'RPU Diff ($)']]) 4. Financial Impact Modeling & Launch Scenarios
We model monthly revenue impact ranges (95% CIs) under two strategy options:
- Full Launch (All Devices): Deploying redesign everywhere.
- Phased Launch (Desktop Only): Deploying redesign to Desktop while keeping Mobile/Tablet on Control.
- In [7]:
def model_revenue_scenario(sub_df, name): c = sub_df[sub_df['variant'] == 'control']['total_revenue'] t = sub_df[sub_df['variant'] == 'treatment']['total_revenue'] n_total = len(c) + len(t) diff_rpu = t.mean() - c.mean() se_rpu = np.sqrt(c.var()/len(c) + t.var()/len(t)) ci_rpu = [diff_rpu - 1.96*se_rpu, diff_rpu + 1.96*se_rpu] monthly_impact = diff_rpu * n_total ci_impact = [ci_rpu[0] * n_total, ci_rpu[1] * n_total] print(f'=== SCENARIO: {name} ===') print(f'Monthly Users in Cohort: {n_total:,}') print(f'RPU Delta: ${diff_rpu:+.2f} (95% CI: [${ci_rpu[0]:+.2f}, ${ci_rpu[1]:+.2f}])') print(f'Monthly Revenue Impact (Test Cohort): ${monthly_impact:+,.2f}') print(f'95% CI Range: [${ci_impact[0]:+,.2f}, ${ci_impact[1]:+,.2f}]\n') model_revenue_scenario(df, 'Full Launch (All Devices)') model_revenue_scenario(df[df['device'] == 'desktop'], 'Phased Launch (Desktop Only)') model_revenue_scenario(df[df['device'] == 'mobile'], 'Mobile Redesign Loss') 5. Visual Summary Charts
Below are the generated visual charts summarizing the experiment findings.
- In [8]:
from IPython.display import Image, display display(Image(filename='charts/conversion_rate_by_device.png')) display(Image(filename='charts/segment_conversion_matrix.png')) display(Image(filename='charts/revenue_impact_scenarios.png'))
Etsy Checkout Redesign A/B Test: Experiment Analysis & Launch Recommendation
Role: Senior Product Analyst, Checkout Team
Stakeholders: Head of Product, Checkout Engineering Team, Design Team
Test Window: September 2, 2025 – September 29, 2025 (4 Weeks)
Deliverable Artifacts: README.md, checkout_ab_test_analysis.ipynb, checkout_ab_test_analysis.py, charts/
Executive Summary & Launch Recommendation
Recommendation: CHANGE & RETEST (PHASED LAUNCH)
- Desktop Rollout: LAUNCH IMMEDIATELY to 100% of Desktop users.
- Mobile & Tablet Rollout: DO NOT LAUNCH. Retain Mobile and Tablet users on the Control checkout.
- Next Steps: Conduct mobile UX usability audits, address touch-friction bugs, fix mobile wallet placement, and launch a dedicated Mobile A/B retest.
Key Decision Rationale & Data Evidence
| Rollout Strategy | Conversion Rate Impact | Revenue Per User (RPU) | Monthly Revenue Impact (Test Scale) | Recommendation & Risk Assessment |
|---|---|---|---|---|
| Full Launch (All Devices) | +0.47 pp (+6.47% rel, $p = 0.1180$) | +$0.41 (95% CI: [-$0.06, +$0.88]) | +$12,612 (95% CI: [-$1,889, +$27,113]) | HIGH RISK / SUBOPTIMAL: Obscures massive mobile drop (-23%). High uncertainty ($p > 0.05$). |
| Phased Launch (Desktop Only) | +2.59 pp (+34.34% rel, $p < 0.0001$) | +$1.90 (95% CI: [+$1.17, +$2.63]) | +$28,455 (95% CI: [+$17,509, +$39,401]) | RECOMMENDED: Captures 100% of desktop revenue upside while avoiding all mobile loss. |
| Mobile Redesign Impact | -1.63 pp (-22.99% rel, $p = 0.0001$) | -$1.01 (95% CI: [-$1.67, -$0.35]) | -$13,314 (95% CI: [-$22,038, -$4,590]) | BLOCKER: Severe UX regression on mobile. Must not launch to mobile users. |
1. Data Integrity Audit & Experiment Validation
Before calculating metrics, we performed a thorough experiment audit on assignments.csv (31,284 rows) and orders.csv (2,670 rows).
Identified Integrity Issues & Handling Decisions
- Cross-Variant Contamination (Mixed Users):
- Issue: 284 unique users were assigned to both Control and Treatment across 568 assignment rows (0.92% of total users). This occurred due to cross-device/cookie tracking instability when users visited from multiple devices.
- Handling Decision: EXCLUDE ALL 284 MIXED USERS (and their 568 assignment rows + 19 orders) from the analysis.
- Rationale: Exposing a user to both old and new checkout flows violates the Single Unit Treatment Value Assumption (SUTVA) and causes behavioral pollution.
- Temporal Anomaly (Pre-Assignment Orders):
- Issue: 85 orders from clean single-variant users were placed prior to the user's recorded assignment timestamp (including 11 orders placed in late August 2025).
- Handling Decision: EXCLUDE ALL PRE-ASSIGNMENT ORDERS.
- Rationale: Orders placed before assignment cannot be causally attributed to the checkout redesign.
- Sample Ratio Mismatch (SRM) Check:
- Target Split: Planned 50 / 50 allocation.
- Observed Split (Clean Cohort): 15,339 Control (49.94%) vs. 15,377 Treatment (50.06%).
- Goodness-of-Fit Test: $\chi^2 = 0.0470, p = 0.8283$.
- Conclusion: PASS. No SRM detected. The randomization mechanism performed correctly.
Exclusions & Final Clean Sample
Raw Assigned Rows: 31,284 ──► Remove Mixed User Rows (-568) ──► Clean Users: 30,716
├── Control: 15,339 (49.94%)
└── Treatment: 15,377 (50.06%)
Raw Order Rows: 2,670 ──► Remove Pre-Assignment (-85)
──► Remove Mixed User Orders (-19) ──► Valid Orders: 2,566
├── Control: 1,242
└── Treatment: 1,3242. Primary & Secondary Metrics Evaluation
Primary Metric: Conversion Rate
Defined as the percentage of assigned users who placed at least one post-assignment order during the test period.
- Control Conversion Rate: 7.2625% ($1,114 / 15,339$)
- Treatment Conversion Rate: 7.7323% ($1,189 / 15,377$)
- Absolute Lift: +0.4698 percentage points (+0.47 pp)
- Relative Lift: +6.47%
- 95% Confidence Interval (Abs Lift):
[-0.1192%, +1.0588%] - Hypothesis Test (Two-Sample Z-Test): $Z = 1.5633, p = 0.1180$ (Not statistically significant at $\alpha = 0.05$).
Secondary Metric: Average Order Value (AOV)
Defined as total order revenue divided by total orders placed.
- Control AOV: $63.50 ($78,867.55 / 1,242$)
- Treatment AOV: $64.48 ($85,376.74 / 1,324$)
- Absolute Difference: +$0.98 (+1.55%)
- 95% Confidence Interval:
[-$1.03, +$3.00] - Hypothesis Test (Welch's t-test): $t = 0.9567, p = 0.3388$ (Not statistically significant).
Secondary Metric: Revenue Per User (RPU / ARPU)
Defined as total revenue generated divided by total assigned users.
- Control RPU: $5.14 ($78,867.55 / 15,339$)
- Treatment RPU: $5.55 ($85,376.74 / 15,377$)
- Absolute Difference: +$0.41 (+7.99%)
- 95% Confidence Interval:
[-$0.06, +$0.88] - Hypothesis Test (Welch's t-test): $t = 1.7047, p = 0.0883$ (Marginally non-significant).
Statistical Assumptions
- SUTVA (Single Unit Treatment Value Assumption): Satisfied after dropping all 284 mixed users.
- Independence: User sessions and purchasing decisions are assumed independent across individuals.
- Normality / Central Limit Theorem: Large sample size ($N = 30,716$) ensures normal distribution for standard error calculations.
3. Segment Analysis: Device & Visitor Type Breakdown
Evaluating aggregate results alone conceals dramatic opposing effects across device types—a classic manifestation of Simpson's Paradox.
Device Breakdown (Key Discovery)
| Device | Control Users | Treatment Users | Control Conv | Treatment Conv | Absolute Lift (pp) | Relative Lift (%) | Z-Statistic | p-Value | Significant? (alpha=0.0167) | Control RPU | Treatment RPU | RPU Delta |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Desktop | 7,410 | 7,588 | 7.54% | 10.13% | +2.59 pp | +34.34% | 5.5980 | < 0.0001 | YES (Huge Win) | $5.38 | $7.28 | +$1.90 |
| Mobile | 6,658 | 6,553 | 7.07% | 5.45% | -1.63 pp | -22.99% | -3.8619 | 0.0001 | YES (Major Drop) | $4.95 | $3.94 | -$1.01 |
| Tablet | 1,271 | 1,236 | 6.61% | 5.10% | -1.51 pp | -22.88% | -1.6144 | 0.1064 | No (Directionally negative) | $4.73 | $3.47 | -$1.26 |
Note: Bonferroni correction for 3 simultaneous device hypotheses requires $\alpha_{adj} = 0.05 / 3 = 0.0167$. Both Desktop ($p < 0.0001$) and Mobile ($p = 0.0001$) easily pass this corrected significance threshold.
Visitor Type Breakdown
| Visitor Type | Control Users | Treatment Users | Control Conv | Treatment Conv | Absolute Lift (pp) | Relative Lift (%) | Z-Statistic | p-Value | Control RPU | Treatment RPU | RPU Delta |
|---|---|---|---|---|---|---|---|---|---|---|---|
| New Visitors | 9,513 | 9,611 | 6.10% | 6.24% | +0.15 pp | +2.39% | 0.4194 | 0.6749 | $4.22 | $4.58 | +$0.36 |
| Returning Visitors | 5,826 | 5,766 | 9.17% | 10.22% | +1.05 pp | +11.45% | 1.9094 | 0.0562 | $6.65 | $7.18 | +$0.53 |
Cross-Segment Matrix (Device x Visitor Type)
- Desktop - Returning: +3.73 pp (+37.58% relative lift, $p < 0.0001$) — Strongest performing segment!
- Desktop - New: +1.93 pp (+31.74% relative lift, $p = 0.0003$) — Strong positive uplift.
- Mobile - New: -1.49 pp (-24.21% relative drop, $p = 0.0027$) — Severe drop.
- Mobile - Returning: -1.83 pp (-21.31% relative drop, $p = 0.0155$) — Severe drop.
4. Financial Revenue Impact Estimation
We modeled estimated monthly revenue impact under different rollout strategies for the test cohort scale (~30,716 users/month) and normalized per 100,000 users.
Financial Impact Model Summary
- Full Launch (All Devices):
- Expected Monthly Delta: +$12,612.01
- 95% Confidence Interval:
[-$1,888.67, +$27,113.70] - Normalized per 100k Monthly Users: +$41,060.08 (95% CI:
[-$6,148.82, +$88,268.97]) - Risk: High variance; confidence interval crosses zero due to mobile loss offsetting desktop gain.
- Phased Launch (Desktop Only - RECOMMENDED):
- Expected Monthly Delta: +$28,455.00
- 95% Confidence Interval:
[+$17,508.56, +$39,401.45] - Normalized per 100k Desktop Monthly Users: +$189,725.31 (95% CI:
[+$116,739.27, +$262,711.34]) - Advantage: Guaranteed positive financial return; zero risk of mobile degradation.
- Mobile Redesign Loss (If Launched to Mobile):
- Expected Monthly Loss: -$13,314.11
- 95% Confidence Interval:
[-$22,038.14, -$4,590.08] - Normalized per 100k Mobile Monthly Users: -$100,780.49 (95% CI:
[-$166,816.58, -$34,744.40])
5. One-Page Launch Recommendation & Action Plan
Decision: CHANGE & RETEST (PHASED LAUNCH)
Immediate Action Plan (Week 1):
- Launch Desktop Redesign to 100% Traffic:
- Immediately enable the new checkout flow for all Desktop traffic. This delivers an immediate revenue gain of +$28,455 per ~15k desktop users (+34.3% conversion rate lift).
- Hold Mobile & Tablet on Control:
- Lock Mobile and Tablet checkout on the legacy (Control) flow to safeguard Etsy from losing ~$13,300/month in mobile revenue.
Mobile UX Remediation Plan (Weeks 2 - 4):
- Investigate Touch-Screen Form Friction:
- The step reduction likely introduced compressed form inputs, making keyboard navigation on mobile prone to accidental misclicks.
- Audit Mobile Payment Methods:
- Verify Apple Pay, Google Pay, and PayPal Express CTA visibility on mobile browsers to ensure streamlined 1-click checkout.
- Fix Identity & Tracking Leakage:
- Resolve the cross-device tracking issue that caused 284 users to be double-assigned across Control and Treatment.
Retest Roadmap (Month 2):
- Launch a dedicated Mobile Checkout V2 A/B Test once touch UX fixes are implemented, aiming to bring mobile performance up to desktop standards.
6. Repository File Structure & How to Reproduce
├── checkout-redesign-ab-test-datasets/
│ └── checkout-redesign-ab-test/
│ ├── assignments.csv # 31,284 assignment rows (Sept 2-29, 2025)
│ └── orders.csv # 2,670 order rows (USD)
├── charts/
│ ├── conversion_rate_by_device.png # Bar chart of CR by device with 95% CIs
│ ├── segment_conversion_matrix.png # Horizontal lift chart across device x visitor type
│ └── revenue_impact_scenarios.png # Scenario comparison of monthly revenue deltas
├── checkout_ab_test_analysis.ipynb # Fully executable Jupyter Notebook
├── checkout_ab_test_analysis.py # Standalone Python analysis script
├── generate_visualizations.py # Matplotlib/Seaborn visualization script
├── build_ipynb.py # Notebook generator script
└── README.md # Comprehensive analytical report & recommendationReproducing the Analysis
To re-run the entire pipeline and verify numbers locally:
# 1. Run the standalone python analysis script
python checkout_ab_test_analysis.py
# 2. Re-generate visual charts
python generate_visualizations.py
# 3. Open the Jupyter Notebook
jupyter notebook checkout_ab_test_analysis.ipynbThe brief this answers
Analyze a four-week checkout experiment, deal with messy tracking, and decide whether the redesign should launch.
Try it yourselfOther answers to this brief
The same problem, solved by somebody else.
Discussion
Nothing here yet. Ask how they approached it, or tell them what you would have done differently.