Page activation
Describes how to use polling and callback to activate a page.
Conditional activation mode is a flexible and powerful way to activate a page and its associated experiments. There are two ways to use it
- Polling – You enter a condition and Optimizely Web Experimentation activates the page once that condition is true.
- Callback – You enter a function and trigger a callback once your code is ready for the page to activate.
Based on the code you enter, Optimizely automatically determines if it should be polled for or executed as a function. See the examples for detailed usage definitions.
Polling
If the code entered does not evaluate to a function type, it is checked every 50 milliseconds, and the page is activated when it evaluates to true. Optimizely checks this code in a try/catch block, so a condition that results in an error is assumed to be false and polling continues.
/*
* Usage Option #1 - Polling
* Optimizely polls for the code condition to be true if the JavaScript
* entered does not evaluate to a function type.
*
* Note: Optimizely evaluates this code in a try/catch block, meaning
* if your expression errors, it evaluates as false. Timeout is two seconds.
*/
// check if butter bar is in the DOM
document.getElementById("butter-bar-flash-sale") !== null;
/*
* Usage Option #2 - Callback Function
* Optimizely calls the function entered immediately if the JavaScript entered
* does evaluate to a function type.
*
* @param {Function} activate - Activate this Page
* @param {Object=} options {
* isActive : {Boolean} - Indicates if this page is active
* pageId : {String} - ID of the activated Page
* }
*
* Note: Optimizely calls this function immediately when the snippet loads, so make
* sure any functions referenced are defined at that time.
*/
function(activate, options) {
// Do logic and call `activate()` when appropriate
}Polling – Meta tag data
To activate an experiment based on the value of a meta tag, select the contents of the meta tag with jQuery and check them for your value.
<meta name="keywords" content="movies,games,videos,photos"/>/*
* Condition: Activate when the description meta tag contains 'sports', 'games', or 'puzzles'
* Type: Polling
*/
(/sports|games|puzzles/).test($('meta[name=keywords]').attr('content'))Polling – JavaScript variable
To activate an experiment based on the value of a JavaScript variable, enter the condition to check.
/*
* Condition: Activate when the Omniture eVar 33 contains 'product'
* Type: Polling
*/
window.s.eVar33.indexOf('product') != -1Polling – DOM element
To activate an experiment based on the existence of a DOM element, select that element and check the length of the result.
/*
* Condition: Activate when the green button DOM element appears
* Type: Polling
*/
function pollingFn() {
return document.querySelectorAll("button.green").length > 0;
}Callback function
If the code entered is a function, Optimizely assumes it is of the form shown here and calls it immediately, passing an activate function and an options object. Rather than returning a value, your code should call activate() when it's ready, using options.isActive and options.pageId if needed. Because this function is called immediately when the Optimizely snippet loads, any functions or variables referenced here should be available/defined at the time they're used.
NoteNo matter which method is used, remember that this is only an activation condition. Visitors must still meet URL and audience targeting to actually be bucketed into any experiments.
Callback function – Button click
To activate an experiment when a button is clicked, bind a click or mousedown event to that element using jQuery and activate the experiment when that event fires.
/*
* Condition: Activate when a button is clicked
* Type: Callback function
*/
function(activate, options) {
// following line assumes you are including jQuery in your Optimizely snippet
var $ = window.optimizely.get('jquery');
$('html').on('mousedown', '#btn', function() {
activate();
});
}Callback function – AJAX response
To activate an experiment after an AJAX call returns, use jQuery's ajaxComplete function to listen to completed AJAX requests. If the response contains or corresponds to the element that should be changed, activate the experiment.
NoteOptimizely's default (trimmed) version of jQuery doesn't contain the
ajaxCompletefunction. To use this function, you can include the full version of jQuery in your Optimizely snippet (Project Settings -> Project Code Settings) or reference your own version of jQuery that loads above the Optimizely snippet viawindow.$.
You can disable $.ajaxComplete on your site if the AJAX setup is called with global option set to false, preventing this event from firing. See jQuery's documentation for more information.
/*
* Condition: Activate when an AJAX call contains the element that should be changed
* Type: Callback function
*/
function(activate, options) {
// following line assumes you are including (full version of) jQuery in your Optimizely snippet
var $ = window.optimizely.get('jquery');
$(document).ajaxComplete(function(event, xhr, settings) {
if (xhr.responseText.indexOf('rightRailModule') != -1) {
activate();
}
});
}Callback function – DOM mutation activation
To activate an experiment based on a DOM element either changing or appearing on the page, make the following call in your experiment's conditional activation code box:
function(activate, options) {
window.activateOnDOMMutation('#element:not(.changed)', activate, true);
}The first part of the call, #element:not(.changed), is a DOM element selector you would like to monitor. Any time this element displays on the page or is changed, the experiment is activated once or multiple times depending on the last parameter. You can use any DOM selector that can be used with jQuery. If you change the selected element or its children in the variation code, you create an infinite loop. You can prevent this by excluding selectors with an added class, as shown in the code example. You would add the ".changed" class in the experiment code.
The second part of the call, activate, activates the experiment with the given ID.
The last parameter, true, tells the DOM mutation call that you want to reactivate the experiment every time the selector changes or is added to the page. Adding false here activates the experiment once. This is useful when you are appending content to the page and you do not want to append every time the DOM selector changes.
/*
* Condition: Activate when the dom selector changes on the page
* Type: Callback Function
*
* Place the following code in your Project Javascript and call the function below in your experiment's
* conditional activation code box:
*
* window.activateOnDOMMutation('#element', window['optimizely'].push(["activate", EXPERIMENT_ID]), true);
* @param '#element': DOM Selector of element you'd like to watch
* @param 'window['optimizely'].push(["activate", EXPERIMENT_ID])': Replace EXPERIMENT_ID with the current
* experiment's ID
* @param 'true': True re-activates the experiment on the DOM selector changing or being added to the DOM.
* False activates the experiment only the first time the selector is added or updated.
*/
(function(win) {
'use strict';
var listeners = [],
doc = win.document,
MutationObserver = win.MutationObserver || win.WebKitMutationObserver,
observer;
function waitForElement(selector, repeat, fn) {
// Store the selector and callback to be monitored
listeners.push({
selector: selector,
fn: fn,
repeat: repeat,
});
if (!observer) {
// Watch for changes in the document
observer = new MutationObserver(check);
observer.observe($(document), {
childList: true,
subtree: true
});
}
// Check if the element is currently in the DOM
check();
}
function check() {
// Check the DOM for elements matching a stored selector
for (var i = 0, len = listeners.length, listener, elements; i < len; i++) {
listener = listeners[i];
// Query for elements matching the specified selector
elements = $(listener.selector);
for (var j = 0, jLen = elements.length, element; j < jLen; j++) {
element = elements[j];
if (!element.ready || listener.repeat) {
// Invoke the callback with the element
listener.fn.call(element, element);
}
}
}
}
function activateOnDOMMutation(selector, activate, repeat) {
repeat = repeat === undefined ? false : repeat;
if (window.MutationObserver || window.WebKitMutationObserver) {
waitForElement(selector, repeat, function(element) {
activate();
});
} else {
// this solution does not handle older browsers
}
}
// Expose functions
win.waitForElement = waitForElement;
win.activateOnDOMMutation = activateOnDOMMutation;
})(this);Callback activation – Conditionally activated pages
Use jQuery and the native utility functions of Optimizely to activate a page conditionally after a DOM element is found on the page. This method is advantageous to the polling activation type because it's not limited by the two-second timeout after DOM ready.
function callbackFn(activate, options) {
var utils = window.optimizely.get('utils');
var $ = window.optimizely.get('jquery');
utils.waitForElement('button').then(function(buttonElement) {
if ($('button').length > 0) {
activate();
}
});
}Callback activation – Custom activation
There might be instances where you want to activate a page following the execution of an asynchronous function. You can use conditional activation to call the external function and pass activate as a callback.
function callbackFn(activate, options) {
if (window.location.href.indexOf(/* Some URL */) !== -1) {
options.isActive && activate({isActive: false});
window.customProcessFunction.init(activate);
}
}Use utility functions on dynamic pages
On single-page applications and dynamic websites, content can render or re-render after the initial page load. The utils object from window.optimizely.get('utils') lets your variation code wait for the right DOM state before it runs.
These patterns apply in the following cases:
- An experiment must reapply variation code each time the application re-renders.
- An experiment must reactivate when a specific element appears or when a user interacts with the page.
Utility methods
window.optimizely.get('utils') returns two methods for handling asynchronous DOM changes:
utils.waitUntil(condition)– Checks a condition repeatedly until it returnstrue, then resolves a promise. Use it to detect when an element is inserted into or removed from the DOM.utils.waitForElement(selector)– Resolves when a DOM element matching the selector exists. Use it to react to dynamic element insertion.
For full method signatures, see the utils reference.
Reapply variation code when the application re-renders
Single-page applications often remove and re-create elements when the user navigates or interacts. To keep your variation in place, apply it, then use utils.waitUntil to detect removal and reapply the code:
- Run your variation function to insert or modify the element.
- Pass the element's selector to a watcher that calls
utils.waitUntilwith the condition!document.querySelector(selector). - When the promise resolves, confirm the URL still matches the experiment's scope, then run the variation function again.
- Re-arm the watcher so the next re-render triggers the same cycle.
For a complete example, see the reapply-on-rerender Gist.
Reactivate an experiment when an element is removed
Use this pattern when a route change or render cycle removes an element that the experiment depends on:
- Call
utils.waitUntilwith the condition!document.querySelector(selector). - When the promise resolves, confirm the URL still matches the experiment's scope.
- Set the page's
isActivestate tofalse, then call the activation function to reinitialize the experiment.
Reactivate an experiment on user interaction
Use this pattern when a user action triggers reactivation, such as a button click:
- Call
utils.waitForElement(selector)with the selector for the target control. - When the element exists, attach a
click(or other) event listener. - Inside the listener, set the page's
isActivestate tofalse, then call the activation function.
Best practices
- Use specific conditions – Broad selectors or weak conditions in
waitUntilandwaitForElementcause repeated reactivation cycles and increase DOM polling cost. - Use robust URL matching – An
indexOfcheck onwindow.location.hrefworks for static paths. For parameterized routes, use a regular expression or a router-aware comparison. - Clean up event listeners and DOM changes – When the experiment deactivates or the user navigates away, remove listeners and revert DOM modifications.
- Test in production-like states – Exercise the variation across the application's render cycles, route transitions, and interaction paths before launching the experiment.
Updated 13 days ago
