Frustration Tracking surfaces three high-signal interactions that almost always indicate UX pain: rage clicks, dead clicks, and error clicks. Use it as a triage shortcut into the pages and elements that confuse or break for real visitors.
What gets tracked
Three click patterns are captured automatically once the feature flag is on.
| Type | Definition |
|---|---|
| Rage click | 3+ clicks within 600ms on the same element or 30×30px area. The user is hitting something that looks clickable but is not responding. |
| Dead click | A click on a non-interactive element with no DOM mutation within 1 second. Looks clickable, isn't. |
| Error click | A click that triggered a JavaScript error within 100ms. The click broke something. |
These three click types are the full set the tracker captures today. There is no extra configuration: when the feature flag is on, the tracker watches for all three.
Privacy guarantees
Frustration events store only diagnostic signals about the element that was clicked — never the contents of the page around it.
What is captured:
- The element's CSS selector and a short DOM breadcrumb (e.g.
main > section > button.checkout-confirm) - The element's visible label or text, capped at 100 characters (e.g. the word "Submit" on a button)
- The element's ARIA role and aria-label, where present
- The element's computed
cursorstyle (used to flag a "looks clickable but isn't" mismatch) - Click coordinates relative to the viewport
- The page URL and title
- The frustration type and timestamp
- The session and visitor IDs the rest of your analytics already use
What is not captured: form values, file content, the contents of other elements on the page, or any other PII. All strings are bounded defensively. If a visitor has Global Privacy Control enabled, frustration tracking is skipped along with the rest of behavioural processing.
Enable it for a website
- Open Settings → Advanced for the website you want to track.
- Scroll to Feature Flags and turn on Frustration Tracking.
- Reload any open page on the site so the tracker picks up the new feature flag (it refreshes within ~5 minutes automatically).
The toggle is gated to the Pro plan and above.
Where to view it
Open the Errors tab in your dashboard, then switch to the Frustration sub-tab.
You'll see three panels:
- Spotlight — a hero card at the top that auto-selects the highest-priority issue based on event count, unique users affected, recency, and whether it started after your last deploy. The card opens with a plain-language What happened sentence ("A visitor clicked the element labelled 'Submit' on /checkout but nothing happened"), a likely-cause diagnosis, a one-click Copy selector button, a ready-to-paste Reproduce in DevTools snippet, and a Copy for ticket button that bundles everything for handing to a developer.
- Frustration trend — three sparkline cards (Rage / Dead / Error), one per type, showing event counts over the selected range. Toggle to a combined line chart with the Cards / Lines switch in the top-right.
- Top hotspots — a sortable worklist where each row is a single broken element on a single page. Each row shows the selector, page path, visible element label, and counts per type. Click any row to expand: read the same plain-language summary, copy the selector, view recent events, and (for error clicks) see the matching JS error inline. Background-container clicks (clicks that bubbled up to
<main>,<body>, or<html>from empty whitespace) are flagged with a muted Background badge so you can skip them at a glance.
You can filter by frustration type (Rage / Dead / Error), URL prefix, and time range (1h / 24h / 7d / 30d).
Reading the dashboard
The "Top hotspots" table is your worklist. Each row is a single broken element on a single page — sortable by priority.
Both the Spotlight card and each expanded row share the same triage layout:
- A plain-language What happened sentence — readable to anyone on your team, no technical knowledge required.
- A Likely cause diagnosis tuned to the click type and the element's visible signals. The dashboard reads the element's
cursorstyle and tag name to call out the smoking-gun cases ("CSS says clickable, the tag is not a button — make it a real<button>or<a>", or "stuck loading state — handler may throw silently") rather than dumping a generic definition on you. - A Reproduce in DevTools snippet — paste it into the page's console and every matching element gets a red outline + a
[zenovay] matchlog line, so you can find the broken element instantly. - A Copy selector button (for jumping into DevTools' element inspector) and a Copy for ticket button (for handing the whole context — page, element, type, counts, suggested fix — to a developer in one paste).
- For error clicks: the linked JavaScript error message and a Copy fingerprint button so you can pivot into the Errors tab.
- The last few events on the same element with viewport coordinates and session ids.
The Spotlight card auto-selects the highest-priority issue using:
priority = (rage × 3 + dead × 1.5 + error × 5) × ln(unique_users + 1) × recency_boost
Recency boost is 1.5× within the last 24 h. Background-container clicks are heavily de-prioritised so they never end up as the Spotlight. If a hotspot started after your last GitHub deploy, the row gets an amber NEW badge — that's almost always a regression.
Tips for triage
- Start at the Spotlight. Read the plain-language sentence, scan the likely-cause diagnosis, copy the DevTools snippet, paste it into the page's console — the broken element will be outlined.
- Hand it to a developer in one paste. If you're a PM or founder spotting an issue, the Copy for ticket button bundles the page, element, click type, counts, and a suggested fix into a single message you can drop into Linear, Jira, or Slack.
- Watch for the NEW badge. Hotspots flagged as new since your last deploy are almost always regressions worth fixing first.
- Pair rage with error. Rage clicks on the same selector as an error click point to a real exception — fix the JS error and the rage usually disappears.
- Dead clicks reveal expectations. A page where many visitors dead-click the same div tells you what they expected to be clickable. Either make it interactive, or remove the visual cue (e.g.
cursor: pointer). - Skip the Background rows. Rows tagged Background are clicks that landed on empty whitespace and bubbled up to a container; they very rarely indicate a real bug.
Limitations
- Frustration events are retained for roughly 90 days, then purged automatically. They are a triage signal, not a long-term archive — investigate hotspots while they're fresh.
- Event capture is throttled at the tracker layer to avoid runaway counts on broken pages — you'll see a representative sample, not every click.
- Hotspots aggregate across the lifetime of stored data; the chart respects the selected time range.