Part 1 of 3: Rage Click Detection with LaunchDarklyThe holidays are around the corner and with it comes the expected uptick in traffic, and as traffic increases the need to preserve user experience becomes that much more imperative. You can ship out a new feature, everything seems to be going as planned, and then all of a sudden you start to see a spike in support tickets. The error logs aren’t helpful or show nothing and the metrics look fine.So, what happened?
Wouldn’t you like to literally put yourself in the user’s shoes by seeing exactly what happened in a user session? Enter session replay and more specifically rage clicks as a barometer for user experience.In this three-part series, we’ll explore how LaunchDarkly’s session replay and observability features help you detect, diagnose, and fix user experience issues in real-time. Part 1 covers the fundamentals: what rage clicks are, how to detect them, and how to get started with session replay.
A rage click occurs when a user rapidly clicks the same element multiple times in frustration, usually because the element appears clickable but isn’t responding as expected. It’s one of the strongest behavioral signals that something is wrong with your user experience.
Not every series of rapid clicks qualifies as rage clicks. LaunchDarkly uses three criteria to distinguish genuine frustration from normal user behavior:
These defaults work well for most applications, but LaunchDarkly lets you adjust them based on your specific use case. We’ll cover customization later in this post.
While rage clicks are the most obvious indicator of user frustration, LaunchDarkly’s session replay automatically captures several other behavioral patterns:
Together, these signals paint a complete picture of user frustration, which gives you qualitative context that complements your quantitative metrics.Let’s walk through implementing session replay in a complete application, from installation to viewing your first rage click detection.
Self AppThis health tracking app, written in Javascript, demonstrates LaunchDarkly session replay implementation for detecting user frustration through rage click monitoring.Find all the code for this demo here, with the LaunchDarkly integration instructions in this .md file.
< Note: The observability plugin requires JavaScript SDK version 3.7.0 or later. >Step 2: Configure Environment Variables.
Create a .env file in your project root. You can get your client-side ID from LaunchDarkly: Project Settings > Environments.
// LaunchDarkly session replay and Observability Client Initialization// Based on: https://launchdarkly.com/docs/sdk/observability/javascriptimport { initialize } from 'launchdarkly-js-client-sdk';import Observability from '@launchdarkly/observability';import SessionReplay, { LDRecord } from '@launchdarkly/session-replay';let ldClient = null;let isInitialized = false;export async function initializeLaunchDarkly( clientSideId, user = null, options = {}) { if (isInitialized) { console.warn('LaunchDarkly client already initialized'); return ldClient; } // Default to anonymous user if none provided const userContext = user || { kind: 'user', key: `anonymous-${Date.now()}`, anonymous: true, }; const { manualStart = false, privacySetting = 'default', // 'none', 'default', or 'strict' startSessionReplay = true, } = options; try { // Initialize LaunchDarkly client with observability and session replay plugins // Reference: https://launchdarkly.com/docs/sdk/observability/javascript ldClient = initialize(clientSideId, userContext, { plugins: [ new Observability({ manualStart: manualStart, }), new SessionReplay({ manualStart: manualStart, privacySetting: privacySetting, // Redacts PII based on setting }), ], }); // Wait for client to be ready await ldClient.waitForInitialization(); isInitialized = true; console.log('LaunchDarkly client initialized with observability and session replay'); // Start plugins if not using manual start if (!manualStart) { if (startSessionReplay) { // Start session replay recording // Note: Rage click detection is automatically handled by LaunchDarkly // Configure thresholds in Project Settings > Observability > Session settings // Reference: https://launchdarkly.com/docs/home/observability/settings LDRecord.start({ silent: false, // Show console warnings }); console.log('Session replay started'); } } return ldClient; } catch (error) { console.error('Failed to initialize LaunchDarkly:', error); throw error; }}
Step 4: Implement the LaunchDarkly Client in Main.
Initialize LaunchDarkly in src/main.jsx for:
import React from 'react';import ReactDOM from 'react-dom/client';import App from './App';import './styles.css';import { initializeLaunchDarkly } from './services/launchdarkly';// Get LaunchDarkly client-side ID from environment variableconst LAUNCHDARKLY_CLIENT_ID = import.meta.env.VITE_LAUNCHDARKLY_CLIENT_ID || '';// Initialize LaunchDarkly before React renders// This ensures session replay starts as early as possibleif (LAUNCHDARKLY_CLIENT_ID) { initializeLaunchDarkly( LAUNCHDARKLY_CLIENT_ID, null, // User context (null = anonymous user) { serviceName: 'my-health-app', privacySetting: 'strict', // Recommended for health apps enableNetworkRecording: true, } ).catch((error) => { console.error('Failed to initialize LaunchDarkly:', error); });} else { console.warn('LaunchDarkly client-side ID not configured. Set VITE_LAUNCHDARKLY_CLIENT_ID environment variable.');}ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <App /> </React.StrictMode>);
Now that we have initialized our LaunchDarkly client and configured session replay at the start of the app, we can configure rage detection in the LaunchDarkly UI.
In order to test this integration, you can do the following:
Create a test button that intentionally does nothing:
Rapidly click the button 5+ times within 2 seconds in the same spot.
Wait a few minutes for LaunchDarkly to process the session
Check LaunchDarkly dashboard by navigating to Monitor > Sessions with the option to Filter by has_rage_clicks=true.
To start, your app should look something like this:
When you navigate to Launchdarkly UI -> Sessions, you should be able to see the complete session replay.
In order to test the rage clicks integration, we can add a custom button by adding the following code to the AilmentsListScreen.jsx file within the header div.
<h1>Health Tracker</h1>{/* Test button for rage click detection - click rapidly 5+ times within 2 seconds */}<button style={{ marginTop: '10px', padding: '8px 16px', backgroundColor: '#ff4444', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', fontSize: '12px', }} onClick={(e) => { // Intentionally does nothing - for testing rage clicks e.preventDefault(); console.log('Test button clicked (intentionally non-functional for rage click testing)'); }} title="Test rage click detection: Click rapidly 5+ times within 2 seconds in the same spot"> 🧪 Test Rage Click (Click Rapidly)</button>
Now that you have your test button, you can try clicking it 5+ times within 2 seconds in the same spot as shown in the session below.
Finally, you should see your full session replay under the sessions tab.
It’s important to note that all sessions for a specific app are appended in the session replay tab. So if a user is inactive and comes back to the same tab, the video will be longer. However, if the user starts a new tab or its been more than 4 hours a new video will be created for that session.After enabling rage click, you can now:
Filter sessions by has_rage_clicks=true to find frustrated users.
Replay sessions to see exactly what caused frustration.
Identify specific UI elements that trigger rage clicks.
View correlated errors and network requests in the timeline.
Prioritize fixes based on real user frustration data.
# Basic: All sessions with rage clickshas_rage_clicks=true# Filter by page URLhas_rage_clicks=true AND visited-url contains "/checkout"# Filter by specific HTML element clickedclickSelector="button.submit-order"# Filter by button textclickTextContent contains "Place Order"# Rage clicks with long session durationhas_rage_clicks=true AND active_length > 120s# Combine multiple conditionshas_rage_clicks=true AND browser="Chrome" AND device_type="Desktop"
Session replay is powerful, but it comes with important privacy responsibilities. LaunchDarkly provides several layers of protection to ensure you’re capturing useful debugging data without exposing sensitive user information.Default Privacy Mode: Strict Protection
By default, LaunchDarkly operates in strict privacy mode, which provides the safest option:
All text inputs are obfuscated: Form fields, text areas, and input boxes show as masked characters.
PII regex matching: Text matching patterns for emails, phone numbers, social security numbers, addresses, and credit cards are automatically masked.
Images and media preserved: Visual elements remain visible for UX debugging.
This means you can safely record sessions without worrying about capturing passwords, credit card numbers, or other sensitive data.
Implementing rage click detection with LaunchDarkly session replay is a pretty straightforward process and involves installing the observability sdk with specific plugins. The real power comes from LaunchDarkly’s automatic detection and the ability to replay sessions with full context (errors, logs, network requests) to understand exactly what frustrated users.By detecting rage clicks, we can:
Identify broken or confusing UI elements.
Understand user frustration patterns.
Prioritize fixes based on real user data.
Improve user experience proactively.
This was accomplished without any additional code changes. LaunchDarkly handled everything automatically, and you were able to adjust sensitivity through the dashboard.
You now have the foundation for detecting user frustration with LaunchDarkly’s session replay. You can:
Automatically capture rage clicks, rage scrolls, and form abandons.
Search for sessions with specific frustration patterns.
Watch full session replays with correlated errors and logs.
But detection alone isn’t enough. The real magic comes from connecting these frustration signals directly to your feature releases, so you can catch issues during progressive rollouts and roll back instantly if something breaks.In Part 2, we’ll explore Guarded Releases: how to automatically monitor rage clicks during feature rollouts, set up alerts for frustration spikes, and enable automated rollback when metrics exceed thresholds.You’ll learn how to create a closed-loop system where user frustration signals trigger immediate action, which prevents small issues from becoming widespread problems.Additional Resources: