Real user monitoring (RUM) is a passive observability technique that collects performance and experience telemetry from real user sessions through a JavaScript or mobile SDK. It records page loads, Core Web Vitals, network requests, JavaScript errors, and user interactions as they happen, so teams measure what actual visitors experienced rather than what a test script predicted.
The "real" is the point: RUM instruments every visitor's browser, capturing the full spread of devices, networks, geographies, and usage paths, including the slow tail that test scripts never reproduce. Google's Chrome User Experience Report (CrUX) is essentially a planet-scale RUM dataset: the field data behind Core Web Vitals assessment.
How does real user monitoring work?
Real user monitoring works by loading a small SDK into the page or app, which observes browser performance APIs and user events, batches them, and transmits them to a collection endpoint. The backend enriches each event with session, device, and geography context, then writes it to an event store for querying and alerting.
The pipeline has three stages:
- Instrument. A JavaScript snippet (or mobile SDK) subscribes to browser APIs:
PerformanceObserver, the Navigation Timing and Resource Timing interfaces, error handlers, and interaction listeners. - Beacon. Events are batched and sent to a collection endpoint, typically via the W3C Beacon API (
navigator.sendBeacon), which delivers data reliably even as the user navigates away or closes the tab. - Store and sessionize. The backend stitches events into sessions, enriches them (user agent parsing, geo-IP), and lands them in an event store as wide, high-dimensional records.
A single RUM event at rest is one wide row with many attributes:
{
"timestamp": "2026-07-28T09:14:03Z",
"event_type": "page_load",
"session_id": "9f2c1a",
"url": "/checkout",
"lcp_ms": 2140,
"inp_ms": 180,
"cls": 0.04,
"device": "mobile",
"browser": "Chrome 138",
"country": "DE",
"connection": "4g"
}For instrumentation, OpenTelemetry's JavaScript SDK is the standards-based path: it runs in the browser with instrumentations for document load, fetch, XHR, and user interactions, and exports over OTLP. Browser support is still marked experimental, with a dedicated OpenTelemetry Browser SDK under development, but it keeps frontend telemetry in the same open format as backend traces.
What does RUM capture?
RUM captures five families of telemetry from every session: Core Web Vitals, page and route timings, network request performance, JavaScript errors, and user interaction data. Each is recorded per real page view, with device, browser, geography, and session context attached, so any metric can be segmented by the conditions users actually experienced.
- Core Web Vitals. LCP, INP, and CLS: Google's standard user-experience metrics, measured per page view.
- Page and route timings. Navigation timing (DNS, TCP, TTFB, DOM events) for full loads, plus route changes in single-page applications.
- Network requests. Duration, status, and size of
fetch/XHR calls made by the page, exposing slow API endpoints as users hit them. - JavaScript errors. Uncaught exceptions and unhandled promise rejections, with stack traces and the session context that produced them.
- Sessions and interactions. Click paths, rage clicks, page sequences, and session duration: the behavioural layer that connects performance to user outcomes.
How does RUM measure Core Web Vitals?
RUM measures Core Web Vitals by registering PerformanceObserver callbacks for the browser's largest-contentful-paint, event-timing, and layout-shift entry types, then reporting the final value of each metric when the page is hidden or unloaded. The values are field data, gathered from whatever sessions actually happened.
Most SDKs build on Google's open-source web-vitals library, which encapsulates the measurement rules. The three Core Web Vitals, per web.dev:
| Metric | What it measures | Good (at p75) | Poor |
|---|---|---|---|
| LCP (Largest Contentful Paint) | Loading: time until the largest visible element renders | ≤ 2.5 s | > 4.0 s |
| INP (Interaction to Next Paint) | Responsiveness: worst-case delay from user input to next frame | ≤ 200 ms | > 500 ms |
| CLS (Cumulative Layout Shift) | Visual stability: how much content shifts unexpectedly | ≤ 0.1 | > 0.25 |
INP replaced First Input Delay (FID) as a Core Web Vital on March 12, 2024, because FID measured only the first interaction's input delay. Each metric is assessed at the 75th percentile of page loads, because averages hide the slow experiences that drive users away.
How much data does real user monitoring generate?
RUM generates one to two orders of magnitude more data than most teams expect, because it emits multiple events per page view across every session. A site with 1 million page views per day producing 20-30 events per view generates 20-30 million events daily, or tens of gigabytes of raw wide events.
The volume is events per page view (navigation timing, web-vitals reports, resource entries, errors, interactions) × page views per day × bytes per event. At 25 events per view and 1-2 KB per event, 1 million daily page views yields roughly 25-50 GB per day, or around 750 million to 1.5 billion rows per month. Attributes like session ID, URL, and user agent are also high-cardinality, which strains systems that index every dimension. This is why many RUM vendors sample aggressively, and why the storage engine underneath matters. The same wide-event storage problem appears in log analytics, where the answer is columnar storage and compression rather than discarding data.
RUM vs synthetic monitoring
RUM and synthetic monitoring answer different questions. RUM reports what real users experienced: full device, network, and geographic coverage, but only for pages that received traffic. Synthetic monitoring runs scripted probes on a schedule from controlled locations, so it catches outages at 3 a.m. and validates flows before launch, but only along scripted paths. Mature teams run both: synthetic for availability alerting and pre-production checks, RUM for experience truth.
Common misconceptions about RUM
- RUM is the same as web analytics. Analytics tools count conversions and traffic sources; RUM records performance and reliability telemetry. They share the beacon mechanism but answer different questions.
- RUM replaces synthetic monitoring. RUM only sees pages with traffic. A checkout flow that breaks overnight, or on a low-traffic page, produces no RUM signal until users hit it.
- The RUM SDK will slow the site down. Measurement overhead is real but tiny; passive observers and background beaconing keep it off the critical rendering path.
- Average load time is a good RUM summary. Experience metrics are distributions. Percentiles (p75, p95, p99) expose the slow tail that averages conceal.
Storing and querying RUM data with ClickStack
RUM's defining challenge, billions of wide, high-cardinality events that need fast aggregation, is a columnar database problem. ClickStack, the ClickHouse-based observability stack, ingests browser telemetry through its OpenTelemetry collector distribution and stores each event as a wide row, so session attributes, web vitals, and errors live in one queryable table rather than a sampled subset. HyperDX, ClickStack's UI, provides session-level search and event timelines on top.
Because events sit in ClickHouse, experience questions become SQL over columns. A p75 LCP breakdown takes this shape:
SELECT country, device,
quantile(0.75)(lcp_ms) AS p75_lcp
FROM rum_events
WHERE event_type = 'page_load'
AND timestamp > now() - INTERVAL 7 DAY
GROUP BY country, device
ORDER BY p75_lcp DESCColumnar compression makes retaining unsampled RUM data economical, which matters when an issue affects only one browser version in one country. Frontend events then sit alongside the logs and traces that make up the rest of an observability practice, in the same store.
Frequently asked questions
How do I implement RUM on my website?
Add a RUM SDK, a JavaScript snippet loaded early in the page, configured with a collection endpoint. The SDK auto-collects web vitals, errors, and network timings; custom events are added via its API. The standards-based route is OpenTelemetry's browser instrumentation exporting OTLP to a collector, though browser support remains experimental.
Does real user monitoring affect page performance?
A well-built RUM SDK adds negligible overhead. The script is a few kilobytes, loads asynchronously, and relies on passive browser observers rather than polling. Data transmission uses the Beacon API, which queues delivery in the background instead of blocking navigation. The measurable cost is far smaller than a typical third-party marketing tag.
Is real user monitoring the same as APM?
No. Application performance monitoring instruments backend services (request traces, database calls, service errors), while RUM instruments the client side of the same journey: browser rendering, frontend errors, and user interactions. They are complementary, and OpenTelemetry trace context can connect a user's click in RUM to the backend spans it triggered.
How much does RUM data cost to store?
Cost tracks volume: events per page view × traffic × retention. Columnar databases compress wide, repetitive telemetry by 10x or more, which makes storing full-fidelity RUM events in an analytical store affordable, so sampling stops being the only way to control the bill.
Ready to see your frontend telemetry alongside logs and traces? Try ClickStack, OpenTelemetry-native observability built on ClickHouse.