Control the timing of Optimizely Web Experimentation Event dispatch with holdEvents and sendEvents

  • Updated
  • Optimizely Web Experimentation

Optimizely Web Experimentation snippets that use the /events endpoint log batches of events, rather than generate one network request per event. It sends these batches once per second for the first ten seconds after snippet activation and immediately thereafter. holdEvents and sendEvents together control the timing of event logging.  You can use them to better control when the snippet begins sending batches of events. This lets you improve page load performance by waiting to send events until the page has loaded or address data discrepancies to align Optimizely Web Experimentation logging with your analytics platform.

Implement the holdEvents and sendEvents APIs

  1. Call holdEvents before the snippet activates, such as in Project JavaScript or above the Optimizely Web Experimentation snippet tag. This prevents the snippet from logging any events until sendEvents is called (although any events triggered are queued in localStorage):

window.optimizely = window.optimizely || [];
window.optimizely.push({type: "holdEvents"});
  1. Call sendEvents when you want to “release” the events. You should add a listener or timeout to call sendEvents from the same place as holdEvents to call both appropriately. Calling holdEvents but not sendEvents does not track any data.

window.optimizely = window.optimizely || [];
window.optimizely.push({type: "sendEvents"});

After calling sendEvents, the snippet can send batches of queued events at the next polling interval and thereafter. Subsequent batches send once per second until 10 seconds have elapsed since the snippet activated. After that point, individual events send as soon as they are triggered. Any events which have not been sent when a visitor navigates are held in localStorage and sent on the next page where the snippet is implemented, even if the next pageview occurs hours or days later (for example, at the start of a new session).

Use cases

The two primary use cases for implementing sendEvents and holdEvents each require a distinct implementation strategy.

Improve page load performance

You improve page performance by reducing the number of requests the browser makes during the first few seconds after a page starts loading. This is when users are most likely to notice that a page is loading slowly. 

You can ensure that Optimizely Web Experimentation does not track any events during this period by calling holdEvents before the snippet activates (as described above) and binding a call to sendEvents to an event fired by the browser when it finishes loading some part of the page.  

For example, you might want to prevent Optimizely Web Experimentation from generating any event requests until after window.load. Your implementation might look something like this:

window.optimizely = window.optimizely || [];
window.optimizely.push({type: "holdEvents"});
window.addEventListener("load", function() {
    window.optimizely.push({type: "sendEvents"});
});

You must pick the most appropriate event to bind the sendEvents call. The load event happens after all assets have been downloaded, which is late in the page load process. A more aggressive implementation might use the DOMContentLoaded lifecycle event. With sendEvents, you have the flexibility to align the snippet’s logging behavior to whatever best suits your website’s needs.

Mitigate analytics discrepancies

As discussed in troubleshooting analytics discrepancies, there are several reasons why the numbers you see in Optimizely Web Experimentation may not match what you see in your analytics platform. One common cause of discrepancies is timing.  

Typically, the Optimizely Web Experimentation snippet is implemented high in your page's head. This lets Optimizely Web Experimentation initialize quickly and run variation code to manipulate content without causing page flashing. By contrast, analytics tracking code is frequently implemented to fire later during page load, usually in the body of the document. Analytics libraries are not responsible for manipulating content and do not cause flashing.

This mismatch in timing means that Optimizely Web Experimentation typically start logging events before your analytics platform does, which can be several seconds earlier. This leads to Optimizely Web Experimentation counting more conversions and unique visitors than your analytics platform, as visitors who exit a page very quickly may be tracked by Optimizely Web Experimentation but not your analytics platform.

You can address this timing mismatch by calling holdEvents before the snippet activates and then calling sendEvents from within a callback function provided by your analytics library.

For example, you might want to prevent Optimizely Web Experimentation from generating any event requests until after a Google Analytics tracker object is ready for interaction. You could take advantage of readyCallback to do this. Your implementation might look something like this:

// Implemented above the Optimizely snippet code
    window.optimizely = window.optimizely || [];
    window.optimizely.push({type: "holdEvents"});

// Implemented later on the page
    ga(‘create’, ‘UA-XXXXX-Y’, ‘auto’);
    ga('set', 'anonymizeip', true);
    ga(function(tracker) {
        window.optimizely.push({type: "sendEvents"});
    });
This implementation instructs Optimizely Web Experimentation to send events when the GA tracker object is ready for interaction. However, this does not mean that a GA event was fired. If you want to align Optimizely Web Experimentation to a GA event implemented on every page (such as a pageview event), you could use hitCallback.

Finally, your implementation varies depending on your analytics platform. Many platforms provide similar callback functionality:

Mixpanel

  • mixpanel.init() – fired when initializing the Mixpanel library, utilize the loaded callback in the config object

  • mixpanel.track() – fired when tracking an event with Mixpanel, supports an optional callback function

Impact on results

When implementing holdEvents and sendEvents, the Optimizely Web Experimentation snippet may experience a delay before it begins to send events. This affects Optimizely Web Experimentation results in two ways:

  • Optimizely Web Experimentation records fewer unique visitors. Visitors who view one page, exit before the first batch of events being sent, and never return to the site are not tracked.

  • Optimizely Web Experimentation records fewer conversions. Conversions triggered by visitors who immediately exit before the batch is sent and never return to the site are not tracked.

The magnitude of these effects increases with the time the snippet must wait before it begins to send events. This is desirable if you aim to align Optimizely Web Experimentation's results with your analytics platform.

Visitors who convert and then navigate to a new page where the snippet is implemented (as opposed to exiting the site) are tracked when their events held in localStorage are picked up and sent. This is true even when the next pageview occurs hours or days later, such as at the start of a new session.