Real User Monitoring (RUM)
Access the RUM dashboard at https://app.watchlog.io/rum to see real-user traffic, Web Vitals, JavaScript errors, slow resources, and session activity across your applications.
React
Installation
npm i @watchlog/rum-react
# optional (for more precise Web Vitals collection)
npm i web-vitals
Usage (React Router v6)
// src/main.tsx (or src/index.tsx)
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter, Route } from 'react-router-dom'
import { RumProvider, WatchlogRoutes } from '@watchlog/rum-react'
import App from './App'
import User from './UserPage'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<RumProvider
config={{
app: 'my-react-app', // your application name (as shown in the dashboard)
apiKey: '<API-Key>', // copy from Watchlog panel
environment: 'prod', // e.g., 'prod' | 'staging' | 'dev'
endpoint: 'https://api.watchlog.io/rum', // or your self-hosted endpoint
// Sampling & capture options
sampleRate: 0.1, // 0.0–1.0 fraction of sessions to collect
networkSampleRate: 0.1, // sampling for fetch/XHR/resource
enableWebVitals: true, // capture LCP/INP/CLS/TTFB
autoTrackInitialView: true, // send a page_view on first render
captureLongTasks: true, // capture long tasks (main thread)
captureFetch: true, // instrument window.fetch
captureXHR: true, // instrument XMLHttpRequest
// Optional privacy hook (redact, drop, enrich events)
beforeSend: (ev) => {
// Drop event by returning null
// if (ev.type === 'resource') return null
// Example: redact email-like strings from error messages
if (ev.type === 'error' && typeof ev.data?.message === 'string') {
ev.data.message = ev.data.message.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+/gi, '[redacted]')
}
// Example: strip query strings from page URLs
if (ev.context?.page?.url) {
const u = new URL(ev.context.page.url)
u.search = ''
ev.context.page.url = u.toString()
}
return ev
},
}}
>
<BrowserRouter>
{/* Wrap your routes so RUM can auto-track route changes */}
<WatchlogRoutes>
<Route path="/" element={<App />} />
<Route path="/user/:id" element={<User />} />
</WatchlogRoutes>
</BrowserRouter>
</RumProvider>
</React.StrictMode>
)
Event Types Collected
RUM captures several event types out of the box:
- page_view — Route/page navigations (SPA & traditional).
- web_vital — LCP / INP / CLS / TTFB values, with attribution when available.
- resource — Browser resource timings (duration, size, initiator type).
- error — JavaScript errors with message, stack, fingerprint and top paths.
- custom — Optional, user-defined events (e.g., business actions).
Example payloads
page_view
{
"type": "page_view",
"app": "my-react-app",
"environment": "prod",
"ts": "2025-08-21T15:00:00.000Z",
"sessionId": "c8f...",
"deviceId": "c24...",
"context": {
"page": { "url": "https://site.com/user/42", "path": "/user/42", "normalizedPath": "/user/:id", "title": "Profile" },
"viewport": { "w": 1512, "h": 982, "dpr": 2 },
"userAgent": "Mozilla/5.0 ...",
"language": "en",
"timezone": "Asia/Tehran"
}
}
web_vital
{
"type": "web_vital",
"data": { "name": "LCP", "value": 1835.42 },
"context": { "page": { "path": "/user/42" } }
}
resource
{
"type": "resource",
"data": { "name": "https://cdn.example.com/app.js", "duration": 342.1, "transferSize": 128764, "initiator": "script" },
"context": { "page": { "path": "/dashboard" } }
}
error
{
"type": "error",
"data": { "message": "TypeError: Cannot read properties of undefined", "stack": "at ...", "fingerprint": "ab12cd34" },
"context": { "page": { "path": "/checkout" } }
}
Note: You can intercept/modify any event in
beforeSend
. Returnnull
to drop it entirely.
SPA Routing
If you use React Router v6, wrap routes with <WatchlogRoutes>
so RUM detects client-side navigations. If you use another router or a custom setup, you can still trigger a page view manually by toggling autoTrackInitialView
and using the SDK’s route-change helpers (exposed internally by WatchlogRoutes
).
Configuration Reference
Option | Type | Default | Description |
---|---|---|---|
app | string | — | Application name shown in the dashboard. |
apiKey | string | — | Copy from RUM → Your RUM Credentials in the panel. |
endpoint | string | — | Collector endpoint (cloud or self-hosted). |
environment | string | "prod" | Environment tag (e.g., prod/staging/dev). |
sampleRate | number (0.0–1.0) | 1.0 | Fraction of sessions to record. |
networkSampleRate | number (0.0–1.0) | 1.0 | Sampling for resource/fetch/xhr events. |
enableWebVitals | boolean | true | Capture LCP/INP/CLS/TTFB. |
autoTrackInitialView | boolean | true | Send first page_view on mount. |
captureLongTasks | boolean | true | Capture long tasks (>50ms on main thread). |
captureFetch | boolean | true | Instrument window.fetch . |
captureXHR | boolean | true | Instrument XMLHttpRequest . |
beforeSend | `(ev) => ev | null` | undefined |
Privacy & Redaction
Use beforeSend
to drop sensitive events or redact PII. Consider:
- Strip query strings or hashes from URLs.
- Remove email addresses, phone numbers, or form values from error messages.
- Lower sampling for high-traffic pages to reduce data volume.
Troubleshooting
- No data in the dashboard? Confirm endpoint, apiKey, and app match the panel values.
- SPAs not tracking route changes? Ensure your routes are wrapped by
<WatchlogRoutes>
. - Web Vitals missing? Install
web-vitals
and keepenableWebVitals: true
. - Browser blocks third-party scripts? Verify CORS and that your collector domain is reachable from clients.
- Too much data? Lower
sampleRate
/networkSampleRate
, or drop events viabeforeSend
.
Vue — Coming Soon
Vue SDK is in development. It will support automatic page views with Vue Router, Web Vitals, errors, resources, beforeSend
, and TypeScript types. Stay tuned in Changelog for updates.
# Coming soon
npm i @watchlog/rum-vue
Next steps
- Open the dashboard: https://app.watchlog.io/rum
- Copy your Endpoint and API Key from Connect to RUM.
- Deploy to your staging or production environment.
- Explore: Overview → Web Vitals → Errors → Resources → Sessions.