Lesson 26 of 30
CrUX tells you your Chrome users were roughly this fast over the last 28 days. Your own RUM tells you what happened to a specific user, on a specific page, in real time — which is what you actually need to catch and fix a regression.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
Why do most RUM implementations send collected metrics via `navigator.sendBeacon()` instead of a regular `fetch()` call?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
The lab-vs-field lesson in this track established why field data matters: lab tools measure one simulated run under controlled conditions, while field data measures what real visitors actually experienced. This lesson is about the mechanics of collecting that field data yourself, instead of only reading someone else's aggregate.
RUM (Real User Monitoring) works like this: a small JS library — the industry-standard one is Google's web-vitals package — sits on the page and uses the browser's own Performance Observer APIs to watch for each Core Web Vital as it's measured for that one real visitor, live, as they use the page. When a metric finishes being measured (LCP fires once the largest element has painted and no later element beats it, CLS accumulates as shifts happen, INP updates across the whole session), the library hands you that value through a callback.
You then need to get that value off the page and somewhere you can query it. The standard mechanism is navigator.sendBeacon(): it queues a small, asynchronous POST to an endpoint you control (or a RUM vendor's ingestion endpoint) that the browser guarantees will attempt delivery even if the user navigates away a moment later, without blocking or delaying anything else on the page. That's the detail that makes RUM viable at all — a measurement pipeline that competed with the page's own rendering work for resources would be self-defeating.
import { onLCP, onINP, onCLS } from "web-vitals";
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name, // "LCP" | "INP" | "CLS"
value: metric.value,
id: metric.id, // unique per page load, for de-duplication
page: location.pathname,
device: navigator.userAgentData?.mobile ? "mobile" : "desktop",
});
// Fire-and-forget: doesn't block navigation, doesn't compete for the main thread.
navigator.sendBeacon("/api/vitals", body);
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
Each callback fires once that metric has a final (or updated, for INP) value for this specific visitor's session, on this specific page. Multiply that across your real traffic and you have a live, queryable stream of exactly what your users experienced, not a 28-day-old aggregate.
That's the concrete case for building this yourself rather than relying solely on CrUX: CrUX only covers Chrome (nothing about Safari or Firefox visitors), only covers origins with enough traffic volume to be statistically reportable, and reports a rolling 28-day window — so a regression you shipped yesterday is invisible in CrUX for weeks, if it ever clears the traffic threshold at all. Your own RUM is real-time and covers every browser your actual users are on.
sendBeacon matters specifically because of the unload case. A regular fetch() call fired as the user navigates away can get cancelled mid-flight by the browsing context tearing down; sendBeacon is purpose-built to survive that and still deliver.{ name: "LCP", value: 4200 } tells you something is wrong somewhere. Tagging it with page, device, and connection type is what turns that into something actionable.onINP reports the worst interaction observed so far and may update as the session continues — a naive implementation that only listens for the first callback will under-report."How would you know if a performance regression shipped to production before users start complaining?" is a real question that separates candidates who only know Lighthouse from ones who understand that lab tools can't see production traffic at all — RUM is the honest answer.