You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We want to start capturing what we assume could be dead clicks as replay breadcrumbs.
For now, we will do nothing with this but capture it, so we can evaluate this.
Capture logic
We will add a global click handler on button,a,input[type="button"],input[type="submit"]. When such an element is clicked, we will start watching for any mutation on the page via a mutation observer, and start a timer. When the next mutation after the click is > 1s after the click, we will capture a replay breadcrumb with the actual time it took until the next mutation, timing out after a maximum of 5s.
Breadcrumb format
typeBreadcrumb={category: 'replay.slowClickDetected',timestamp: number,// time of clickdata: {timeAfterClickMs: number,// how long until mutation happened, in ms - capped at 5000url: string,// URL of the page at the time of clickroute: string|undefined,// parametrized route of the URL at the time of click. This only works when performance is enabled!,endReason: string,// the reason why the click timer was ended. e.g.: timeout, scroll, mutation, urlChange}
bikeshed moment!
I'd call the event category: 'replay.slowClickDetected', or something. Dead click sounds like a marketing term, what we're really measuring is the speed here, later we will determine if it meets our definition of 'dead' or not.
It's 'slow' because we waited between 1s and 5s, without the floor of 1s it could even be called replay.clickFeedbackMeasurement or something wild.
Oh, idk if we do this anywhere else. But I love having time fields include a unit: timeAfterClickMs for example. Helps disambiguate because timestamp on top is probably in seconds afaik
bikeshed moment! I'd call the event category: 'replay.slowClickDetected', or something. Dead click sounds like a marketing term, what we're really measuring is the speed here, later we will determine if it meets our definition of 'dead' or not. It's 'slow' because we waited between 1s and 5s, without the floor of 1s it could even be called replay.clickFeedbackMeasurement or something wild.
Oh, idk if we do this anywhere else. But I love having time fields include a unit: timeAfterClickMs for example. Helps disambiguate because timestamp on top is probably in seconds afaik
in addition route where available. This basically extends the regular DOM breadcrumb with a few fields.
I would trigger such a breadcrumb if:
a button or a is clicked
Only after more than 500ms one of the following happens:
a DOM mutation
a URL change
a scroll event (**)
after 5000ms we stop waiting and immediately create the breadcrumb.
In regard to scroll events:
If we "cancel" a dead click based on scroll, this may produce some false negatives - e.g. nothing actually happens, but the user scrolls manually. I don't think we can really differentiate between a user scrolling or programmatic scrolling :thinking_face: But maybe still better to have false negatives than false positives
OK, further update: I will only consider scrolls as a "reaction" to a click, when it happens 100ms after the click. This should capture any programmatic scrolling that happens right on click, but if a user scrolls manually afterwards, it should not count as action of the click. We can tweak the numbers for this later, if needed.
For <a> elements, we only consider them if they do not have download attribute, or a target !== '_self'. As downloads or links opened in other tabs should not result in a slow click. This should cover the most relevant cases for <a>, as links with a hash (e.g. #heading1) should be covered by the scroll detection.
Another possible thing to consider is network requests started. We may think about considering something as not-a-slow-click if a network request was triggered after the click. However, this may or may be useful, as the user would still not get any feedback and thus may still be frustrated. We could think about capturing this still, and use it to indicate to our users e.g. "You maybe should show a loading spinner while the network request is being made".
A case I see is we have links that would be handled by the OS (ie. an iMessage button). Can we somehow flag these as "intended" or otherwise ignore it?
Activity
ryan953 commentedon May 3, 2023
bikeshed moment!
I'd call the event
category: 'replay.slowClickDetected',or something. Dead click sounds like a marketing term, what we're really measuring is the speed here, later we will determine if it meets our definition of 'dead' or not.It's 'slow' because we waited between 1s and 5s, without the floor of 1s it could even be called
replay.clickFeedbackMeasurementor something wild.Oh, idk if we do this anywhere else. But I love having time fields include a unit:
timeAfterClickMsfor example. Helps disambiguate becausetimestampon top is probably in seconds afaikmydea commentedon May 4, 2023
Sounds good to me!
mydea commentedon May 5, 2023
So I would capture something like this:
in addition
routewhere available. This basically extends the regular DOM breadcrumb with a few fields.I would trigger such a breadcrumb if:
In regard to scroll events:
If we "cancel" a dead click based on scroll, this may produce some false negatives - e.g. nothing actually happens, but the user scrolls manually. I don't think we can really differentiate between a user scrolling or programmatic scrolling :thinking_face: But maybe still better to have false negatives than false positives
mydea commentedon May 8, 2023
OK, further update: I will only consider scrolls as a "reaction" to a click, when it happens 100ms after the click. This should capture any programmatic scrolling that happens right on click, but if a user scrolls manually afterwards, it should not count as action of the click. We can tweak the numbers for this later, if needed.
mydea commentedon May 10, 2023
For
<a>elements, we only consider them if they do not havedownloadattribute, or atarget !== '_self'. As downloads or links opened in other tabs should not result in a slow click. This should cover the most relevant cases for<a>, as links with a hash (e.g.#heading1) should be covered by the scroll detection.Another possible thing to consider is network requests started. We may think about considering something as not-a-slow-click if a network request was triggered after the click. However, this may or may be useful, as the user would still not get any feedback and thus may still be frustrated. We could think about capturing this still, and use it to indicate to our users e.g. "You maybe should show a loading spinner while the network request is being made".
chris-erickson commentedon Jul 1, 2023
A case I see is we have links that would be handled by the OS (ie. an iMessage button). Can we somehow flag these as "intended" or otherwise ignore it?