Implementation
<!DOCTYPE html>
<html>
<head>
<title>Bunchbox implementation sample</title>
<script src="//cdn.bunchbox.co/4aa7bb5c5616ee6459a19734.min.js" referrerpolicy="no-referrer-when-downgrade"></script>
</head>
<body>
The content of the document......
</body>
</html>
Bunchbox uses a JavaScript file on your site to provide various functions. This file contains all the logic and important information that you set up via the app in your account.
The script is made available via a CDN (Content-Delivery-Network) and thus guarantees a close position to the website visitor and thus an improvement in connectivity.
The script tag for your account can be found in your account settings.
Interface
Global variables
<!DOCTYPE html>
<html>
<head>
<title>Bunchbox implementation sample</title>
<script>
window._bb = window._bb || [];
window._bb.push([command, value]);
</script>
<script src="//cdn.bunchbox.co/4aa7bb5c5616ee6459a19734.min.js" referrerpolicy="no-referrer-when-downgrade"></script>
</head>
<body>
The content of the document......
<script>
window._bb = window._bb || [];
window._bb.push([another_command, value]);
</script>
</body>
</html>
Bunchbox avoids defining unnecessary variables on the global namespace. Only the variables _bb_helpers
and _bb
are defined globally. The latter serves as an interface.
You can use this interface - depending on the command - before, during or after running Bunchbox.
The _bb
object defines the push
method.
_bb.push(array_with_commands...);
The method expects at least one array describing the command.
User-defined attributes
Visitor attributes
window._bb = window._bb || [];
window._bb.push(
['attribute', 'source', 'social'],
['attribute', 'hasNewsletter', true]
);
window._bb.push(['attribute', type, [value]])
If you have visitor attributes available, you can pass these Bunchbox before execution. You can use the attributes you provide, for example, for targeting conditions.
type
the name of the attributevalue
(optional) is the value of the attribute
E-commerce attributes
window._bb = window._bb || [];
window._bb.push(
['ecommerce', 'orderSize', 99.99],
['ecommerce', 'productIds', ['id1', 'id2']],
['ecommerce', 'orderId', '48b7db13-a8c9-44c1-be18-5ea46e35c01f']
);
window._bb.push(['ecommerce', [type], [value]])
In order to view success metrics such as Revenue-Per-Visitor in the report, you have to give Bunchbox certain values on pages on which you can achieve defined goals. Each conversion can be assigned a purchase value orderSize
, the ID of the order orderId
and IDs of purchased products productIds
.
type
the name of the E-commerce valuevalue
(optional) the E-commerce value
Manual activation of experiments
window._bb = window._bb || [];
window._bb.push(['activate experiment', '4aa7f5d0a7a7bad33b439b9a']);
window._bb.push(['activate experiment', experimentId, [stepIndex]])
If you have created an experiment that has no targeting conditions, you can activate it manually.
experimentId
is the ID of the experiment you want to activatestepIndex
(optional) if the experiment has multiple steps, you can pass the index of the step
Tracking of event goals
window._bb = window._bb || [];
window._bb.push(['track event goal', '4aa7f5d0a7a7bad33b439b9a', 'goalId']);
window._bb.push(['track event goal', [experimentId], goalId])
If your experiment has an event goal, you can track it with this command. The ID of the experiment is optional. If you omit these, all active experiments are taken into account. If several experiments have an event goal with the corresponding goalId
, a conversion is tracked for all applicable targets.
experimentId
(optional) the ID of the experimentgoalId
is the ID of the event target
Cross domain link
window._bb = window._bb || [];
var link = window._bb.push(['cross domain link']);
// auf einer weiteren Domain
window._bb.push(['cross domain link', link]);
window._bb.push(['cross domain link', [linkObject]])
Bunchbox offers the possibility to serialize existing test participations of a visitor as a link object. You can then manually transfer this link to another domain in order to link both domains unidirectionally. A link has a lifetime of 30 seconds. After receiving a link object on the second domain, you can pass Bunchbox the link.
linkObject
(optional) a link object
Safe Mode
window._bb = window._bb || [];
window._bb.push(['safe mode', true]);
window._bb.push(['safe mode', isSafeModeEnabled])
If you want to prevent the execution of variants on certain pages - regardless of targeting - you can ensure this with the command safe mode
. This command causes no experiments to be evaluated or executed. There can therefore be no DOM manipulations on the part of the experiments. Experiment targets, on the other hand, will continue to be evaluated.
isSafeModeEnabled
a boolean with which you can activate or deactivate the safe mode
Consent Mode
window._bb = window._bb || [];
window._bb.push(['consent', false]);
window._bb.push(['consent', hasUserGivenNecessaryConsent])
Bunchbox offers a consent mode to ensure it works in compliance with a cookie consent on the website while still allowing for as smooth a testing experience as possible. The consent
command can be used to inform Bunchbox about the current consent status. Even without consent Bunchbox can run experiments and detect conversions. However, they are not reported back to Bunchbox until the user has given consent and Bunchbox has been notified of it via the consent
command.
In case of a first-time visit to the site it is recommended the consent
command is given with a status of false
before Bunchbox is loaded. As soon as the user has given consent the command should be called a second time, this time with true
. Now, all stored tracking will be sent back to Bunchbox.
hasUserGivenNecessaryConsent
a Boolean to inform Bunchbox whether the user has or has not given consent.
State request
window._bb = window._bb || [];
window._bb.push([
'get state',
function(state) {
// read from state ...
}
]);
window._bb.push(['get state', callback])
The get state
command can be used to query the state of the current evaluation. This command can be executed at any time. The transferred callback function is executed as soon as the evaluation is completed. The evaluation includes the evaluation of user and tracking filters as well as the experimental targeting conditions, variants and goals. As soon as execution is complete, the specified callback function is executed. The first parameter is a JavaScript object. This object contains the results of the tracking filters and user filters, an overview of all previously defined user attributes and a list of any executed experiments.
callback
a callback function with which status information is offered to the executor
{
accountId: '4b447121b2d3c8851f61a62a',
userId: '4b447134b2d3c8851f61a62c',
isUserExcludedByUserFilter: false,
isUserExcludedByTrackingFilter: false,
customAttributes: {
page_type: 'pdp',
hasNewsletter: false
},
activeExperiments: [
{
experimentId: '4b44660d0206844801d8f76a',
experimentName: 'LP Button Test',
variantId: '4b44660d0206844801d8f783',
variantName: 'Button Position Left',
event: 'bb_experiment_lp_button_test_button_position_left'
}
]
}
Prevent flickering
window._bb = window._bb || [];
window._bb.push(['prevent flickering']);
window._bb.push(['prevent flickering', options])
There are some situations where JavaScript runs asynchronously. In these cases, an original variant may be visible before visual changes are made by the actual asynchronously executed variant. This command causes the JavaScript to add a CSS class to the document element. The CSS class is used to set the opacity of the entire page to zero. After the JavaScript is executed, the class is removed again so that there is no effect on the visitor from jumping elements.
Unless otherwise configured, bb-async-hide
will be the expected class name. You want to make sure that this class is defined before the Bunchbox JavaScript is executed.
If you already have a class that allows you to set opacity to zero, you can tell us using { className: 'my-custom-hide-class' }
as the second parameter.
options
an optional object, used to configure the command
<!DOCTYPE html>
<html>
<head>
<title>Bunchbox implementation sample</title>
<style>
.prevent-flickering {
opacity: 0 !important;
}
</style>
<script>
window._bb = window._bb || [];
window._bb.push([
'prevent flickering',
{ className: 'prevent-flickering' }
]);
</script>
<script src="//cdn.bunchbox.co/4aa7bb5c5616ee6459a19734.min.js" referrerpolicy="no-referrer-when-downgrade"></script>
</head>
<body>
The content of the document......
</body>
</html>
Prevent flickering in asynchronous implementation
<!DOCTYPE html>
<html>
<head>
<title>Bunchbox implementation sample</title>
<style>
.bb-async-hide {
opacity: 0 !important;
}
</style>
<script>
/**
* @param {Window} b The global object.
* @param {HTMLDocument} e The document.
* @param {HTMLHtmlElement} c The html element.
* @param {string} d The name of property of the global Bunchbox object.
* @param {string} h The account id used to load the Bunchbox script.
* @param {string} g The class name used to hide the page
* @param {number} a The maximium timeout in ms used as fallback
*/
(function(b, e, c, d, h, g, a) {
b[d] = b[d] || [];
var f = b[d].show = function() {
c.className = c.className.replace(RegExp(" ?" + g), "");
f = b[d].show = function() {};
};
b.setTimeout(function() {
f();
}, a);
c.className += " " + g;
a = e.createElement("script");
a.async = !0;
a.src = "//cdn.bunchbox.co/" + h + ".min.js";
a.onerror = function() {
f();
};
(e.head || e.getElementsByTagName("head")[0]).appendChild(a);
})(window, document, document.documentElement, "_bb", "539dd741b822cc631f000003", "bb-async-hide", 2000);
</script>
</head>
<body>
The content of the document......
</body>
</html>
If you want to load Bunchbox asynchronously, you can do this with this script. The script not only loads Bunchbox, but also prevents potential flickering. Flickering can occur when the default page content is rendered before Bunchbox applies the visual changes of one or more variants to the current web page. To prevent this, this snippet hides the page with a predefined CSS class. The class is added to the document element and removed after successful loading. If Bunchbox resources are blocked by the current browser, the page is immediately displayed again. In addition, the snippet ensures that the page never remains hidden longer than the specified maximum timeout.
Unless otherwise configured, bb-async-hide
is the expected class name. You should make sure this class is defined before running the snippet. Also note that 539dd741b822cc631f000003
is an example account ID which you must replace with your account ID.
If you already have a class that allows you to set the opacity to zero, you can tell us by specifying another class instead of 'bb-async-hide'
. Similar to the CSS class, the maximum timeout can also be configured.
Variants
The following help functions are available within the context of a code variant.
Redirect
bb.redirect('//www.example.com/');
// oder
bb.redirect('/experiment/variante.html');
bb.redirect(url);
This function delegates the given URL or path to window.location
to ensure that no further experiments are performed.
url
the path or URL to be redirected to
Tracking of event goals
bb.track('event goal', 'engagement');
bb.track(goalType, goalId);
With this function, the event goals defined in the experiment can be tracked. The second parameter goalId
corresponds to the ID of the goal defined by you in the experiment.
goalType
defines the type of the goal. Currently onlyevent goal
is supportedgoalId
the ID of the target to be tracked
Waiting for events
bb.waitUntil(
function() {
return !!window.$;
},
function() {
$('body').css({ background: 'red' });
},
{ forever: true }
);
bb.waitUntil(testFn, callback, [options])
Since Bunchbox is executed immediately after loading the page, it is possible that required global objects are not yet available at the time of execution. With bb.waitUntil
the following execution can be delayed until the given condition is fulfilled.
testFn
function that checks the respective conditioncallback
is executed as soon as thetestFn
returnstrue
options
(optional)forever
by default, thetestFn
runs until the ‘document state complete’ occurs. With{forever: true}
this restriction can be removed
Waiting for DOM elements
waitForElements
var task = bb.waitForElements(
'ul > li',
function(li) {
li.textContent = li.textContent + ' New!';
},
{
timeout: 5 * 1000,
onTimeout: function() {
alert('Timeout!');
}
}
);
if (maybeTrue) task.cancel();
At the time of execution of Bunchbox it is in most cases necessary to wait for required DOM elements to be able to change them. With bb.waitForElements
you can wait for one or more elements to change the element as fast as possible without visual side effects for the website visitors.
bb.waitForElements(selector, callback, [options])
selector
CSS selectorcallback
callback is executed as soon as an element is foundoptions
(optional)timeout
specifies after which time period is to be aborted (in ms)onTimeout
a function that is executed when the timeout is exceeded
exists
bb.exists('h2', function(els) {
els[0].innerHTML = 'Buy now';
});
bb.exists(
'ul > li',
function(els) {
els.forEach(function(li, i) {
li.innerHTML = i + 1 + '. Item';
});
},
{ forever: true, elements: 3 }
);
bb.exists(selector, callback, [options])
selector
CSS selectorcallback
a callback function, whose first argument is a NodeList, which matches for theselector
options
(optional)forever
by default, the function runs until the document statecomplete
occurs. With{forever: true}
this restriction can be removed. By default, the function runs until the document statecomplete
occurs. With{forever: true}
this restriction can be removed.elements
the minimum number of elements that must be found before the callback is executed
DOM manipulation
append
bb.waitForElements('section', function(section) {
bb.append(section, '<h1>New category</h1>');
});
bb.append(element, htmlString)
This function allows you to add your own HTML to existing DOM elements.
element
the DOM element to which HTML is to be addedhtmlString
the HTML as string
prepend
bb.waitForElements('section', function(section) {
bb.prepend(section, '<h1>New category</h1>');
});
bb.prepend(element, htmlString)
This function allows you to add your own HTML code to existing DOM elements. Unlike bb.append
, the HTML is placed before the specified element.
element
the DOM element to which HTML is to be addedhtmlString
the HTML as string
replaceWith
bb.waitForElements('section', function(section) {
bb.replaceWith(section, '<section>New section</section>');
});
bb.replaceWith(element, htmlString)
This function replaces an existing DOM element with new HTML.
element
the DOM element to be replaced with thehtmlString
htmlString
the HTML as string
css
bb.css('.container h2 { display: none; }');
// oder
bb.css(document.body, '.container h2 { display: none; }');
bb.css([element], styleString)
Adds a stylesheet to the page to design the DOM.
element
(optional) DOM element to which the stylesheet is added (head
by default)styleString
string, with style information
DOM Events
on
bb.on('click', function(event) {
event.target.innerHTML += '<button>Submit</button>';
});
bb.on('mouseout', 'h2', function(event) {
event.target.innerHTML = 'Category';
});
bb.waitForElements('h2', function(h2) {
bb.on('mouseover', h2, function(event) {
event.target.style.color = 'red';
});
});
bb.waitForElements('body', function(body) {
bb.on('click', body, 'h2', function(event) {
event.target.style.color = 'blue';
});
});
bb.on(event, [elements, selector], callback)
bb.on
offers the appropriate functionality to listen to DOM events. The function can be used to listen to events directly at an element. The event delegation function can also be used.
event
type of the eventelements
(optional) one or more DOM elements (document
by default)selector
(optional) CSS selectorcallback
callback function, which is executed as soon as the event occurs
off
var ids = bb.on('click', 'header', function(event) {
bb.off(ids);
event.target.style.backgroundColor = 'red';
});
bb.off(ids)
This function removes one or more event listeners previously registered with bb.on
.
ids
the IDs returned bybb.on
Mouse tracking
bb.mousetracking.pause();
// ...
bb.mousetracking.resume();
bb.mousetracking.pause()
and bb.mousetracking.resume()
Provided that mouse tracking has been activated for the experiment, tracking for the current variant can be paused or continued using these functions.
Further Information
{
experimentId: '4aa7e3a5a5ecf992cd77bdf9';
experimentName: 'AB Checkout Experiment';
stepId: '4aa7e3a5a5ecf992cd77bdfa';
variantEvent: 'ab_checkout_experiment_original';
variantId: '4aa7e3a5a5ecf992cd77bdfb';
variantName: 'Original';
}
Various information can be retrieved via bb.info
. This information can be used, for example, to provide data to third-party tools.
experimentId
the ID of the experimentexperimentName
the name of the experimentstepId
the ID of the stepvariantId
the ID of the variantvariantName
the name of the variantvariantEvent
the event of the variant (assuming Webtracking is activated)
Single-page applications
Single page applications play a special role in AB testing. Unlike traditional pages, there is only an initial page load. All subsequent pages are generated dynamically without additional page load.
The implementation of Bunchbox therefore requires special attention. Bunchbox offers an interface which can be used successfully independent of the framework (e.g. ReactJS, Vue, AngularJS).
Implementation
<!DOCTYPE html>
<html>
<head>
<title>Bunchbox SPA implementation sample</title>
<script>
window._bb = window._bb || [];
window._bb.push(['auto evaluation', false]);
</script>
<script src="//cdn.bunchbox.co/4aa7bb5c5616ee6459a19734.min.js" referrerpolicy="no-referrer-when-downgrade"></script>
</head>
<body>
The content of the document......
</body>
</html>
First, the automatic evaluation must be deactivated, since this is controlled manually in the following.
Controlling the evaluation
var routes = [
{ path: '/a-page', component: Page },
{ path: '/another-page', component: AnotherPage }
];
var router = new VueRouter({
mode: 'history',
routes: routes,
base: '/'
});
_bb = window._bb || [];
router.afterEach(function(current, referrer) {
_bb.push([
'evaluate experiments',
{
attributes: {
foo: 'bar'
}
}
]);
});
This procedure allows Bunchbox to accept the validity of certain attributes and settings. Triggering an evaluation always resets all previously defined data and settings. The newly transferred data determines the new status.
Payload
_bb = window._bb || [];
_bb.push([
'evaluate experiments',
{
attributes: {
foo: 'bar',
bar: ['foo']
},
ecommerce: {
orderSize: 99.99,
orderId: '1e90384530c2',
productIds: ['0d0cd94dfd74', 'bd79fc089b79']
},
safeMode: false
}
]);
payload
(optional) all data and settings to be provided to the evaluationattributes
(optional) this object is used to pass user-defined attributes. They are specified as key-value pairs. See Visitor Attributesecommerce
(optional) this object is used to transfer user-defined purchase attributes. They are specified as key-value pairs. See <a - href='#ecommerce-attributes'>Ecommerce AttributessafeMode
(optional) this boolean can be used to prevent variants from being executed - independent of targeting. See Safe Mode
URL fragment based apps
_bb = window._bb || [];
_bb.push(['disable history navigation']);
If the single-page application uses URL fragments (#
) to define URLs, this must be communicated to Bunchbox.
The command disable history navigation
is used for this purpose.
Variants
Variants for single-page applications often require more attention than their counterparts on conventional websites. Bunchbox only executes variants, but cannot undo code executions. You can listen to a specific event so that a variant can be executed several times in succession and always produces the same result. Bunchbox provides an event emitter which can be used within the variant code. The event emitter can also be used to communicate with other variants.
const ee = bb.getEventEmitter();
const handler = () => console.log('React to custom event');
ee.on('custom:event', handler);
ee.emit('custom:event', 'I am the payload');
ee.off('custom:event', handler);
ee.once('custom:event:2', () => console.log('React to another custom event'));
To find out within the variant code when Bunchbox is evaluated again, you can listen for the event reset
. This event is always fired before a subsequent Bunchbox evaluation. The event can thus be used to undo changes made to the variant before it is executed again.
Events can also be triggered by the "outside world". The following command can be used for this purpose.
window._bb = window._bb || [];
window._bb.push(['emit', 'custom:event', 'I am the payload', 'Me too!']);
bb.getEventEmitter();
This function returns an EventEmitter. This EventEmitter provides the functions on
, once
, off
and emit
.
ee.on(event, handler);
event
Name of the event to attach the listener tohandler
Method to be called when the event is emitted
ee.once(event, handler);
event
Name of the event to attach the listener tohandler
Method to be called when the event is emitted
ee.off(event, handler);
event
Name of the event to remove the listener fromhandler
Method to remove from the event
ee.emit(event, handler);
event
Name of the event to emit and execute listenershandler
Optional additional arguments to be passed to each listener