LCP

Largest Contentful Paint

Time for the largest visible image or text block to fully render in the viewport

≤ 2.5s
≤ 4s
> 4s
Good Needs improvement Poor
Common causes
  • Slow server response time (high TTFB)
  • Render-blocking JavaScript or CSS
  • Large, unoptimised hero images or fonts
  • Client-side rendering delaying visible content
Diagnostic snippet
new PerformanceObserver((list) => {
  const lcp = list.getEntries().at(-1);
  console.log('LCP',
    (lcp.startTime / 1000).toFixed(2) + 's',
    lcp.element);
}).observe({ type: 'largest-contentful-paint', buffered: true });
INP

Interaction to Next Paint

Worst-case latency of all clicks, taps, and keypresses throughout the page lifetime

≤ 200ms
≤ 500ms
> 500ms
Good Needs improvement Poor
Common causes
  • Long JavaScript tasks blocking the main thread
  • Heavy synchronous work inside event handlers
  • Large DOM causing slow style recalculation
  • Forced reflows during interaction (reading layout then writing)
Diagnostic snippet
new PerformanceObserver((list) => {
  list.getEntries().forEach((e) => {
    if (e.duration > 200)
      console.warn('Slow interaction',
        e.name, e.duration.toFixed(0) + 'ms');
  });
}).observe({ type: 'event', buffered: true, durationThreshold: 16 });
CLS

Cumulative Layout Shift

Total visual instability score — how much content unexpectedly moves during load

≤ 0.1
≤ 0.25
> 0.25
Good Needs improvement Poor
Common causes
  • Images or videos without explicit width/height attributes
  • Ads or embeds injected above existing content
  • Web fonts causing flash of unstyled text (FOUT)
  • Animations using top/left instead of transform
Diagnostic snippet
let cls = 0;
new PerformanceObserver((list) => {
  list.getEntries().forEach((e) => {
    if (!e.hadRecentInput) cls += e.value;
  });
  console.log('CLS', cls.toFixed(4));
}).observe({ type: 'layout-shift', buffered: true });
TTFB

Time to First Byte

Time from request start until the first byte of the HTML response arrives

≤ 800ms
≤ 1800ms
> 1800ms
Good Needs improvement Poor
Common causes
  • Slow DNS resolution or TLS negotiation overhead
  • Unoptimised server-side processing or database queries
  • Geographic distance without a CDN
  • Shared hosting resource contention
Diagnostic snippet
const [nav] = performance.getEntriesByType('navigation');
const ttfb = nav.responseStart - nav.requestStart;
console.log('TTFB', ttfb.toFixed(0) + 'ms');