How LogRocket Works
LogRocket captures user sessions by recording DOM state and mutations, network activity, console output, and JavaScript errors into a structured event stream that can be replayed as a video-like experience. The recording is not screen capture; it is DOM serialization with synchronized side-channel data.
The LogRocket SDK operates four parallel recording subsystems:
DOM Recording: Takes an initial full DOM snapshot (serialized HTML tree), then uses
MutationObserverto capture every subsequent DOM change (node additions, removals, attribute changes, text mutations). CSS stylesheet changes and dynamic style modifications are captured separately.Network Interceptor: Monkey-patches
XMLHttpRequestandfetchto record every network request with method, URL, request headers, request body, response status, response headers, response body, and timing. WebSocket frames are captured if enabled. Request/response bodies are sanitized by default for sensitive endpoints.Console Capture: Wraps
console.log,console.warn,console.error, andconsole.infoto record all console output with timestamps. Unhandled exceptions and promise rejections are captured viawindow.onerrorandunhandledrejectionevent listeners.State Management Plugins: Optional middleware for Redux, Vuex, NgRx, and MobX that records every dispatched action and resulting state diff. State snapshots are stored as JSON patches rather than full copies to minimize payload size.
All captured data is batched, compressed, and transmitted to https://r.lr-in.com via POST requests. The SDK uses sendBeacon for page unload events to prevent data loss during navigation. Each session is assigned a unique URL: https://app.logrocket.com/YOUR_ORG/YOUR_APP/sessions/SESSION_ID.
LogRocket identifies visitors via a first-party cookie with a 2-year expiry. Cross-session identity linking occurs when LogRocket.identify() is called.
Installing the Tracking Script
Script Tag Installation
Add to <head> before the closing tag. Replace APP_ID with your LogRocket app slug (format: org-slug/app-slug):
<script src="https://cdn.lr-in.com/LogRocket.min.js" crossorigin="anonymous"></script>
<script>
window.LogRocket && LogRocket.init('APP_ID');
</script>
npm Installation
npm install logrocket
import LogRocket from 'logrocket';
LogRocket.init('APP_ID');
Configuration Options
LogRocket.init('APP_ID', {
release: '1.2.3', // App version for filtering sessions
console: {
isEnabled: {
log: true,
warn: true,
error: true,
info: false, // Disable info-level capture
debug: false // Disable debug-level capture
}
},
network: {
isEnabled: true,
requestSanitizer: (request) => {
// Remove authorization headers from recordings
if (request.headers['Authorization']) {
request.headers['Authorization'] = '***';
}
// Exclude health check endpoints entirely
if (request.url.includes('/health')) {
return null;
}
return request;
},
responseSanitizer: (response) => {
return response;
}
},
dom: {
isEnabled: true,
inputSanitizer: true // Mask all input field values by default
},
shouldCaptureIP: false, // Do not store visitor IP
rootHostname: 'example.com' // Share identity across subdomains
});
State Management Plugins
Redux:
import LogRocket from 'logrocket';
import createPlugin from 'logrocket-redux';
const logRocketMiddleware = createPlugin(LogRocket);
const store = createStore(
rootReducer,
applyMiddleware(logRocketMiddleware)
);
The Redux plugin records every dispatched action with its type and payload, plus the resulting state diff. In session replay, you can scrub to any point in time and inspect the Redux state.
Vuex:
import LogRocket from 'logrocket';
import createPlugin from 'logrocket-vuex';
const store = new Vuex.Store({
plugins: [createPlugin(LogRocket)],
state: { /* ... */ },
mutations: { /* ... */ }
});
NgRx:
import LogRocket from 'logrocket';
import createPlugin from 'logrocket-ngrx';
export const metaReducers = [createPlugin(LogRocket)];
Content Security Policy
script-src: https://cdn.lr-in.com https://cdn.lr-ingest.io
connect-src: https://r.lr-in.com https://r.lr-ingest.io
Event Tracking and Data Collection
Custom Events
Track application-specific events that appear in the session timeline and are searchable in the LogRocket dashboard:
LogRocket.track('Purchase Completed', {
orderId: 'ORD-12345',
revenue: 149.99,
itemCount: 3,
paymentMethod: 'credit_card'
});
LogRocket.track('Feature Activated', {
feature: 'bulk_export',
plan: 'enterprise'
});
LogRocket.track('Search Performed', {
query: 'analytics dashboard',
resultCount: 24,
filters: 'date:last_30_days'
});
Event properties support strings, numbers, and booleans. Nested objects are not supported.
Error Tracking
LogRocket automatically captures:
- Unhandled JavaScript exceptions (
window.onerror) - Unhandled promise rejections (
unhandledrejection) - React error boundaries (with
LogRocket.captureException) - Network errors (4xx/5xx responses)
Manually capture caught exceptions:
try {
riskyOperation();
} catch (error) {
LogRocket.captureException(error, {
tags: {
component: 'PaymentForm',
severity: 'critical'
},
extra: {
userId: currentUser.id,
attemptNumber: retryCount
}
});
}
Performance Monitoring
LogRocket automatically captures Core Web Vitals (LCP, FID, CLS) and page load timing. Access performance data in the LogRocket dashboard under the Performance tab.
For custom performance marks:
// Standard Performance API marks are captured automatically
performance.mark('checkout-start');
// ... checkout logic ...
performance.mark('checkout-end');
performance.measure('checkout-duration', 'checkout-start', 'checkout-end');
Identity and User Tracking
User Identification
Call LogRocket.identify() after authentication to link sessions to known users:
LogRocket.identify('user_12345', {
name: 'Jane Smith',
email: 'jane@example.com',
plan: 'enterprise',
accountId: 'acct_789',
role: 'admin'
});
The first argument is your internal user ID (string). The second argument is a traits object. name and email are reserved keys displayed in the LogRocket UI. All other keys are custom traits for filtering and search.
Session URL Access
Get the current session URL programmatically for integration with support tools:
LogRocket.getSessionURL((sessionURL) => {
// Attach to support ticket
supportWidget.setMetadata('logrocket_session', sessionURL);
// Send to your analytics platform
analytics.track('Session Started', { logrocketUrl: sessionURL });
// Log for debugging
console.log('LogRocket session:', sessionURL);
});
Integration with Error Tracking Services
Sentry:
import * as Sentry from '@sentry/browser';
import LogRocket from 'logrocket';
LogRocket.getSessionURL((sessionURL) => {
Sentry.configureScope((scope) => {
scope.setExtra('logrocket_session', sessionURL);
});
});
Every Sentry error report now includes a link to the LogRocket session replay showing exactly what happened.
Datadog RUM:
LogRocket.getSessionURL((sessionURL) => {
datadogRum.addRumGlobalContext('logrocket_session', sessionURL);
});
API and Data Export
Session Search API
Query sessions programmatically:
curl -X POST \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"userId": "user_12345",
"dateRange": {
"start": "2025-11-01T00:00:00Z",
"end": "2025-11-15T00:00:00Z"
}
},
"limit": 20,
"offset": 0
}' \
"https://api.logrocket.com/v1/orgs/YOUR_ORG/apps/YOUR_APP/sessions/search"
Data Export API
Export raw session data for warehouse ingestion:
curl -X POST \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dateRange": {
"start": "2025-11-01T00:00:00Z",
"end": "2025-11-02T00:00:00Z"
},
"exportType": "sessions"
}' \
"https://api.logrocket.com/v1/orgs/YOUR_ORG/apps/YOUR_APP/exports"
The export endpoint returns a download URL for a JSON Lines file containing session metadata, event summaries, and error data.
Webhook Integration
Configure webhooks in Settings > Integrations to receive real-time session notifications:
{
"event": "session.error",
"session": {
"id": "SESSION_ID",
"url": "https://app.logrocket.com/YOUR_ORG/YOUR_APP/sessions/SESSION_ID",
"userId": "user_12345",
"duration": 185,
"errorCount": 2,
"frustratedSignals": 1
},
"errors": [
{
"message": "TypeError: Cannot read property 'map' of undefined",
"source": "app.bundle.js:1234:56",
"timestamp": "2025-11-15T14:30:22Z"
}
]
}
Jira Integration
LogRocket can automatically attach session replay URLs to Jira issues. Configure in Settings > Integrations > Jira:
// Programmatically create a Jira issue with session context
LogRocket.getSessionURL((sessionURL) => {
fetch('/api/jira/create-issue', {
method: 'POST',
body: JSON.stringify({
summary: 'User reported checkout bug',
description: `Session replay: ${sessionURL}`,
project: 'ENG',
issueType: 'Bug'
})
});
});
Common Issues
Session replay shows a blank or broken page: The LogRocket SDK failed to capture the initial DOM snapshot. This happens when the SDK loads after the page is fully rendered and the initial snapshot is missed. Place the LogRocket script as early as possible in <head>. Also verify CSP headers allow https://cdn.lr-in.com in script-src.
Redux actions appear as @@UNKNOWN: The Redux plugin was not applied correctly. Ensure createPlugin(LogRocket) is called after LogRocket.init() and that the resulting middleware is passed to applyMiddleware(). If using Redux Toolkit, add the middleware to configureStore:
import { configureStore } from '@reduxjs/toolkit';
import LogRocket from 'logrocket';
import createPlugin from 'logrocket-redux';
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(createPlugin(LogRocket))
});
Network request bodies not captured: By default, LogRocket captures request and response bodies for XHR and Fetch calls. If bodies appear empty, check that the requestSanitizer or responseSanitizer is not returning null for those requests. Also verify the response Content-Type is application/json; binary and streaming responses are not captured.
Identify not linking sessions: LogRocket.identify() must be called after LogRocket.init() completes. If called synchronously before the SDK initializes, the identify call is queued. Verify the SDK has loaded by checking window.LogRocket before calling identify. Also ensure the user ID is a non-empty string.
High SDK payload size causing slow page interactions: On pages with extremely frequent DOM mutations (real-time data feeds, live chat, animation-heavy pages), the MutationObserver generates large event volumes. Use conditional recording:
// Only record sessions for authenticated users
if (currentUser) {
LogRocket.init('APP_ID');
LogRocket.identify(currentUser.id);
}
Source maps not resolving: Upload source maps to LogRocket during your build process:
npx @logrocket/cli upload-sourcemaps ./dist \
--org=YOUR_ORG \
--app=YOUR_APP \
--release=1.2.3 \
--api-key=YOUR_CLI_API_KEY
Match the release value to the one passed in LogRocket.init() options.
Platform-Specific Considerations
Privacy Controls
LogRocket provides multiple layers of data sanitization:
Input masking (enabled by default with inputSanitizer: true): All <input>, <textarea>, and <select> values are replaced with asterisks in recordings. The DOM structure and layout are preserved, but actual values are not captured.
Element-level exclusion: Prevent specific elements from being captured:
<!-- Exclude this element and all children from recording -->
<div data-logrocket-hidden>
<p>This content will not appear in session replay</p>
</div>
<!-- Redact text content but preserve layout -->
<div data-logrocket-redacted>
<span>Visible text is replaced with placeholder characters</span>
</div>
Network sanitization: Scrub sensitive data from request/response bodies:
LogRocket.init('APP_ID', {
network: {
requestSanitizer: (request) => {
// Remove tokens from headers
if (request.headers['Authorization']) {
request.headers['Authorization'] = '[REDACTED]';
}
// Strip sensitive body fields
if (request.body) {
try {
const body = JSON.parse(request.body);
delete body.password;
delete body.ssn;
request.body = JSON.stringify(body);
} catch (e) { /* not JSON */ }
}
return request;
}
}
});
Session Sampling
Control which sessions are recorded to manage costs and data volume:
// Record 25% of sessions randomly
if (Math.random() < 0.25) {
LogRocket.init('APP_ID');
}
// Record all sessions for paying customers, sample free users
if (currentUser.plan === 'paid') {
LogRocket.init('APP_ID');
} else if (Math.random() < 0.1) {
LogRocket.init('APP_ID');
}
Performance Overhead
The LogRocket SDK adds approximately 50KB (gzipped) to initial page load. Runtime overhead depends on DOM complexity and mutation frequency:
- Typical pages: Less than 1% CPU overhead
- High-mutation pages (real-time feeds, virtualized lists): 2-5% CPU overhead
- Network interception: Negligible overhead per request; bodies are cloned asynchronously
For performance-critical paths, you can temporarily disable recording:
// Disable during performance-sensitive operations
LogRocket.shutdown();
performCriticalAnimation();
LogRocket.start();
Cross-Domain Session Continuity
LogRocket sessions are scoped to the domain where LogRocket.init() was called. To link sessions across subdomains, set rootHostname:
LogRocket.init('APP_ID', {
rootHostname: 'example.com' // Shares identity cookie across *.example.com
});
Cross-domain tracking (e.g., app.example.com to checkout.different.com) is not natively supported. Use LogRocket.getSessionURL() to pass the session URL between domains for manual correlation.