Skip to content

Conversation

@mydea
Copy link
Member

@mydea mydea commented May 5, 2023

This adds an experimental config to allow capturing slow clicks in the UI.

Enable via:

new Replay({
  _experiments: {
    slowClicks: {
      threshold: 300, // min. duration for when we capture a click
      timeout: 5000, // stop waiting for an event after this time
      scrollTimeout: 300, // for scroll events, we only wait until this time is passed, then stop listening
      ignoreSelectors: string[], // do not detect slow clicks for elements matching these
    }
  }
}) 

Currently, we consider for this:

  • clicks on <button>, <a>, <input type='button'>, <input type='submit'>
  • We wait for either a DOM mutation to happen, or a scroll right after the click, or until the timeout
  • When the time is > threshold time, then we create a breadcrumb that looks like this:
{
  category: 'ui.slowClickDetected',
  data: {
    endReason: 'mutation',
    node: {
      attributes: {
        id: 'mutationButton',
      },
      id: expect.any(Number),
      tagName: 'button',
      textContent: '******* ********',
    },
    nodeId: expect.any(Number),
    timeAfterClickMs: expect.any(Number),
    url: 'http://sentry-test.io/index.html',
  },
  message: 'body > button#mutationButton',
  timestamp: expect.any(Number),
}

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.

Closes #8021

@mydea mydea self-assigned this May 5, 2023
@github-actions
Copy link
Contributor

github-actions bot commented May 5, 2023

size-limit report 📦

Path Size
@sentry/browser - ES5 CDN Bundle (gzipped + minified) 21.03 KB (+0.03% 🔺)
@sentry/browser - ES5 CDN Bundle (minified) 65.63 KB (+0.02% 🔺)
@sentry/browser - ES6 CDN Bundle (gzipped + minified) 19.57 KB (+0.04% 🔺)
@sentry/browser - ES6 CDN Bundle (minified) 58.09 KB (+0.02% 🔺)
@sentry/browser - Webpack (gzipped + minified) 21.17 KB (0%)
@sentry/browser - Webpack (minified) 69.04 KB (0%)
@sentry/react - Webpack (gzipped + minified) 21.19 KB (0%)
@sentry/nextjs Client - Webpack (gzipped + minified) 49.11 KB (0%)
@sentry/browser + @sentry/tracing - ES5 CDN Bundle (gzipped + minified) 28.65 KB (+0.02% 🔺)
@sentry/browser + @sentry/tracing - ES6 CDN Bundle (gzipped + minified) 26.88 KB (+0.03% 🔺)
@sentry/replay ES6 CDN Bundle (gzipped + minified) 48.13 KB (+1.08% 🔺)
@sentry/replay - Webpack (gzipped + minified) 42.02 KB (+1.35% 🔺)
@sentry/browser + @sentry/tracing + @sentry/replay - ES6 CDN Bundle (gzipped + minified) 67.08 KB (+0.87% 🔺)
@sentry/browser + @sentry/replay - ES6 CDN Bundle (gzipped + minified) 59.99 KB (+1.02% 🔺)

@mydea mydea force-pushed the fn/captureSlowClick branch from d47112b to 998906e Compare May 9, 2023 09:36
@mydea mydea changed the title WIP(replay): Capture slow clicks feat(replay): Capture slow clicks (experimental) May 9, 2023
@mydea mydea marked this pull request as ready for review May 9, 2023 09:48
@mydea mydea requested review from Lms24, billyvg and ryan953 May 9, 2023 09:48
@mydea mydea force-pushed the fn/captureSlowClick branch from 1ef65cc to 1402cff Compare May 10, 2023 07:12
@mydea mydea added the Package: replay Issues related to the Sentry Replay SDK label May 10, 2023
@mydea mydea force-pushed the fn/captureSlowClick branch from efad913 to 231a5f0 Compare May 10, 2023 12:34
@cmanallen
Copy link
Member

Related: getsentry/sentry#48259

Comment on lines +43 to +45
const event = isClick && (handlerData.event as PointerEvent);
// Ignore clicks if ctrl/alt/meta keys are held down as they alter behavior of clicks (e.g. open in new tab)
if (isClick && slowClickConfig && event && !event.altKey && !event.metaKey && !event.ctrlKey) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to ignore clicks made while alt/meta/ctrl are held down since they can alter behavior that would consider it a dead click.

Comment on lines +117 to +144
const SLOW_CLICK_IGNORE_TAGS = ['SELECT', 'OPTION'];

function ignoreElement(node: HTMLElement, config: SlowClickConfig): boolean {
// If <input> tag, we only want to consider input[type='submit'] & input[type='button']
if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
return true;
}

if (SLOW_CLICK_IGNORE_TAGS.includes(node.tagName)) {
return true;
}

// If <a> tag, detect special variants that may not lead to an action
// If target !== _self, we may open the link somewhere else, which would lead to no action
// Also, when downloading a file, we may not leave the page, but still not trigger an action
if (
node.tagName === 'A' &&
(node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self'))
) {
return true;
}

if (config.ignoreSelector && node.matches(config.ignoreSelector)) {
return true;
}

return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this so that we include more tags while in experimental phase.

@billyvg billyvg merged commit bd48cf2 into develop May 15, 2023
@billyvg billyvg deleted the fn/captureSlowClick branch May 15, 2023 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Package: replay Issues related to the Sentry Replay SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Capture Replay dead click as breadcrumb

5 participants