flusterduck
v0.7.10
Published
Rage click detection, dead click tracking, and form abandonment monitoring across 132 UX friction signals. Privacy-first analytics without session replay.
Maintainers
Keywords
Readme
flusterduck
Browser SDK for UX friction monitoring. Detects and classifies rage clicks, dead clicks, form abandonment, navigation loops, and 20+ other behavioral signals locally in the browser. No configuration required beyond your publishable key.
Installation
npm install flusterduckOr load via script tag:
<script async src="https://cdn.jsdelivr.net/npm/flusterduck@0/dist/d.global.js" data-key="fd_pub_..."></script>Basic usage
import { init } from 'flusterduck';
init({ key: 'fd_pub_...' });Call init once on page load. It's idempotent; calling it again does nothing. The SDK attaches all signal detectors, starts batching events, and observes route changes automatically.
Manual signals
import { signal, track, identify } from 'flusterduck';
// Custom friction signal with optional weight (0-100, default 15)
signal('checkout_error', { element: '#pay-btn', weight: 30 });
// Business event for correlation
track('checkout_started', { plan: 'scale' });
// Segment for filtering in the dashboard
identify({ plan: 'scale', role: 'admin' });Configuration
init({
key: 'fd_pub_...',
// Tag events by environment
environment: 'production',
// Only track a fraction of sessions (0-1)
sampleRate: 0.5,
// Cookieless mode: memory-only session ID, no Flusterduck cookie
cookieless: false,
// Respect DoNotTrack and GlobalPrivacyControl (default: true)
respectDoNotTrack: true,
// Map URL patterns to logical page names
pageRules: [
{ pattern: '/checkout/*', label: '/checkout' },
{ pattern: '/blog/*', label: '/blog' },
],
// Segment all events from this init call
segment: { plan: 'scale' },
// Control individual detectors
signals: {
rageClick: { enabled: true },
deadClick: { enabled: true },
formHesitation: { enabled: true, threshold: 3000 },
loopNav: { enabled: true },
helpHunt: { enabled: false },
},
// Skip tracking entirely on these pages
ignorePages: ['/internal', '/admin'],
// Skip signal detection on matching elements
ignoreElements: ['.no-track', '[data-fd-ignore]'],
// DOM evidence capture: 'off' | 'metadata' | 'snapshot'
domMode: 'metadata',
// Event batching
batchInterval: 2000,
batchMaxSize: 50,
});Consent and opt-out
import { setConsent, optOut } from 'flusterduck';
// Pass true after the user accepts your cookie banner
setConsent(true);
// Permanently opt out: clears session and stops all tracking
optOut();init defers automatically if respectDoNotTrack is enabled and the user's browser signals DNT or Global Privacy Control. Call setConsent(true) explicitly to override.
Signal detectors
Automatic detectors (all on by default):
| Signal | Description |
|---|---|
| rageClick | 3+ clicks on the same target within 700ms |
| deadClick | Click with no DOM change within 500ms |
| speedFrustration | Server response takes over 3s |
| thrashCursor | High-velocity erratic mouse movement |
| loopNav | Same page visited 3+ times in one session |
| scrollBounce | Scroll to bottom then immediately back |
| formHesitation | Pause over 3s in a form field |
| formAbandon | Form interaction without submission |
| formValidationLoop | 3+ failed submit attempts |
| errorEncounter | Uncaught JS errors or unhandled rejections |
| scrollHijack | Scroll direction reversed by the page |
| scrollDepthAbandon | Scroll past 80% then leave without action |
| helpHunt | Repeated clicks on help/support elements |
| closeClick | Modal/overlay dismissed repeatedly |
| filterSpiral | Rapid filter/sort changes |
| copyFrustration | Copy attempt on non-selectable content |
| navigationConfusion | Back/forward used immediately after navigation |
| deadClickTrapZone | Cluster of dead clicks in one area |
Mobile-only (activates automatically on touch devices):
| Signal | Description |
|---|---|
| mobileTapMiss | Tap on non-interactive element |
| pinchZoom | Pinch-to-zoom on non-zoomable content |
| swipeFrustration | Failed swipe gestures |
Keyboard:
| Signal | Description |
|---|---|
| tabThrash | Tab key used rapidly without focusing any input |
| focusTrap | Focus trapped in a region |
| keyboardNavFrustration | Arrow key navigation with no visible change |
Lifecycle
import { destroy } from 'flusterduck';
// Tears down all detectors and flushes the event queue
destroy();Route changes in SPAs are detected automatically via History API patching and popstate. You don't need to call anything on navigation.
Key format
The SDK only accepts publishable keys (fd_pub_). If a secret key (fd_sec_) is passed, it logs an error and aborts. Nothing is tracked.
