Dynamic content
Run experiments on content that appears after the page has loaded, such as modals, tabs and AJAX content.
Not everything a visitor sees is there when the page loads. Modals, cart drawers, tabs, checkout steps and content from an API call appear later, often without changing the URL. This page shows how to make ABlyft wait for them.
There are two separate questions:
- When should the experiment become active? Solved with the trigger of a page.
- When can my variation code change an element? Solved with helper functions in your code.
Make the page wait: choose a trigger
Each page has a Trigger that defines when ABlyft checks the page's targeting. Open Targeting & Goals → Pages, edit the page, and go to the section Trigger.
| Trigger | Use it when |
|---|---|
| Direct (immediately when ABlyft runs) | The content is part of the page at load (default for most projects) |
| DOM Change (when something on the page is changing) | The page should be active as soon as certain elements exist |
| Callback (when the callback function is called) | You decide in a small piece of JavaScript when the page starts |
| API (manual activation by an API / JavaScript call) | Your own application tells ABlyft when the page starts |
| URL Change … | The URL changes, see SPA navigation |
DOM Change trigger
With DOM Change, ABlyft checks the page once at start and then again every time the page changes (elements are added, removed or their attributes change). Changes caused by ABlyft's own code are ignored.
To use it, combine the trigger with JavaScript rules that describe the dynamic content. Open Advanced
Targeting in the section Targeting of the page and write a condition that returns true when the content exists:
// Page is active as soon as the cart drawer is open
return document.querySelector('.cart-drawer.is-open') !== null;The condition is valid if your JavaScript returns true. Inside it you can use ablyftTools.
Two options in Advanced Targeting help with late content:
| Option | Effect |
|---|---|
| Poll on rules | ABlyft checks the condition again and again for up to 2 seconds before it gives up. Use it when the element appears shortly after the trigger. |
| Always embed in snippet | Usually not needed. Only enable it if your setup requires it. |
DOM Change runs often
A busy page changes its DOM many times per second, and ABlyft checks the page every time. Keep JavaScript rules short and fast, and avoid heavy work in them.
Callback trigger
With Callback, you write the logic. A field for JavaScript appears below the trigger. ABlyft runs your code
when it starts (and again on every re-run, for example after ablyft.reInit()). Call activate() when the page should be active. You can also use ablyftTools and page
(an object with the page id).
// Activate the page when the checkout step 2 is rendered
ablyftTools.waitForElement('.checkout-step-2', () => {
activate();
});Call activate(false) to deactivate the page again, for example when a modal is closed:
document.addEventListener('modal-opened', () => activate());
document.addEventListener('modal-closed', () => activate(false));activate() still checks the page's URL rules and JavaScript rules. It does not activate the page if they do not match.
API trigger
With API, your own code activates the page with an activatePage call, for example in the handler that opens your modal,
and deactivates it with deactivatePage. Setup and calls are described in the Page API.
What happens when the page deactivates
The deactivation mode of the page (Advanced Settings → Deactivation mode) controls whether Reset JS runs and whether the page stays active. See SPA navigation.
Make the code wait: helper functions
Even on an active page, an element may not exist yet. In variation code, use the
tools, available as ablyftTools. The variation editor shows a Code Helper
with ready-made snippets for the most common ones.
| Function | Use it to |
|---|---|
waitForElement | Run code for every element that matches a selector as soon as it exists, also elements added later |
elementIsInView | Run code when an element scrolls into the viewport |
domChanged | Run code on every DOM change |
domLoaded | Run code when the DOM is ready |
poll / check | Wait for any condition you define |
// Variation JS: change a button that is rendered later
ablyftTools.waitForElement('.add-to-cart', (button) => {
button.textContent = 'Add to basket';
});waitForElement calls your function once per element. If the element is replaced by your application (for example, re-rendered),
the new element is handled too.
Dynamic data: re-check audiences
Audiences are evaluated when an experiment starts. If a value becomes known later, for example a cookie is set or a data layer entry is pushed, tell ABlyft to look again:
ablyft.push({ eventType: 'reevaluateAudiences' });ABlyft then re-evaluates the audiences of experiments on currently active pages that are not running yet. Visitors who were already excluded from an experiment stay excluded.
For audiences that depend on something happening on the page, you do not need to call it yourself. Audience rules of
the type JavaScript Trigger (call activate() when the audience should match) and dataLayer Event trigger the
re-check automatically. See Data layer events.
Troubleshooting
- Page never activates: check the JavaScript rules in the console of your browser and turn on debug mode. Activated pages are logged.
- Page activates, but the change is not applied: your selector does not match, or the element appears after your
code ran. Wrap the change in
ablyftTools.waitForElement. - Change disappears when the app re-renders: use
waitForElementinstead of a one-time change, so every new copy of the element is changed.