Browser performance
configureFrontend() enables Web Vitals by default. Long Animation Frame
reporting is opt-in. Use the Frontend page
to investigate the collected data.
The examples use frontendOptions from the browser setup.
Add these options to your application’s existing configureFrontend() call.
configureFrontend() records Core Web Vitals from real browser sessions by default:
logfire.configureFrontend({
...frontendOptions,
rum: { webVitals: true },
})
The browser SDK dynamically loads web-vitals/attribution only when
rum.webVitals is enabled. It records LCP, INP, CLS, FCP, and TTFB as short
OpenTelemetry spans named web_vital.lcp, web_vital.inp, web_vital.cls,
web_vital.fcp, and web_vital.ttfb. These point events carry exact
logfire.span_type = 'log'.
Every Web Vital span includes web_vital.name, web_vital.value,
web_vital.delta, web_vital.id, web_vital.rating, and
web_vital.navigation_type. It also includes available navigation identity,
interaction, and start-time fields as web_vital.navigation_*. Attribution fields include values such as
web_vital.lcp.target, web_vital.inp.target, and
web_vital.cls.largest_shift_target.
When INP attribution identifies a culprit Long Animation Frame script, the INP
span also includes its normalized source URL, bounded function name, invoker,
and duration as web_vital.inp.script.* attributes. These diagnostic fields
remain span-only and are not added to Web Vitals metrics.
rum.webVitals implies default rum.session behavior so Web Vital spans get
session and URL attributes. To sanitize URLs while reporting Web Vitals, pass
session options alongside Web Vitals:
logfire.configureFrontend({
...frontendOptions,
rum: {
session: {
urlAttributes: (url) => ({
full: `${url.origin}${url.pathname}`,
path: url.pathname,
}),
},
webVitals: {
reportAllChanges: true,
},
},
})
Web Vitals observers live for the page lifetime. The first successful startup
fixes reportAllChanges, generateTarget,
includeProcessedEventEntries, and reportSoftNavs; later configure() calls can update the tracer
and metric destination but ignore changed observer options with a diagnostic
warning. If the initial lazy load or observer startup fails, a later
configure() call retries it.
configureFrontend() enables Web Vitals histogram metrics by default. To keep
Web Vitals spans while disabling histogram emission:
logfire.configureFrontend({
...frontendOptions,
rum: {
webVitals: {
metrics: false,
},
},
})
configureFrontend() derives the metrics endpoint from baseUrl automatically.
With the lower-level configure(), metric export is disabled unless top-level
metrics.metricUrl is configured, and rum.webVitals.metrics requires that
transport. The SDK uses a local
OpenTelemetry MeterProvider; it does not replace the application’s global
meter provider. If that metrics runtime fails to start, the SDK emits an
explicit diagnostic and continues Web Vitals span reporting without a metric
recorder. It never retries configured authentication with empty headers.
Web Vitals metrics are histograms named
logfire.browser.web_vital.lcp, logfire.browser.web_vital.inp,
logfire.browser.web_vital.cls, logfire.browser.web_vital.fcp, and
logfire.browser.web_vital.ttfb. LCP, INP, FCP, and TTFB use unit ms; CLS
uses unit 1.
Metric data point attributes are intentionally low-cardinality:
web_vital.name and web_vital.rating by default. When soft-navigation
reporting is enabled, they also include web_vital.navigation_type. They do not include
session.id, logfire.page.url.full, logfire.page.url.path,
logfire.page.route, logfire.session.*, Web Vital
ids/deltas, DOM selectors, attribution fields, or raw PerformanceEntry data. Use
spans for raw-sample drilldown, session/replay correlation, exact page context,
and attribution selectors. When metrics are configured, Logfire Platform should
treat these histograms as the aggregate Web Vitals surface.
By default, Web Vitals use the standard document-level measurement method. Web
Vital span URL attributes describe the navigation that produced the measurement,
even when its callback runs after the browser URL changes. The span’s
logfire.page.route is the route of that same navigation. The SDK remembers the
first route that getRouteName returned while each navigation’s URL was
current, and it uses that route for a late report, even after the application
changes its route state or returns to the same URL. If the SDK never observed a
route for that navigation, the span omits logfire.page.route instead of using
the current route. If the browser does not supply a valid navigation URL for a
document report, the span falls back to the current sanitized URL and route.
Chromium 151 and newer can also report metrics separately for browser-detected soft navigations in single-page applications:
logfire.configureFrontend({
...frontendOptions,
rum: {
webVitals: {
reportSoftNavs: true,
},
},
})
This option remains document-level in Firefox, Safari, and older Chromium. A
soft navigation requires a user interaction, URL change, and resulting paint,
so browser detection can differ from application router events. Enabling it
also finalizes the initial navigation when the first soft navigation occurs.
Soft-navigation LCP considers newly painted content, which can differ from a
cold load of the same URL, and soft-navigation TTFB is reported as 0 rather
than as request latency.
Soft-navigation spans use the metric’s sanitized navigation URL. They carry
logfire.page.route when the SDK observed a route for that navigation, and omit
it otherwise. Web Vitals metrics do not carry the route. To add a
low-cardinality route dimension to metrics, derive it from the metric’s
navigationURL in rum.webVitals.metrics.attributes.
Enable rum.longAnimationFrames to detect and diagnose severe main-thread
congestion in supported Chromium browsers:
logfire.configureFrontend({
...frontendOptions,
rum: {
longAnimationFrames: true,
},
})
The Long Animation Frames API observes frames over 50 ms. It is available in Chromium-based browsers, but not in Firefox or Safari at the time of writing. It does not cover all main-thread work and cannot attribute cross-origin frames, workers, or extension isolated worlds. Treat it as a high-coverage sentinel for severe congestion, complementary to INP, request volume, journey timing, and synthetic monitoring.
The feature is off by default. When enabled, the SDK feature-detects
long-animation-frame, samples 10% of browser sessions, and observes with
buffered: true. Sampled-out and unsupported sessions do not install an
observer, timer, or lifecycle listeners.
For sampled sessions, the SDK emits two log-type span shapes:
browser.long_animation_framediagnoses frames whoseblockingDurationis at least 100 ms. Frames are ranked within each foreground window, and the worst frames are emitted up to a fixed cap of 20 per browser session.browser.main_thread_windowsummarizes each foreground window with its real foreground duration, total blocking duration, LoAF count, dropped diagnostic count, and the top three scripts by summed duration. Hidden time is excluded, and a partial window is emitted on document hide orpagehide.
The default ranking and summary window is 60 seconds. You can tune collection without changing the SDK-owned event and script caps:
logfire.configureFrontend({
...frontendOptions,
rum: {
longAnimationFrames: {
blockingDurationThresholdMs: 150,
sessionSampleRate: 0.25,
windowDurationMs: 30_000,
},
},
})
sessionSampleRate is clamped to 0..1. The window has a 10-second minimum to
prevent accidental span floods. HTTP(S) script source URLs have credentials,
query strings, and fragments removed and are capped at 2,048 Unicode code
points. Payload-bearing and per-load URL schemes use stable scheme or origin
placeholders. Function names are capped at 200 Unicode code points. Periodic
window summaries do not extend the browser session idle timeout, but diagnostic
frame spans count as session activity. LoAF data is emitted only as spans, never
as OpenTelemetry metrics. The existing browser session processor adds session
id, route, sanitized page URL, replay state, and service-version context to both
span shapes.
Use compact resource timing to keep the documentLoad, documentFetch, and
per-asset resourceFetch spans while omitting their DNS, connection, TLS,
request, response, and DOM timing events:
logfire.configureFrontend({
...frontendOptions,
resourceTiming: { detail: 'summary' },
})
summary is the default when resourceTiming is configured, so
resourceTiming: {} is equivalent. Use detail: 'full' when you need the
phase events for detailed diagnostics. Full detail increases telemetry volume,
especially on pages with many static assets.
resourceTiming controls only the document-load instrumentation created by
autoInstrumentations; it does not enable auto-instrumentation or override an
explicitly disabled document-load instrumentation. When the raw
@opentelemetry/instrumentation-document-load.ignoreNetworkEvents option is
also present, resourceTiming.detail takes precedence. Other raw document-load
options remain unchanged. Summary mode does not remove firstPaint or
firstContentfulPaint; use the upstream ignorePerformancePaintEvents option
if you also want to omit paint events.