The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Detect observable typesconst types = PerformanceObserver.supportedEntryTypesView examples
Observe buffered entriesobserver.observe({ type: 'largest-contentful-paint', buffered: true })View examples
Drain queued recordsconst pending = observer.takeRecords()View examples
Stop observationobserver.disconnect()View examples
Read navigation timingconst [nav] = performance.getEntriesByType('navigation')View examples
Compute response waitconst ttfb = nav.responseStart - nav.requestStartView examples
Read resource timingsconst resources = performance.getEntriesByType('resource')View examples
Expose cross-origin detailTiming-Allow-Origin: https://app.exampleView examples
Clear the resource bufferperformance.clearResourceTimings()View examples
Mark a workflow pointperformance.mark('checkout:start')View examples
Measure between marksperformance.measure('checkout', 'checkout:start', 'checkout:end')View examples
Clear application marksperformance.clearMarks('checkout:start')View examples
Read first contentful paintperformance.getEntriesByName('first-contentful-paint', 'paint')[0]View examples
Observe long interactionsobserver.observe({ type: 'event', buffered: true, durationThreshold: 40 })View examples
Bound telemetry payloadsnavigator.sendBeacon('/rum', new Blob([payload], { type: 'application/json' }))View examples

The Performance Timeline records high-resolution entries for navigation, resources, application marks, rendering, and selected user interactions. PerformanceObserver delivers supported entry types without polling. Measure real user journeys with a bounded schema, observe buffered entries where defined, avoid deprecated timing interfaces, and treat URLs and fine-grained timestamps as potentially sensitive telemetry.

Step by step

Detailed examples

01

Register narrowly scoped observers and drain them on teardown

PerformanceObserver callbacks receive batches asynchronously. Check supportedEntryTypes because entry support differs by browser and global. The type form accepts buffered but observes one type; entryTypes observes several types but cannot be combined with type, buffered, or durationThreshold. Subscribe only to useful types, process records quickly, use takeRecords() before disconnect when final queued data matters, and cap in-memory aggregation.

Observe supported types with independent options
const observers = [];
function observe(type, callback, options = {}) {
  if (!PerformanceObserver.supportedEntryTypes.includes(type)) return;
  const observer = new PerformanceObserver(list => callback(list.getEntries()));
  observer.observe({ type, ...options });
  observers.push(observer);
}
observe('longtask', reportLongTasks, { buffered: true });
addEventListener('pagehide', () => observers.forEach(observer => observer.disconnect()), { once: true });
Back to quick reference ↑
02

Use Navigation Timing Level 2 and monotonic durations

PerformanceNavigationTiming replaces the deprecated performance.timing object. Its timestamps share timeOrigin and use a monotonic clock, making subtraction safe from wall-clock changes. Different intervals answer different questions: responseStart minus requestStart approximates server/network wait; domContentLoadedEventEnd and loadEventEnd include page processing. Zero can mean an event has not occurred or detail is unavailable. Redirect and cross-origin attributes are privacy-filtered.

Derive named navigation intervals
const [nav] = performance.getEntriesByType('navigation');
const metrics = nav ? {
  dns: nav.domainLookupEnd - nav.domainLookupStart,
  connect: nav.connectEnd - nav.connectStart,
  ttfb: nav.responseStart - nav.requestStart,
  domReady: nav.domContentLoadedEventEnd - nav.startTime,
} : null;
Back to quick reference ↑
03

Interpret resource timing with cross-origin restrictions

PerformanceResourceTiming covers fetched resources, including initiator type, protocol, transfer sizes, and fetch phases. For most cross-origin resources, detailed timestamps and sizes are zero unless the response opts in with Timing-Allow-Origin; CORS alone does not expose timing. Cached responses complicate transferSize interpretation. The resource buffer is finite, so observe entries or handle resourcetimingbufferfull, resize deliberately, then clear records in long-lived applications.

Summarize same-origin or opted-in resources
const rows = performance.getEntriesByType('resource').map(entry => ({
  url: new URL(entry.name).pathname,
  kind: entry.initiatorType,
  duration: Math.round(entry.duration),
  transferred: entry.transferSize,
  protocol: entry.nextHopProtocol,
}));
performance.clearResourceTimings();
Back to quick reference ↑
04

Instrument user journeys with bounded names and details

performance.mark() and measure() create PerformanceMark and PerformanceMeasure entries that observers can consume. Use a controlled vocabulary rather than embedding account IDs, search strings, or arbitrary URLs in names. Modern mark and measure options can specify startTime, detail, start, end, or duration, but feature support should be checked. Clear marks and measures after reporting; these APIs measure client spans and do not replace server tracing.

Measure an asynchronous workflow
async function measuredCheckout() {
  performance.mark('checkout:start');
  try { return await submitCheckout(); }
  finally {
    performance.mark('checkout:end');
    performance.measure('checkout', 'checkout:start', 'checkout:end');
    performance.clearMarks('checkout:start');
    performance.clearMarks('checkout:end');
  }
}
Back to quick reference ↑
05

Observe rendering and responsiveness with metric-specific rules

Paint Timing exposes first-paint and first-contentful-paint. Largest Contentful Paint entries are reported as candidates until user interaction or page hiding; layout-shift entries must be grouped into session windows and shifts with recent input excluded for CLS. Event Timing and Long Animation Frames support responsiveness diagnosis but differ in availability and semantics. Do not invent Core Web Vitals calculations from one raw entry—use the published algorithms or a maintained library and test back-forward cache restores.

Collect the latest LCP candidate
let lcp;
if (PerformanceObserver.supportedEntryTypes.includes('largest-contentful-paint')) {
  const observer = new PerformanceObserver(list => {
    lcp = list.getEntries().at(-1) ?? lcp;
  });
  observer.observe({ type: 'largest-contentful-paint', buffered: true });
  addEventListener('pagehide', () => {
    lcp = observer.takeRecords().at(-1) ?? lcp;
    observer.disconnect();
    reportLcp(lcp);
  }, { once: true });
}
Back to quick reference ↑
06

Minimize telemetry and preserve measurement context

Timing precision, resource URLs, element identifiers, and interaction targets may reveal browsing behavior or personal data. Strip query strings, use allowlisted metric names, sample, aggregate, and apply retention controls. Cross-origin isolation can increase timer precision and therefore risk. Use sendBeacon() or keepalive fetch only for a small final payload, never assume delivery, and do not block unloading. Include navigation type, visibility, device class, and version only when needed to interpret results.

Send a small privacy-bounded payload
function report(metrics) {
  const payload = JSON.stringify({
    page: location.pathname,
    build: APP_BUILD,
    metrics: Object.fromEntries(Object.entries(metrics).filter(([, value]) => Number.isFinite(value))),
  });
  if (payload.length < 32000) navigator.sendBeacon('/rum', new Blob([payload], { type: 'application/json' }));
}
Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. World Wide Web ConsortiumPerformance Timelinew3.org
  2. World Wide Web ConsortiumNavigation Timing Level 2w3.org
  3. World Wide Web ConsortiumResource Timingw3.org
  4. World Wide Web ConsortiumUser Timing Level 3w3.org
  5. World Wide Web ConsortiumPaint Timing Level 1w3.org
  6. World Wide Web ConsortiumEvent Timingw3.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback