SPA navigation
Run experiments on single-page applications, where the page changes without a reload.
On a classic website, every click loads a new page and the snippet starts again. In a single-page application (SPA) the browser loads the page once, and your code swaps the content afterwards. ABlyft would then check pages and audiences only once, on the first load.
This page explains the settings and calls that make ABlyft follow your navigation.
What you need to decide
There are two ways to tell ABlyft that "the page has changed". You can combine them.
| Approach | How it works | Use it when |
|---|---|---|
| Page trigger | ABlyft watches the URL or the DOM itself and re-checks a page when something changes | You do not want to touch your application code |
ablyft.reInit() | Your application calls ABlyft after each navigation | Your router offers a hook, or you want full control |
Both need the project setting Use SPA features, described next.
Project settings for SPAs
Open your project and go to Settings → Project Settings. The section Project Activations Settings contains:
| Setting | What it does |
|---|---|
| Use SPA features | Enables the features for dynamic websites: page triggering via URL Change or DOM Change, and Reset JS. |
Run only on ablyft.reInit() | The snippet is loaded, but starts only when your code calls ablyft.reInit(). |
| Default Page Trigger | The trigger that newly created pages receive. Default: Direct. |
With Use SPA features switched on, ABlyft additionally does the following:
- Before an experiment is applied again, ABlyft first undoes its previous run: it runs the Reset JS and removes the CSS that the experiment and its variation had added.
- On every new run of the project, the CSS that ABlyft added to the page is removed and added again, so styles do not pile up.
ablyft.reInit()re-initializes all experiments the visitor is already in, so that resets run and goals are applied again.
Without Use SPA features, Reset JS is never run automatically. Switch the setting on before you rely on resets.
Option 1: Let ABlyft detect the navigation
Every page has a Trigger that defines when ABlyft checks the page's targeting. You set it on the page under Targeting & Goals → Pages, in the section Trigger. The default of most projects is Direct: check once, when ABlyft starts.
For SPAs, choose URL Change (history API), URL Change (polling) or DOM Change. What each trigger does is listed in Pages & URL targeting.
At start, ABlyft checks every page once. After that, it checks the page again each time the trigger fires.
Triggers are an advanced setting. If a page runs on a normal, reloading part of your site, leave it on Direct.
What happens on each check
- If the page matches (URL rules and optional JavaScript rules) and is not active yet, ABlyft activates it, triggers its pageview goals, and evaluates its experiments (environments, audiences, traffic).
- If the page is already active and no longer matches, ABlyft deactivates it. What happens to its experiments depends on the page's deactivation mode.
Deactivation modes
The page's deactivation mode (see Pages & URL targeting) decides whether Reset JS runs and whether the page stays active.
Choose Reset for most cases: the experiment disappears when the visitor navigates away from the page.
Option 2: Call ablyft.reInit() yourself
ablyft.reInit() re-runs ABlyft on the current page: pages and audiences are checked again ("rerun condition check").
Call it from your router after the new view has been rendered.
// Example: call after your app finished rendering a new route
function onRouteChanged() {
if (window.ablyft && typeof window.ablyft.reInit === 'function') {
window.ablyft.reInit();
}
}reInit() exists only after the snippet has loaded, hence the check. Pushing goals and other commands before that
works differently, see queueing.
To start from a clean state, for example after a login or language switch, use ablyft.reInit({ resetStates: true }). The options are described in the
JavaScript API.
Run only on ablyft.reInit()
Turn on Run only on ablyft.reInit() if ABlyft should not start on its own. This is useful when the application
must be ready first (for example, the first view is rendered or the user data is loaded). The snippet still loads
and window.ablyft is available, but experiments only start with your first reInit() call.
Do not forget the call
With this setting on and no reInit() call, no experiment runs at all.
React to ABlyft runs
ABlyft dispatches the ablyft_initialized event on document on every run, including every reInit(), and supports a
lifecycleEnd listener that is called after each run. Both are documented in the
JavaScript API.
Reset JS
Reset JS is code that undoes what your experiment code did, so that a variation can be removed again without a page reload. You can set it in two places:
- the experiment: Experiment Level Codes → Reset JS code,
- a variation: Code → Reset JS code.
ABlyft runs it when an experiment is reset: before the experiment is applied again, and when a page is deactivated in the mode Reset or Force-reset (see above).
For an example with variation code and the matching Reset JS code, see A complete example.
The CSS you added to experiments and variations is removed automatically; you only need to reset what your JavaScript changed. More on code fields: Custom JavaScript.
Which setup should I choose?
| Your application | Recommendation |
|---|---|
SPA that uses pushState routing | Pages with trigger URL Change (… history API), deactivation mode Reset |
| URL does not change, but views switch (tabs, steps) | Trigger DOM Change, or a Callback / API trigger, see Dynamic content |
| You control the router and want precise timing | ablyft.reInit() in a router hook, optionally with Run only on ablyft.reInit() |
Troubleshooting
- Experiment shows on the first page but not after navigation: the page still has the trigger Direct, and no
reInit()is called. Change the trigger or callreInit(). - Changes stay when leaving the page: no Reset JS was added, or Use SPA features is off.
- Experiment runs twice or flickers: both an automatic trigger and
reInit()are in use. A page that is already active is not activated again, but pick one approach where possible. - Turn on debug mode and watch the console. Every page activation is logged. More in Debugging.