RUM (Real User Monitoring)
Real User Monitoring: measuring page performance in the browsers of real visitors on the live site and reading it as a distribution. RUM reports the TTFB and Core Web Vitals that real devices, networks and locations saw — the field counterpart to a synthetic test run from machines you pick.
Also known as Real User Monitoring, Real User Measurement.
Full Explanation
RUM (Real User Monitoring) measures page performance in the browsers of real visitors while they use the live site. Every load reports its own timings, so the TTFB and latency in the data are what that person actually got, on that device and that network. RUM is passive monitoring: it records interaction without changing how the site behaves. It is not a synthetic test. Nothing is scripted, and you do not choose the vantage points. That is why RUM is unusually good at exposing last-mile problems. Google calls this side of the split field data, as against lab data from a controlled run. The trade is fixed: RUM tells you who was slow, but not which layer was to blame. It only sees pages people actually visited. And it needs traffic before it says anything at all.
How it works
A small JavaScript snippet runs in the page and reads the browser's performance APIs. This snippet is called the beacon. Navigation Timing covers the document's own navigation. Resource Timing covers every subresource. Between them they expose the load as timestamps. DNS lookup time is domainLookupEnd - domainLookupStart. TCP handshake time is connectEnd - connectStart. TLS negotiation time is requestStart - secureConnectionStart. And responseStart marks the first byte of the response.
On top of those raw timestamps, the snippet computes the user-centric metrics. The current Core Web Vitals are LCP for loading (good: within 2.5 seconds), INP for interactivity (200 milliseconds or less) and CLS for visual stability (0.1 or less). The recommended way to judge them is at the 75th percentile of page loads, split across mobile and desktop. TTFB and FCP are not Core Web Vitals. Google treats them as supplemental metrics that help diagnose LCP.
Each sample is shipped to a collector with navigator.sendBeacon(). This call queues an asynchronous POST of at most about 64 KiB. It neither delays unload nor slows the next navigation. Timing matters. Metrics such as CLS are only final once the page goes away. The reliable moment to send is the visibilitychange event, when the page's visibility state becomes hidden. The older unload and beforeunload events are unreliable, especially on mobile. They are not recommended, partly because they can keep a page out of the back/forward cache. The collector then aggregates the samples into a distribution. It reports percentiles, not a mean, segmented by country, device, browser and connection speed.
Why it matters for a CDN
A CDN exists to be fast for a specific population of users. Only field data shows what that population received. Google is blunt about it: "Only field measurement can accurately capture the complete picture." TTFB is the metric most nearly shaped by the CDN. That is because it is measured from the start of navigation, and is the sum of redirect time, service worker startup, DNS lookup, connection and TLS negotiation, and the request itself, nearly all of it inside the delivery path. As a rough guide, web.dev puts a good TTFB at 0.8 seconds or less, and a poor one above 1.8 seconds. It notes that TTFB is not itself a Core Web Vital.
The segmentation is what makes RUM decisive for delivery work. Broken out by country, network and device, RUM shows the regions and ISPs where the edge is winning. It also shows the ones a handful of fixed probes could never represent. It is also the number to hold beside cache hit ratio. A high hit ratio proves the edge answered, not that users were fast.
Google's own field dataset is the Chrome User Experience Report (CrUX). It is collected from real Chrome users and is used by Google Search to inform the page experience ranking factor. But it is not a substitute for your own RUM. Not every origin or page is in it. A page must be publicly discoverable and have "a large enough number of visitors in order to create a statistically significant dataset". CrUX also gives no per-pageview telemetry. That is why Google strongly recommends that sites set up their own real-user monitoring.
What CDNs do
Where a CDN ships RUM of its own, the beacon is normally injected at the edge. So nothing has to change at the origin. Two documented examples:
- Cloudflare ships a RUM beacon with Web Analytics and Observatory. For sites proxied through Cloudflare, the snippet can be injected automatically into the HTML as the response passes through the edge network. This happens once you enable the automatic-injection option. Otherwise, you embed it by hand. It collects LCP, INP, CLS, TTFB and FCP, using Google's open-source web-vitals module. It also collects navigation and resource timing. And it discards the client IP at the nearest data centre. Free-plan customers have RUM enabled automatically, with traffic from the EEA, the UK and Switzerland excluded. They can switch it off. Other plans enable it as needed.
- Akamai sells RUM as mPulse. Its snippet loads the open-source boomerang.js library. Where Akamai delivers the traffic, the edge server injects the snippet into the page, and the browser beacons the data back to an edge collector. mPulse also works for sites Akamai does not deliver, with the snippet placed at the origin or through a tag manager. The beacon carries geography, bandwidth, user-agent and resource timing alongside custom business metrics.
Cloudflare's Observatory is a useful model of the intended pairing. Synthetic Lighthouse and network tests give repeatable comparisons. RUM covers the conditions no probe reproduces: other parts of the world, other network conditions and ISPs, other devices and browsers, and the extensions and background software competing for resources on a real machine. Cloudflare notes one asymmetry explicitly: real user data yields INP, which synthetic tests do not offer.
Watch out for
- RUM reports what, not why. It identifies the slow cohort, not the layer: DNS, TLS, edge, origin or last mile. The mechanism that closes that gap is Server-Timing. Its values surface to the beacon as PerformanceServerTiming entries on navigation and resource entries. This lets a CDN label its own share of the time.
- Cross-origin timings are blank by default. Serve assets from a CDN hostname, and Resource Timing returns 0 for domainLookupStart/End, connectStart/End, secureConnectionStart, requestStart and responseStart, unless the response carries Timing-Allow-Origin. Without that header, your RUM cannot see the CDN it is meant to be measuring.
- Averages mislead. A small group on very slow networks never moves the mean enough to look like a problem. Yet those are the users you lost. Report percentiles: the 75th to judge Core Web Vitals, p95 and p99 for the tail.
- RUM is not a census. Consent gates, vendor geography rules (Cloudflare's default free-plan exclusion of EEA, UK and Swiss traffic), and plain low traffic all thin the sample. A quiet page may not clear CrUX's visitor threshold at all.
- Measurement can distort the measurement. Analytics loaded in a blocking way hurts LCP. A large or long-task-heavy beacon script hurts the very INP it reports.
- 103 Early Hints shifts what "first byte" means. A 103 counts as the first bytes for responseStart. So a CDN sending Early Hints lowers measured TTFB, while the final document response is timed separately by finalResponseHeadersStart. Chrome moved responseStart to the final response in version 115, and reverted it in 133. So compare like with like before declaring a win.
Best practice
- Report distributions, never a bare average: the 75th percentile for the Core Web Vitals verdict, p95 and p99 for the tail that churns.
- Segment by country, network, device and browser before drawing any conclusion about a CDN configuration. The aggregate hides exactly the population a delivery change is meant to fix.
- Load the beacon asynchronously and last. Send it with sendBeacon() on visibilitychange. Track only the metrics you will act on.
- Send Timing-Allow-Origin from CDN asset responses, and Server-Timing from the edge. Then RUM can attribute time instead of merely reporting it.
- Pair RUM with synthetic tests in both directions. Synthetic catches regressions under repeatable conditions before release. RUM is the only source for interaction metrics such as INP, and for the real device and network mix.
- Stamp every delivery change with a version, and track that version in the beacon. Do not assume that everything after the deploy date reflects the new configuration: caching at the HTTP, service worker or CDN layer can keep serving the old one.
Examples
# Basic RUM with Navigation Timing API
<script>
window.addEventListener('load', () => {
const perf = performance.getEntriesByType('navigation')[0];
const data = {
dns: perf.domainLookupEnd - perf.domainLookupStart,
tcp: perf.connectEnd - perf.connectStart,
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
ttfb: perf.responseStart - perf.requestStart,
download: perf.responseEnd - perf.responseStart,
dom: perf.domContentLoadedEventEnd - perf.responseEnd,
total: perf.loadEventEnd - perf.startTime
};
navigator.sendBeacon('/analytics', JSON.stringify(data));
});
</script>
Frequently Asked Questions
Real User Monitoring: measuring page performance in the browsers of real visitors on the live site and reading it as a distribution. RUM reports the TTFB and Core Web Vitals that real devices, networks and locations saw — the field counterpart to a synthetic test run from machines you pick.
# Basic RUM with Navigation Timing API
<script>
window.addEventListener('load', () => {
const perf = performance.getEntriesByType('navigation')[0];
const data = {
dns: perf.domainLookupEnd - perf.domainLookupStart,
tcp: perf.connectEnd - perf.connectStart,
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
ttfb: perf.responseStart - perf.requestStart,
download: perf.responseEnd - perf.responseStart,
dom: perf.domContentLoadedEventEnd - perf.responseEnd,
total: perf.loadEventEnd - perf.startTime
};
navigator.sendBeacon('/analytics', JSON.stringify(data));
});
</script>
Yes. RUM (Real User Monitoring) is also known as Real User Monitoring, Real User Measurement. Real User Monitoring: measuring page performance in the browsers of real visitors on the live site and reading it as a distribution. RUM reports the TTFB and Core Web Vitals that real devices, networks and locations saw — the field counterpart to a synthetic test run from machines you pick.
Related CDN concepts include:
- Cache Hit Ratio (CHR) — The share of requests a cache answers from its own stored copies instead of fetching …
- Latency — Latency is the time data takes to travel from one point on a network to …
- TTFB (Time To First Byte) (TTFB) — TTFB is the time from the start of a request until the first byte of …