-
Notifications
You must be signed in to change notification settings - Fork 222
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugin: Element Tracking #1400
base: master
Are you sure you want to change the base?
Plugin: Element Tracking #1400
Conversation
BundleMonFiles added (6)
Total files change +105.7KB 0% Final result: ✅ View report in BundleMon website ➡️ |
94041da
to
3f57ff8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is surprisingly comprehensive and well engineered! 👏👏👏
Just some initial feedback from testing this in a React app:
- I see the obscure and destroy events firing after the next page view (after
useEffect
callback in React is triggered on new page elements). This makes sense and is likely very hard to avoid, but is a bit confusing. I was wondering if there is a way to add afirstPageViewId
information to these events so that one can understand if they refer to elements created on the previous page? Some elements might outlive one page intentionally, so probably we can't force the previous page view id in theweb_page
entity. But there might be a better solution I haven't thought of. - Related to the previous one, the obscure and destroy events always have all values in the
element
entity (width, height, position) set to 0. Not sure if we can use the last non-zero value? - The
element_age_ms
property in the stats entity seems to be too large – 3468018102679.6997 (see screenshot attached). But this is only happening for some elements, on others it's closer tototal_time_visible_ms
. Also we probably don't need the floating point precision when the unit is ms. - This is a small suggestion, but I was wondering if it makes sense to add the stats entity for the current element on the obscure/destroy events? Could give more context to the event and potentially a more accurate measurement than the ping events with N second granularity.
Not sure if compliment? 😅 But I'll take it as one. Thanks!
Hm, yes I can see this being problematic. Especially with everything sending async there's a good chance it'll be part of the next pageview rather than the previous one. Good call!
Last-non-zero might get confusing if it actually shrinks to that before obscured/removed, but last-known-if-zero for those events hopefully helps? Added.
Oops, relative vs absolute timestamp mixup. Fixed!
You should already be able to do this with the |
This adds a new plugin for the Browser and JavaScript trackers: Element Tracking
The Element Tracking plugin aims to provide a generic mechanism for tracking specific DOM elements on web pages; in particular element lifetimes and view-ability.
It achieves this via the Intersection Observer and Mutation Observer APIs. This is similar to mechanisms like GTM's Visibility Triggers, but Snowplow-specific. Like those triggers, the elements are defined via CSS selectors. This aims to be more flexible in that it can fire more than once per page load if desired.
Configuration can vary from simple (just provide a CSS selector to track visibility events) to quite complex (track existence of elements from my shadow host custom components once per page, track them as visible after they have been on screen for 2500 milliseconds and more than 50% of the area is in-view, collect the heading text from that element and the data-product-id attributes from every div inside it). See the README for various in-depth examples & explanations of the various options.
Four events are supported:
create_element
: When an element matching a CSS selector is added to the document (or is already in the document when the plugin is enabled; or when an existing DOM element is mutated to match a given selector)expose_element
: When an element matching a CSS selector enters the viewport and becomes visible to the userobscure_element
: When an element matching a CSS selector leaves the viewport and becomes no-longer-visible to the userdestroy_element
: When an element that matched a CSS selector is removed from the document or modified to no longer match that selectorAnd there are 4 companion entities:
element
: Contains details about elements that are the subject of the above events; since the data is otherwise identical the events all share this one entityelement_content
: The plugin allows declarative extraction of information about elements and their child elements; this entity allows a flattened tree of children to be described; e.g. so you can track viewability of a Recommendations component, and extract information about the individual items that were recommended at the same timeelement_statistics
: This is an auxiliary entity intended for attaching state tracked by this plugin to other events; e.g. you can have the visibility state, number of times visible, and time-in-view of a given element attached to page ping events to get a rolling summary over time. This also allows element-specific depth tracking, similar to that provided by page pings for the overall documentcomponent_parents
: You can name selector and mark them as "components"; events triggered for specific elements will have a list of their containing components included in this entity. This works for the above events, and the plugin also provides a mechanism for use as a context generator with the Link and Form tracking plugins.Proposed schemas for these events & entities: snowplow/iglu-central#1421
The events/entities are quite generic, but the plugin aims to enable uses cases such as:
Should resolve #98
I haven't tested with a large number of configurations on complex pages; many
expose
configurations may have performance impacts from calculating total time in view very often, but I've tried to keep everything as async-friendly as possible to manage perf. Community feedback welcome in that regard!