> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erdo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# A/B test your landing pages

> Split live traffic across page variants, keep each visitor on their variant, attribute every lead, and let the loop decide the winner.

# A/B test your landing pages

A landing-page A/B test is an [Experiment](/experiments) whose variants are [Pages](/pages).
You point one ad at one URL; Erdo serves different versions of that page to different visitors,
keeps each visitor on the version they first saw, tags every lead and analytics event with the
version that produced it, and — once the evidence is in — the measurement loop calls the winner.

The point of wiring it this way is that nothing about the split leaks into the ad or the URL. The
ad's destination is a single page's share link. A visitor who lands there is quietly assigned a
variant and stays on it; the address bar never changes, so click attribution, canonical URLs, and
retargeting all keep working.

## Setting one up

You don't configure this by hand — you ask Erdo in a [conversation](/concepts#conversations):

> "A/B test this landing page. Make a variant with a punchier hero, split traffic 50/50, and tell
> me which gets more leads."

The agent builds the variant pages, creates an [Experiment](/experiments) with those pages as its
variants, gives each an **allocation** (the share of traffic it should get), and arms the
measurement loop against the dataset your lead form writes to. Going live is the one step that
waits for you: starting the experiment — the moment your page's traffic comes under its control —
raises an approval card, as does swapping the variants of one that's already running. Approve it
and the split is live.

## How traffic is split

Each variant carries an **allocation percent** — the slice of visitors it should receive. The rules
that turn those numbers into a real split are deliberately forgiving, so a half-configured
experiment still serves sensibly:

* Explicit weights are used as given and normalised by their total, so they need **not** sum to 100
  — `[30, 30]` is a 50/50 split, not "30% each and 40% nowhere".
* A variant left **without** a weight takes an equal share of whatever the explicit weights leave
  under 100. So control at 60 plus two un-weighted variants gives 60 / 20 / 20.
* If nothing adds up (every weight zero or missing), traffic is split evenly rather than dropped.

The control is whichever variant the ad's URL points at. Serving a different variant renders **that
variant's content at the control's URL** — there is no redirect.

## Stickiness

A visitor is assigned once and kept there. The first time someone hits the page, Erdo does a
weighted pick and stores the result in a cookie scoped to that experiment; every later visit reads
the cookie and serves the same variant. A variant that's since been removed from the experiment
falls back to a fresh pick, so a stale cookie never shows a dead page.

Assignment happens in the visitor's browser, which is what lets the page stay fast: the shared page
shell is cached and served to everyone, and only the per-visitor choice runs live. The experiment
never slows down the common, non-experiment page.

## Attribution: every lead and event carries its variant

The whole point is being able to say "variant B produced more leads," so the assigned variant is
stamped automatically onto the two things you measure with:

* **Leads.** When the page's form submits, the variant the visitor was actually served is written
  onto the lead row — you don't have to build the page to copy it, and it can't be faked by the
  page's own markup. The lead lands in your [dataset](/data) with a `variant` column alongside the
  form fields, so per-variant conversion is a plain query.
* **Analytics.** If you've enabled [page analytics](/pages), the assigned variant is attached to
  every event (pageviews, clicks, conversions) as a property, so your funnels split by variant with
  no extra tagging.

Because attribution is stamped from the variant the visitor was *served* — not from anything the
generated page declares about itself — it stays correct even if a page's own code is wrong about
which variant it is.

## Deciding the winner

Measurement is the same deterministic loop every [Experiment](/experiments) uses: a scheduled recipe
reads your lead dataset, records one observation per variant per metric, and writes a decision-check
breadcrumb. When you tell the agent which metric decides the test (say, lead-submit rate, higher is
better) and how big a lead you'll accept as real, the loop does one more thing once the evidence
gate clears and a clear winner has emerged: it **signals the decision**. That moves the experiment
from `running` to `reading`, and Erdo writes up the outcome — the winning variant, the numbers, and
the learning — and marks it `decided`.

You can also just read the observations and make the call yourself; the automatic signal only fires
when you've configured a decision metric and margin. Either way the experiment ends with a recorded
decision you can point back to.

## What you see

In your workspace the experiment lives under **Activity**, usually inside the
[Workstream](/workstreams) that hosts the campaign. You watch the per-variant lead counts and
conversion rates accrue, see the decision check flip to "gate passed," and read the final decision
narrative when the loop (or you) calls it.
