Skip to content

Experiments

Run A/B tests on feature flags with Bayesian statistics that stay valid while you peek, honest exposure attribution, and explicit guardrails before any verdict.

An experiment splits traffic between variants of a feature flag, attributes metric events to each variant, and tells you the probability that each variant is the best — with guardrails that refuse to offer a verdict on too little data.

Create and launch

An experiment moves through four states: draft → running → stopped → archived. Creating one also creates its feature flag, inactive — a draft serves no traffic. The default setup is two variants, control and test, split 50/50; edit variants and targeting on the flag while the experiment is still a draft.

Launching requires a primary metric — an experiment with nothing to measure can’t be launched — and is what activates the flag and stamps the start date. Metrics come in three shapes: conversion (did the person do it), count per user (how many times), and mean (average of a numeric property). Secondary metrics ride along for context.

Before launching, the sample-size helper estimates how many exposures per variant you need for a given baseline rate and minimum detectable effect — and, given your traffic, how many days that will take. Running an experiment your traffic can’t power is the most common way to waste two weeks.

How exposure works

A person enters the experiment at their first az.flag_called event whose flag response matches one of the experiment’s variant keys, inside the experiment’s start/end window. The SDKs emit that event automatically when your code reads the flag — see exposure on the flags page.

Two rules keep the numbers honest:

  • A person observed in more than one variant is excluded outright — attributing them to either arm would contaminate both. The excluded count is reported in the results, not hidden.
  • Metric events count only at or after the person’s first exposure. A purchase from before someone ever saw the test can’t credit the test.

Results attribute on the raw per-event person id; the canonical-person join that folds in late identify-merges is a known follow-up, not current behavior.

Read the results

Experiment results with probability-to-be-best and credible intervals per variant

The primary display is Bayesian: each variant gets a probability-to-be-best and a 95% credible interval. Bayesian results remain valid under continuous peeking — you can look at a running experiment every day without invalidating the statistics, which is how people actually behave. A frequentist p-value and confidence interval are shown next to them as a familiar reference point, not as the significance gate.

No verdict is offered until every variant has at least 100 exposures, and — for conversion metrics — at least 5 successes. A winner is called at 95% probability-to-be-best. Probability-to-be-best is estimated by Monte Carlo with a fixed seed, so the same inputs always produce the same numbers — results don’t jitter between refreshes.

Results are computed from compacted storage (cached for five minutes); the separate exposures counter merges the live ingest buffer, so a just-launched experiment shows traffic immediately even before results fill in.

Stop and roll out

Stopping an experiment stamps the end date but leaves the flag active — participants keep their assignments instead of being snapped back to control the moment you stop measuring. To roll out the winner, edit the flag: set the winning variant to 100% (or flip a boolean flag fully on). To roll back, turn the flag off.

Deleting an experiment keeps its flag, and deleting a flag that an experiment references is blocked — you can’t orphan a running test or silently un-ship a rollout by cleaning up the wrong object.

Reference

Guardrails

GuardrailValue
Minimum exposures100 per variant before any verdict
Minimum successes5 per variant (conversion metrics)
Winner threshold95% probability-to-be-best
Credible intervals95%
Multi-variant personsExcluded, count reported

Experiments are created, launched, and read entirely in the app; the only token-authenticated surface involved is /api/v1/decide, which serves the flag itself.