Auto-tracked "render" events should only be sent once per page load
Overview
Currently, if you add the magic data-track-action=render
attribute to an element, it will be automatically picked up by tracking/index.js
and will send an event to Snowplow when the page loads.
Problem
However, we also look for the closest [data-track-action]
element when any click
event is triggered on any element in a page, so if some of those elements happen to be nested within a [data-track-action="render"]
element, they’ll cause the render
action event to be re-sent.
Given the following code:
.click-event-handler{ data: { 'track-action': :all_the_clicks } }
.render-event-handler{ data: { 'track-action': :render } }
%a{ href: 'something' } Track Me
We would see a render
event dispatched on initial page load, as we would expect. We would also see, however, the render
event getting dispatched for all clicks of our “Track Me” link. We would not see any all_the_clicks
events.
Solution
Exclude the [data-track-action="render"]
(and also the deprecated [data-track-event="render"]
) elements from the automatic event handling feature
const eventHandler = (e, func, opts = {}) => {
- const el = e.target.closest('[data-track-event], [data-track-action]');
+ const eventSelector = '[data-track-event]:not([data-track-event="render"])';
+ const actionSelector = '[data-track-action]:not([data-track-action="render"])';
+ const el = e.target.closest(`${eventSelector}, ${actionSelector}`);
if (!el) return;
const { action, data } = createEventPayload(el, opts);
func(opts.category, action, data);
};
Alternative solutions explored
-
Remove the
data-track-action
(or the deprecateddata-track-event
) attribute from the element once we’ve dispatched the eventstatic trackLoadEvents(category = document.body.dataset.page, parent = document) { if (!this.enabled()) return []; const loadEvents = parent.querySelectorAll( '[data-track-action="render"], [data-track-event="render"]', ); loadEvents.forEach((element) => { const { action, data } = createEventPayload(element); this.event(category, action, data); + element.removeAttribute('data-track-action'); + element.removeAttribute('data-track-event'); }); return loadEvents; }
Given our same example code from earlier:
.click-event-handler{ data: { 'track-action': :all_the_clicks } }
.render-event-handler{ data: { 'track-action': :render } }
%a{ href: 'something' } Track Me
We would see the render
event dispatched exactly once per page, on initial page load (as expected). We would also see an all_the_clicks
event dispatched for each and every click of the “Track Me” button, which is probably also what we would expect.