When to use one
- You already have two real URLs to test. Landing page A vs landing page B. Do not rebuild B on top of A with JavaScript when it exists already.
- The variant is heavy enough that in-place would flicker. A full page redesign is a redirect test; a headline tweak is not.
How to set one up
Choose the test type when you create the experiment. In the Name and basics step, pick Split URL instead of A/B test. This is the step that decides whether the experiment redirects at all, and it comes before you reach Variations. Then, in the Variations step, set the Redirect URL field on each treated variation. In a Split URL experiment that field replaces the JS and CSS editors: a redirect variation cannot carry code, and the API refuses to save one that does, rather than saving it and silently never running it. The visitor is navigated away before variation code would apply, so there is nothing for it to do. The Original variation is not a redirect; it stays on the current URL. Only treated variations can be redirects. Below the variations, in the same step, there is one more choice: Redirect returning visitors. It decides what happens when someone who has already been sent to the variation comes back to the original page, and it matters more than it sounds like it does. It applies to the whole experiment rather than to one variation, which is why it sits after the list rather than inside a card. See Returning visitors below.Returning visitors
By default a visitor bucketed into the redirect variation is sent to the variation on every eligible visit, not just the first. That is what keeps their experience consistent with the variation they were assigned to, and it is what other split URL tools do. It has a consequence worth understanding before you start: that visitor cannot reach the original page again while the test runs. If they click a link back to it, they are redirected. Because the runtime useslocation.replace(), Back does not return them either.
For a straight A versus B page test that is correct and invisible. If
the original page is somewhere people have a reason to go back to, it
is a trap.
So there are two options:
- Every eligible visit (default, recommended). The behaviour above.
- First eligible visit only. The visitor is redirected once, and can reach the original page afterwards by following a link to it or entering its URL.
Neither option makes the Back button return to the original page.
That is a separate mechanism and it is worth being clear about, because
“they can reach the original page afterwards” sounds like it should
cover Back, and it does not.
location.replace() replaces the current history entry rather than
adding one, so the original page never enters the back stack. Pressing
Back from the variation goes to whatever the visitor saw before the
original, or nowhere at all if the original was where they entered your
site. Nothing is intercepting Back; there is simply no entry behind
them to return to.“First eligible visit only” changes whether the redirect fires
again. It does not put back a history entry that was already
replaced, so a visitor who has been freed still reaches the original by
clicking or typing, not by going back.First eligible visit only means once per publish
The runtime remembers that it redirected a visitor by recording it against their current assignment. Anything that ends that assignment starts them over, and they are redirected once more:- You publish the experiment again. This is the common one. Every publish resets it, so on a site that publishes daily, a returning visitor is freed once per day and redirected again after the next publish.
- The assignment expires (30 days).
- You change the redirect target, or the visitor is assigned a different variation.
- You reset the experiment’s data.
Changing it on a running test
You can change this setting after the test has started, unlike the test type. On a running experiment it lives on the experiment page, in the Variations card, rather than back in the create wizard. Because it changes what visitors experience from that point on, it is treated as a material change: ABTestly asks whether to keep the data collected so far or reset it, and records the change either way. Keeping the data is a legitimate answer here, since the change does not invalidate what was already measured. One thing that surprises people: switching from Every eligible visit to First eligible visit only does not free anyone immediately. Under the default the runtime records nothing about who it redirected, so every already assigned visitor is redirected one more time first, and freed after that.What happens at runtime
- The visitor loads the current URL.
- The snippet decides which variant they are in.
- If they get the redirect variant, the snippet records the exposure
and hands it to the transport first, then calls
location.replace()with the redirect URL. The order matters: the payload leaves while the origin page is still the live document, rather than depending on surviving the unload. - That exposure goes out on its own beacon rather than riding the
page’s batch, because
location.replace()does not stop the rest of the page’s JavaScript and the batch would otherwise send the same row a second time. - The exposure is dispatched with
sendBeacon, falling back tofetchwithkeepaliveifsendBeaconis unavailable or refuses the payload. - On the new URL, the visitor is not re-bucketed. Bucketing is a pure function of the experiment’s salt and the visitor’s id, so they land in the same variant on any page the experiment applies to.
location.replace() rather than a normal
navigation, the starting URL is not left in the visitor’s history, so
Back does not return them to it. This holds whatever you set Returning
visitors to: that setting decides whether the
redirect fires again, not whether a history entry exists.
Anti flicker and the redirect
If you have anti flicker enabled, it interacts with a redirect in a way worth knowing about. Normally the snippet hides the page while it decides and applies, then reveals it. On a redirect variation there is nothing to reveal: the visitor is leaving. So once the navigation has been issued, the runtime keeps the origin page hidden and cancels the ordinary reveal, rather than showing the old page for however long the destination takes to load. Without that, a slow destination would flash the original page at the visitor before replacing it. Two bounds on this:- If the page was already visible when the redirect was issued, nothing is hidden. Hiding it at that point would blank a page the visitor is already looking at, which is worse than the flash it would prevent.
- A separate watchdog reveals the origin page after 5 seconds if the navigation has still not happened. That is deliberately much longer than the 2 second anti flicker failsafe, because the two answer different questions: the 2 second one asks whether applying a variation hung, and this one asks whether a redirect that was issued failed to navigate. A redirect still un navigated after 5 seconds is a failed navigation, not a slow one, and the visitor gets the origin page back rather than a blank screen.
Ambient goals
Goals defined on either URL still count. A Page visit goal for/thanks fires when the visitor reaches /thanks, regardless of
which variant sent them there.
Credit for a purchase follows the visitor, not the URL, so a
conversion on the destination page is attributed to the variant that
sent them there. Separately, orderId deduplication stops the same
order being counted twice if the confirmation page is reloaded or the
order qualifies more than once. The two are different mechanisms;
deduplication is not what performs the attribution.
Attribution depends on the visitor being recognised on the
destination, which works across subdomains of the same registrable
domain (
www.example.com to shop.example.com) but not across
different domains. A redirect to a separate domain produces a brand
new visitor there, with no exposure and no way to join the two. Split
URL tests across domains are not supported.Watch for
- Redirect loops. If the redirect target is itself matched by the experiment’s Location rules, the visitor is bucketed again on arrival and gets the same variant. The runtime will not send them onward: before navigating, it compares where the visitor already is against where the variant would send them, and skips the redirect when those are the same page. Query strings and a trailing slash are ignored in that comparison, because a target differing only by those still lands on the same page. Separately, saving is refused if a redirect target is the experiment’s own target URL, which catches the common slip of pasting the same address back. That save check is a convenience only: it compares one stored URL and does not evaluate your Location rules, so it can pass on a config the runtime guard then has to catch. Still exclude your redirect target from the experiment’s Location rules. A visitor who arrives and re-activates the experiment records a second exposure even though they are not redirected again, which inflates event counts without changing your visitor totals or the result.
- The redirect target must be a host you have declared. A redirect
URL has to be
httporhttps, and its host has to be one of the site’s declared hosts (localhostand127.0.0.1stay allowed so local development works). Anything else is refused when you save, and refused again by the snippet before it navigates. Note this is a scheme and host check only; it does not look at your Location rules, so the loop above is still yours to avoid. sendBeaconfailing. In rare browsers (some corporate policies disable it), the exposure may not be dispatched at all. ABTestly falls back tofetch(keepalive: true), which is also dispatched without waiting for a reply.- SRM on redirect variants. The classic cause, a slow destination losing exposures on the way out, no longer applies here: the exposure is dispatched from the origin page before the navigation starts, so how long the destination takes to load does not affect whether it was sent. What remains is the bullet above: if the dispatch itself is refused or blocked, the loss falls on the redirecting variation alone rather than spreading evenly across variations, which is exactly the shape that trips an SRM check. See SRM.
What if I need a soft redirect (client-side route change)?
For an SPA, use JavaScript in the variant:onCleanup should push back to the original URL if the visitor
navigates to a page the experiment does not target.
For a hard redirect on an SPA, the Redirect URL field still works.
window.location.replace(url) is what the runtime does under the
hood, and it always causes a full navigation.