Browser RUM Implementation Guide
By Nicolas Narbais
Use Grafana Faro to capture browser errors, views, Web Vitals, and selected frontend journeys without collecting customer data by accident.
Overview
Real User Monitoring shows what users experience in a browser: slow views, poor Web Vitals, JavaScript errors, and failed API calls. Start with the Grafana Faro Web SDK. Add browser tracing only when you need to follow a browser action into an API that already emits backend traces.
Browser ── Faro: views, errors, Web Vitals ──► Faro collector
│
└── traceparent on approved API calls ─────► Backend traces
Your application team owns the SDK, its data policy, and release identity. Your platform or security team owns the public-token lifecycle, collector allowlist, and cross-origin policy.
Before starting
- Agree the frontend application, public origins, environments, owners, and first customer journey. Start with one application.
- Create the application and public key in your Faro backend. A browser key is public by design, so restrict accepted origins and rotate it when an origin is retired or abused. Do not ship a server-side ingestion key to the browser.
- Set stable identity:
app.namefor the frontend, an immutable build value inapp.version, and the deployment environment inapp.environment. If you add tracing, use the same logical frontend name forservice.name. - Decide which data may leave the browser. Remove or normalize URL parameters, fragments, error messages, console data, and custom-event fields that can contain customer data. Obtain consent before collecting persistent identifiers or replay data.
- List third-party endpoints to exclude. If you add tracing, list the exact API origins allowed to receive
traceparentandtracestateheaders.
References: Frontend Observability instrumentation setup and Faro instrumentation configuration.
Level 1 - Collect the browser baseline
Initialize Faro once in the browser entry point, before the application mounts. In a server-rendered application, run it only in the browser. Use environment-specific build configuration for the collector URL and public key, not a source-controlled value.
import { getWebInstrumentations, initializeFaro } from '@grafana/faro-web-sdk';
initializeFaro({
url: import.meta.env.VITE_FARO_URL,
apiKey: import.meta.env.VITE_FARO_PUBLIC_KEY,
app: {
name: 'customer-portal',
version: import.meta.env.VITE_RELEASE_SHA,
environment: import.meta.env.VITE_DEPLOYMENT_ENVIRONMENT,
},
instrumentations: [...getWebInstrumentations()],
ignoreUrls: [
/^https:\/\/faro-collector\.example\.com\//,
/^https:\/\/analytics\.example\.com\//,
],
});
The default web instrumentations collect uncaught errors, views, session events, browser metadata, and Web Vitals. Keep getWebInstrumentations() when adding custom instrumentation. Replacing it can remove Web Vitals or error capture.
Deploy to a test environment. Load one known route and use the browser Network panel to confirm a successful request to the Faro collector. Trigger one controlled error in the test environment and confirm that it arrives once with useful stack and page context.
Exit criteria: a known navigation has a view, session, application identity, release, and browser-supported Web Vitals. A controlled test error has usable stack and page context.
References: Frontend Observability instrumentation setup and Track Web Vitals.
Level 2 - Make the customer journey readable
Use stable view names and releases so you can compare a regression. For a single-page application, add the framework’s supported router instrumentation. A document-load event does not describe client-side route changes.
Name views from the route template, for example /checkout or /orders/:orderId. Do not use full paths that contain a customer ID, search term, email address, order number, token, query parameter, or fragment. Get app.version from the build or deployment system, not from a page-load timestamp.
Add custom events only for the important transitions in the first journey. Use controlled event names and bounded fields.
faro.api.pushEvent('checkout_submitted', {
flow: 'standard',
payment_method: 'card',
});
Do not send form values, support messages, payment data, credentials, headers, response bodies, full URLs, user IDs, session IDs, cart IDs, or order IDs. Keep console capture disabled unless the captured data is approved. Session replay needs separate approval, consent handling, and a masking test.
Test the successful and failed journey. Confirm that both are distinguishable by the approved view, event, release, and outcome. Search for a deliberately sensitive test value to confirm it did not arrive.
Exit criteria: the first customer journey has stable views and an approved, bounded event trail. A release comparison can show a change in error or performance rate without exposing customer data.
References: Instrument React applications and Frontend Observability instrumentation setup.
Level 3 - Connect an owned API to backend traces
Enable tracing only when the owning API already emits server traces. The Faro tracing package creates browser spans for fetch and XHR calls. It sends trace headers to same-origin requests by default. Add a narrow allowlist for an API on another origin.
import { getWebInstrumentations, initializeFaro } from '@grafana/faro-web-sdk';
import { TracingInstrumentation } from '@grafana/faro-web-tracing';
initializeFaro({
url: import.meta.env.VITE_FARO_URL,
apiKey: import.meta.env.VITE_FARO_PUBLIC_KEY,
app: { name: 'customer-portal', version: import.meta.env.VITE_RELEASE_SHA },
instrumentations: [
...getWebInstrumentations(),
new TracingInstrumentation({
instrumentationOptions: {
propagateTraceHeaderCorsUrls: [/^https:\/\/api\.example\.com\//],
},
}),
],
ignoreUrls: [/^https:\/\/faro-collector\.example\.com\//],
});
The API must accept traceparent and tracestate from the frontend origin in its CORS policy and continue the inbound context in its server SDK. Keep frontend and backend service identities distinct. Trace context must not make the backend trust browser-supplied user, tenant, role, or authorization data.
Test one API call from the known journey. Check that the browser sends a trace header only to the allowlisted origin, then confirm that the browser request and API entry span share one trace. Verify that an unapproved cross-origin request receives no trace header.
Exit criteria: a known browser action can be followed through the owning API’s backend trace without widening cross-origin access to other origins.
References: Capture traces in Faro.
Level 4 - Make browser experience operational
Build the first dashboard from proven RUM data. Show:
- Views, traffic, release, and environment.
- Browser error rate and representative grouped errors.
- Web Vital distribution and poor rate for supported browsers.
- Owned API failures and latency, with a trace pivot when level 3 is enabled.
- The first customer-journey event and outcome rate.
Alert only on sustained customer impact with a named owner and response. Start with a release-specific error increase, a Web Vital regression on the checkout view, or a sustained failure rate for an owned API. Account for traffic volume and sampling before setting a threshold. Test the notification route.
Exit criteria: the owning team can identify a release or view-specific regression and tell whether the problem is in browser code, user experience, or an owned API.
References: Analyze HTTP request health and performance and Track Web Vitals.
Troubleshooting path
Start with one known navigation.
- Confirm that Faro initializes once in the browser with the intended application identity.
- In the Network panel, find the Faro collector request. Fix the first failure: URL, public key, origin, content-security policy, CORS, extension, or network policy.
- If views arrive without Web Vitals or errors, confirm that the default web instrumentations remain enabled and that the browser supports that Web Vital.
- If a custom event is missing, trigger the exact journey and check the consent branch, event name, and source-side filter.
- If traces are separate, inspect
traceparent, the API CORS preflight, and server-side context propagation. Do not broaden the origin allowlist without an owner.
References: Configure Faro instrumentation and Capture traces in Faro.
Completion criterion
A known production-equivalent browser journey has a normalized view, application identity, release, browser-supported Web Vitals, and a safe browser-error test. The team can distinguish a browser regression from an owned API failure and, when tracing is enabled, follow the API request into the backend trace. No prohibited customer value is collected as a RUM attribute or dimension.
Written by Nicolas Narbais
I work at Tsuga and write about observability, OpenTelemetry, and the practical work of making monitoring useful for engineering teams. Earlier Datadog experience also informs the guidance shared here. I am also running Olatuak to help teams reduce telemetry waste and improve observability outcomes.
Need a different implementation route?
Browse the implementation guides for the collection, application, database, logging, and investigation decisions that come next.