Skip to content
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

Capture Replay dead click as breadcrumb #8021

Closed
mydea opened this issue May 3, 2023 · 6 comments · Fixed by #8052
Closed

Capture Replay dead click as breadcrumb #8021

mydea opened this issue May 3, 2023 · 6 comments · Fixed by #8052
Assignees

Comments

@mydea
Copy link
Member

mydea commented May 3, 2023

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

type Breadcrumb = {
  category: 'replay.slowClickDetected',
  timestamp: number, // time of click
  data: {
   
    timeAfterClickMs: number, // how long until mutation happened, in ms - capped at 5000
    url: string, // URL of the page at the time of click
    route: 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
}
@mydea mydea self-assigned this May 3, 2023
@ryan953
Copy link
Member

ryan953 commented 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.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

@mydea
Copy link
Member Author

mydea commented May 4, 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.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

Sounds good to me!

@mydea
Copy link
Member Author

mydea commented May 5, 2023

So I would capture something like this:

image

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

@mydea
Copy link
Member Author

mydea commented 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
Copy link
Member Author

mydea commented May 10, 2023

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".

@chris-erickson
Copy link

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?

Screenshot 2023-07-01 at 15 01 29@2x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants