- Learn how to use
holdEvents
andsendEvents
JavaScript APIs to address analytics discrepancies and improve performance
/events
endpoint to use the holdEvents
and sendEvents
API methods. Follow these instructions to identify the logging endpoint used by your snippet and confirm that it is using the /events
endpoint before proceeding.Optimizely Web Experimentation snippets that are configured to use the /events endpoint log batches of events (as opposed to generating one network request per event). These batches are sent once per second for the first ten seconds after snippet activation, and then immediately thereafter. holdEvents
and sendEvents
work together to control the timing of event logging. You can use them to better control when the snippet begins sending batches of events. You might want to do this if:
-
You want to improve page load performance by waiting to send events until after the page has finished loading
-
To address data discrepancies, you want to align Optimizely Web Experimentation logging with your analytics platform.
Implement the holdEvents and sendEvents APIs
-
Call
holdEvents
before the snippet activates (for example, in Project JavaScript or above the Optimizely Web Experimentation snippet tag). This will prevent the snippet from logging any events untilsendEvents
is called (although any events triggered will be queued in localStorage):
window.optimizely = window.optimizely || []; window.optimizely.push({type: "holdEvents"});
-
Call
sendEvents
when you want to “release” the events. We recommend adding a listener/timeout to callsendEvents
from the same place whereholdEvents
is called, so you make sure both of them are called appropriately. If you callholdEvents
but NOTsendEvents
, Optimizely Web Experimentation will not track any data.
window.optimizely = window.optimizely || []; window.optimizely.push({type: "sendEvents"});
After calling sendEvents
, the snippet will be permitted to send batches of queued events at the next polling interval and thereafter. Subsequent batches will be sent once per second until 10 seconds have elapsed since the snippet activated. After that point, individual events will be sent as soon as they are triggered. Any events which have not been sent when a visitor navigates will be 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 requires a distinct implementation strategy.
Improve page load performance
One way to improve page performance is to reduce the number of requests the browser makes during the critical 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 then 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"}); });
It is up to you to pick the most appropriate event to bind the sendEvents
call to. 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 this article on 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 will be implemented high in the head of your pages. This ensures that Optimizely Web Experimentation can 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 therefore flashing isn’t a concern.
This mismatch in timing means that Optimizely Web Experimentation will typically start logging events before your analytics platform does--sometimes 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"}); });
hitCallback
.Finally, your implementation will vary depending on the analytics platform you are using. Many platforms provide similar callback functionality:
Mixpanel
-
mixpanel.init()
: fired when initializing the Mixpanel library, utilize theloaded
callback in theconfig
object -
mixpanel.track()
: fired when tracking an event with Mixpanel, supports an optional callback function
Amplitude
-
amplitudeClient.init()
: fired when initializing the Amplitude SDK, supports an optional callback function -
amplitudeClient.logEvent()
: fired when logging an event, 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 will affect Optimizely Web Experimentation results in two ways:
-
Optimizely Web Experimentation will record fewer unique visitors. Visitors who view one page, exit before the first batch of events being sent, and never return to the site will not be tracked.
-
Optimizely Web Experimentation will record fewer conversions. Conversions triggered by visitors who immediately exit before the batch being sent and never return to the site will not be tracked.
The magnitude of these effects will increase with the amount of time the snippet must wait before it begins to send events. This is desirable if your goal is to align Optimizely Web Experimentation's results with your analytics platform.