Want to understand how A/B testing works under the hood? Let's build a simple client-side A/B test from scratch. By the end, you'll understand exactly what tools like ExperimentHQ do — and when you should use a tool vs building your own.
Prerequisites
- Basic JavaScript knowledge
- Understanding of the DOM
- A website to test on
The Core Concept
Every A/B test has three parts:
Assignment
Randomly assign visitors to a variant
Modification
Apply the variant's changes to the page
Tracking
Record which variant converted
Step 1: Assign Visitors to Variants
First, we need to randomly assign each visitor to a variant — and remember that assignment so they see the same variant on return visits.
function getVariant(experimentId, variants) {
// Check if user already has an assignment
const storageKey = `exp_${experimentId}`;
let variant = localStorage.getItem(storageKey);
if (!variant) {
// Randomly assign to a variant
const randomIndex = Math.floor(Math.random() * variants.length);
variant = variants[randomIndex];
localStorage.setItem(storageKey, variant);
}
return variant;
}
// Usage
const variant = getVariant('homepage-headline', ['control', 'variant-a']);
console.log(`User assigned to: ${variant}`);Note on localStorage
localStorage works for basic tests, but it's cleared when users clear their browser data. Production tools use more robust methods.
Step 2: Apply the Variant Changes
Now we need to modify the DOM based on which variant the user is in. Here's a simple example:
function applyVariant(variant) {
const headline = document.querySelector('h1');
if (variant === 'variant-a') {
headline.textContent = 'Save 10 Hours Every Week';
}
// 'control' keeps the original headline
}
// Run when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
const variant = getVariant('homepage-headline', ['control', 'variant-a']);
applyVariant(variant);
});The Flicker Problem
If you wait for DOMContentLoaded, users might see the original content flash before the variant loads. This is called "flicker." Production tools solve this by hiding content until the variant is applied, or by running synchronously in the <head>.
Step 3: Track Conversions
Finally, we need to track when users convert (e.g., click a button, submit a form):
function trackConversion(experimentId, variant) {
// Send to your analytics backend
fetch('/api/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
experimentId,
variant,
timestamp: Date.now()
})
});
}
// Track when CTA is clicked
document.querySelector('.cta-button').addEventListener('click', () => {
const variant = localStorage.getItem('exp_homepage-headline');
trackConversion('homepage-headline', variant);
});Complete Working Example
Here's everything together in a single script:
(function() {
const EXPERIMENT_ID = 'homepage-headline-v1';
const VARIANTS = ['control', 'variant-a'];
// 1. Get or assign variant
const storageKey = `exp_${EXPERIMENT_ID}`;
let variant = localStorage.getItem(storageKey);
if (!variant) {
variant = VARIANTS[Math.floor(Math.random() * VARIANTS.length)];
localStorage.setItem(storageKey, variant);
}
// 2. Apply changes
document.addEventListener('DOMContentLoaded', () => {
if (variant === 'variant-a') {
const headline = document.querySelector('h1');
if (headline) {
headline.textContent = 'Save 10 Hours Every Week';
}
}
// 3. Track conversions
const cta = document.querySelector('.cta-button');
if (cta) {
cta.addEventListener('click', () => {
console.log(`Conversion: ${EXPERIMENT_ID}, ${variant}`);
// Send to your analytics here
});
}
});
})();When to Build vs Use a Tool
Build Your Own If:
- You want to learn how A/B testing works
- You have very simple, one-off tests
- You have engineering time to maintain it
Use a Tool If:
- You need a visual editor (no-code)
- You want proper statistical analysis
- You need flicker-free implementation
- You want to run multiple tests easily
Wrapping Up
Building a basic A/B test is straightforward. But production-grade testing requires handling edge cases: flicker prevention, statistical significance, cross-device tracking, and more. That's why most teams use dedicated tools.
Now you understand what's happening under the hood — which makes you a better user of any A/B testing tool.