The Browser Telemetry API Reference: 30 Web APIs That Emit Observability Data
30 browser APIs emit observability data. Most devs know maybe half. Here's the complete reference.
Last month I was debugging a P95 latency spike in our checkout flow. Had traces. Had logs. Still couldn't figure out why some users waited 4 seconds while others got 200ms responses.
Turns out the slow users were on Android Chrome with poor network conditions — and I'd never instrumented the Network Information API. The browser knew the connection was garbage. My observability stack didn't.
That sent me down a rabbit hole. How many browser APIs emit observability-relevant data? Thirty. Thirty APIs that browsers expose for free, most of which never make it into your dashboards.
I'd been doing observability for years and only knew maybe half of these. Embarrassing? Sure. But I suspect you're in the same boat.
This is the reference I wish I'd had.
The Master Reference Table
Before we dig into each API, here's the quick-reference table. Bookmark this.
| API | Signal Type | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|---|
| Navigation Timing L2 | Page load timing | ✅ | ✅ | ✅ | ✅ |
| Resource Timing L2 | Asset load timing | ✅ | ✅ | ✅ | ✅ |
| User Timing L3 | Custom marks/measures | ✅ | ✅ | ✅ | ✅ |
| Paint Timing | FCP, LCP | ✅ | ✅ | ✅ | ✅ |
| Layout Instability | CLS | ✅ | ✅ | ✅ | ✅ |
| PerformanceEventTiming | INP, FID | ✅ | ✅ | ✅ 17.2+ | ✅ |
| Long Tasks API | Main thread blocking | ✅ | ❌ | ❌ | ✅ |
| Element Timing | Per-element render | ✅ | ❌ | ❌ | ✅ |
| Server Timing | Backend metrics | ✅ | ✅ | ✅ | ✅ |
| Network Information | Connection quality | ✅ | ❌ | ❌ | ✅ |
| Device Memory | RAM availability | ✅ | ❌ | ❌ | ✅ |
| Error Event | JS exceptions | ✅ | ✅ | ✅ | ✅ |
| Unhandled Rejection | Promise errors | ✅ | ✅ | ✅ | ✅ |
| Reporting API | Deprecations, CSP | ✅ | ❌ | ❌ | ✅ |
| Performance Observer | Unified entry point | ✅ | ✅ | ✅ | ✅ |
(That's the top 15. Full 30 below.)
Page Load & Timing APIs (1-6)
1. Navigation Timing API (Level 2)
The foundation. Every RUM tool starts here.
Navigation Timing gives you the full waterfall for the main document: DNS lookup, TCP connect, TLS handshake, request sent, response received, DOM parsing. Exposed via performance.getEntriesByType('navigation').
Key metrics: responseEnd - requestStart is TTFB. loadEventEnd - navigationStart is classic page load time. Universal browser support since 2017.
2. Resource Timing API (Level 2)
Same waterfall data, but for subresources. Every image, script, stylesheet, font, fetch, and XHR gets a PerformanceResourceTiming entry with initiatorType so you can filter by asset class.
Catch: cross-origin resources only expose timing data if the server sends Timing-Allow-Origin headers. Without it, you get zeroed-out fields.
3. User Timing API (Level 3)
Your custom instrumentation layer. performance.mark('checkout-start') and performance.measure('checkout-duration', 'checkout-start', 'checkout-end') let you track application-specific milestones.
Level 3 added detail metadata: performance.mark('product-view', { detail: { sku: 'ABC123' } }). Chrome and Edge support it; Safari and Firefox are catching up.
4. Paint Timing API
Exposes two entries: first-paint and first-contentful-paint. FCP is the timestamp when the browser renders the first text, image, or canvas — the moment the page stops looking blank.
FCP is a Core Web Vital proxy (Google uses LCP, but FCP matters for perceived speed). If your FCP is over 1.8 seconds, you've lost impatient users. See our Core Web Vitals statistics for 2026 for industry benchmarks.
5. Largest Contentful Paint (LCP)
LCP identifies the largest visible element when it finishes rendering. Could be a hero image, an H1, a video poster — whatever takes up the most viewport real estate.
You collect LCP via PerformanceObserver watching 'largest-contentful-paint' entries. The tricky part: LCP can fire multiple times as larger elements render, so you take the last entry before user input or page hide. The web-vitals library handles this edge case.
Target: under 2.5 seconds. Over 4 seconds and you're in the "poor" bucket per Google's thresholds.
6. Server Timing API
Backend metrics surfaced to the frontend. Your server adds Server-Timing: db;dur=53, cache;dur=2 headers, and those values appear in the PerformanceResourceTiming entry's serverTiming array.
This bridges the frontend-backend gap — timing data travels with the response. Free observability if your framework supports it.
Interaction & Responsiveness APIs (7-12)
7. PerformanceEventTiming (INP)
The API behind Interaction to Next Paint — Google's responsiveness metric that replaced FID in March 2024.
Every discrete input event (click, keydown, pointerdown) gets a PerformanceEventTiming entry with processingStart, processingEnd, and duration. INP is the worst interaction latency (98th percentile for pages with many interactions) over the page session.
Safari added support in 17.2 (December 2023). Firefox landed it in 119. Before that, measuring INP required Chrome-only APIs.
Target: under 200ms. Over 500ms and your page feels sluggish regardless of how fast it loaded.
8. First Input Delay (FID) — Legacy
FID measured the delay between first user input and the browser's ability to begin processing it. It's been replaced by INP as a Core Web Vital, but the data still flows through PerformanceEventTiming.
If you see first-input entries in old monitoring code, that's FID. New implementations should measure INP instead.
9. Long Tasks API
Flags any main-thread task exceeding 50ms. PerformanceObserver watching 'longtask' entries tells you when the main thread was blocked and which iframe or script caused it.
Chromium-only. Firefox and Safari don't implement it — you're blind on 30% of users. Honestly, this drives me nuts. Still worth collecting where available, but the cross-browser fragmentation in performance APIs is a mess. If you're tracking down sluggish interactions, see our guide to finding P99 latency sources.
10. Long Animation Frames API
The evolution of Long Tasks. LoAF captures frames exceeding their budget (16ms for 60fps) with richer attribution: which scripts ran, which callbacks fired. Chrome 123+ only.
11. Task Attribution API
Part of Long Tasks. Tells you whose code caused the blockage: first-party, third-party iframe, specific script URL. This is how you prove to marketing that their tag is causing 300ms delays. (I've had that conversation. It never goes well.)
12. Scheduler API
scheduler.postTask() lets you yield to the browser. Not telemetry exactly, but it affects your telemetry — proper scheduling eliminates long tasks.
Stability & Layout APIs (13-16)
13. Layout Instability API (CLS)
Measures Cumulative Layout Shift. Every time a visible element moves without user input, the browser fires a layout-shift entry. Target: under 0.1.
Gotcha: CLS accumulates over the entire page lifecycle, not just initial load. A modal shifting content 30 seconds in still counts.
14. Element Timing API
Mark specific elements for render timing: <img elementtiming="hero-image">. Fires a PerformanceElementTiming entry when rendered. Chromium-only.
15. Resize Observer (Performance Context)
Not a PerformanceObserver entry type, but fires observability-relevant data: element dimension changes, reflow frequency. Batch and throttle if capturing.
16. Intersection Observer (Performance Context)
Instrumenting viewport entry/exit times answers "how long until users scroll to our CTA?" Not telemetry per se, but timestamps plus intersection data gets you there.
Error & Exception APIs (17-21)
17. window.onerror
The oldest JS error handler. Captures uncaught exceptions with message, source URL, line, column, and error object. Every error tracking tool hooks this.
18. window.onunhandledrejection
Promise-era equivalent. Captures rejected promises without .catch() handlers. Cross-origin errors show up as "Script error." without CORS headers.
19. Error Event (ErrorEvent interface)
Same data as onerror but in event form. For resource loading errors (broken images, failed scripts), listen on capture phase: addEventListener('error', handler, true).
20. SecurityPolicyViolationEvent
Fires on CSP violations. A spike might mean XSS attempts or a third-party script you forgot to allowlist. Security observability.
21. ReportingObserver
Observes deprecation warnings, intervention reports, CSP violations. Deprecation reports are gold — Chrome tells you when APIs will break. Chromium-only.
Network & Connectivity APIs (22-25)
22. Network Information API
navigator.connection exposes connection type, effective bandwidth, RTT, saveData preference. Log connection quality with RUM data to correlate slow experiences with network conditions.
Chromium-only. Safari refuses (privacy concerns). Firefox removed it. I get the privacy argument, but it's frustrating when you're trying to debug why Safari users report slowness and you have zero network context.
23. Device Memory API
navigator.deviceMemory returns approximate RAM (0.25, 0.5, 1, 2, 4, 8 GB). Correlate slow experiences with constrained hardware. Coarse-grained to prevent fingerprinting — same reason Safari refuses Network Information.
24. Performance.memory (Non-Standard)
Chrome-only: performance.memory returns JS heap size. Track memory leaks — if usedJSHeapSize trends up without plateauing, you've got a leak.
25. Navigator.sendBeacon
The transport mechanism. sendBeacon() sends data reliably during page unload when XHR might be cancelled. The difference between "50% sessions have no end time" and "98% complete."
Browser-Level Reporting APIs (26-30)
26. Reporting API (Report-To Header)
Report-To header tells browsers where to send crash reports, deprecation notices, CSP violations. Out-of-band — catches issues when your JS failed to load.
27. NEL (Network Error Logging)
Reports DNS errors, TCP failures, TLS issues, HTTP errors. Catches problems before your JavaScript runs. Configure via NEL response header.
28. Crash Reporting
Browsers report renderer crashes and OOMs. The observability last resort — when the tab is unresponsive, you might still get a crash report.
29. Performance Timeline API
Synchronous access: performance.getEntries(), getEntriesByType(), getEntriesByName(). The older approach before PerformanceObserver.
30. PerformanceObserver
The unified subscription mechanism. Register observers, receive callbacks when entries arrive:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.name, entry.duration);
}
});
observer.observe({ type: 'resource', buffered: true });
Use buffered: true to catch entries that fired before registration. This is how modern RUM works.
Honorable Mentions
Three APIs that almost made the list:
Timing-Allow-Origin — not an API, but the header that unlocks cross-origin Resource Timing data. Without it, CDN and third-party script timings are zeroed out. If you control any servers serving assets, add the header.
PerformanceServerTiming — the entry type for Server-Timing header data. Already covered under Server Timing API, but worth knowing the interface name.
PerformancePaintTiming — the entry type for Paint Timing data (FP, FCP). Same data, just clarifying the interface for those reading MDN docs. If you're building observability tools, check how error tracking and analytics can share session context for richer debugging.
Quick Verdict
If you're instrumenting a new RUM implementation, start with these five:
- Navigation Timing — the baseline page load metrics
- PerformanceObserver — the unified entry point for everything else
- Paint Timing + LCP — Core Web Vitals (visual metrics)
- PerformanceEventTiming — Core Web Vitals (INP/responsiveness)
- window.onerror + onunhandledrejection — error tracking foundation
That covers 80% of what you need. Maybe 85%. Add Long Tasks, Network Information, and Layout Instability as you mature. If you're coming from a fragmented stack, our guide to consolidating five observability tools walks through the migration.
The browser is talking. Your observability stack should be listening. Or — and this is my strong opinion — you're just guessing why users have bad experiences.
Frequently Asked Questions
What browser APIs are used for Real User Monitoring?
RUM relies on Performance Observer for timing data, Navigation Timing for page loads, Resource Timing for assets, Paint Timing for LCP/FCP, and the PerformanceEventTiming API for interaction metrics like INP. Error monitoring uses window.onerror and window.onunhandledrejection for JavaScript exceptions.
How do I measure Core Web Vitals with browser APIs?
LCP comes from PerformanceObserver watching 'largest-contentful-paint' entries. CLS requires observing 'layout-shift' entries and summing shifts without recent input. INP uses 'event' entries from PerformanceEventTiming. The web-vitals library wraps these APIs but you can collect them directly.
Which browser telemetry APIs work in Safari and Firefox?
Navigation Timing, Resource Timing, User Timing, and Paint Timing work across all major browsers. Layout Instability API (CLS) has full support. PerformanceEventTiming (INP) landed in Safari 17.2 and Firefox 119. Reporting API v1 is Chromium-only as of August 2026.
What is the difference between Navigation Timing and Resource Timing?
Navigation Timing tracks the main document load — DNS, TCP, TLS, request, response, DOM parsing. Resource Timing tracks subresources like images, scripts, stylesheets, and fetches. Both use PerformanceResourceTiming but Navigation Timing entries have additional fields like redirectCount and type.
Try JustAnalytics
All-in-one observability in one under-5KB script: cookieless analytics + error tracking + APM + session replay + uptime + structured logs. Replaces GA4 + Sentry + Datadog + Pingdom + LogRocket. Free tier (100K events/mo), Pro $49/month ($39 annual).
Author at JustAnalytics.