Skip to content

Capture Replay dead click as breadcrumb #8021

Closed

Description

@mydea

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
}

Activity

  1. self-assigned this
    on May 3, 2023
  2. ryan953 commented on May 3, 2023

    @ryan953
    Member

    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

  3. mydea commented on May 4, 2023

    @mydea
    MemberAuthor

    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!

  4. mydea commented on May 5, 2023

    @mydea
    MemberAuthor

    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

  5. mydea commented on May 8, 2023

    @mydea
    MemberAuthor

    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.

  6. mydea commented on May 10, 2023

    @mydea
    MemberAuthor

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

  7. chris-erickson commented on Jul 1, 2023

    @chris-erickson

    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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions