Back to blog
SRE & Performance September 8, 2026

Page Load Time vs Response Time: TTFB, First Contentful Paint, and Server Latency

Automate WhatsApp Alerts
Start Free ➔

Page Load Time vs Response Time: TTFB, First Contentful Paint, and Server Latency

Engineering teams frequently conflate Server Response Time with Page Load Time. A backend API returning in 45 ms does not ensure that an end user experiences a fast page load. Conversely, an end user waiting 4.5 seconds for a web page to render may be suffering from render-blocking CSS, synchronous JavaScript execution, or unoptimized web fonts while backend database queries execute in under 10 ms.

Site Reliability Engineers must dissect the complete browser delivery pipeline into discrete failure domains: network transport, server processing (TTFB), DOM construction, and client-side visual rendering (First Contentful Paint and Largest Contentful Paint).

Browser Navigation Initiated
   │
   ├── [ NETWORK DOMAIN ]
   │   ├── 1. DNS Resolution (UDP/DoH) ──► 2. TCP Handshake ──► 3. TLS 1.3 Negotiation
   │
   ├── [ BACKEND / ORIGIN DOMAIN ]
   │   ├── 4. HTTP Request ──► 5. Server Queue ──► 6. DB Execution ──► 7. First Byte Emitted (TTFB)
   │
   ├── [ BROWSER PARSING DOMAIN ]
   │   ├── 8. HTML Stream Transfer ──► 9. Tokenization ──► 10. DOM Construction
   │
   └── [ RENDERING DOMAIN ]
       ├── 11. CSSOM Construction (Render-Blocking CSS) ──► 12. Main-Thread Layout ──► First Contentful Paint (FCP)

1. Defining the Core Latency Metrics

To isolate performance degradation, distinguish between the four fundamental latency metrics:

  • Server Execution Time ($T_{\text{server}}$): The internal duration from when the application worker receives an incoming request socket to when it flushes the response headers (measured by APM / OpenTelemetry).
  • Time to First Byte (TTFB): The total elapsed time from when the client initiates navigation until the browser receives the very first byte of the HTTP response header from the edge or origin.
  • First Contentful Paint (FCP): The browser-level timestamp when the layout engine paints the first piece of meaningful DOM content (text, image, SVG, or canvas).
  • Page Load Time ($T_{\text{load}}$): The timestamp when the window.onload event fires, indicating that all dependent sub-resources (images, iframes, stylesheets) have finished downloading.
Backend Metric:    [ Server Execution Time: 35ms ]
Edge Metric:       [ Time to First Byte (TTFB): 180ms ] (Includes DNS + TCP + TLS + Network)
User Visual Metric:[ First Contentful Paint (FCP): 1,450ms ] (Includes HTML parse + CSSOM + Fonts)
Full Page Metric:  [ Total Page Load: 3,200ms ] (Includes all async scripts + background images)

2. Deconstructing the TTFB Equation

Time to First Byte is not a standalone server metric; it is an aggregation of network protocol handshakes, edge routing, and backend queueing:

$$ TTFB \approx T_{\text{DNS}} + T_{\text{connect}} + T_{\text{TLS}} + T_{\text{request}} + T_{\text{queue}} + T_{\text{app}} + T_{\text{DB}} + T_{\text{transit}} $$

Cold Mobile Connection Decomposition (High-Latency Cell Link):
• DNS Resolution (Cold):         65 ms
• TCP Connect (1 RTT):           80 ms
• TLS 1.3 Negotiation (1 RTT):   80 ms
• Request Transmission:          15 ms
• Origin Worker Queue Wait:      45 ms
• PostgreSQL Query & SSR:        95 ms
• Network Transit to Edge:       20 ms
─────────────────────────────────────────────────────────────
Total Client-Observed TTFB =    400 ms (Even though DB query was only 95 ms!)

Exposing Backend Spans via Server-Timing Headers

Emit detailed backend execution stages directly into HTTP response headers so browser DevTools and RUM SDKs can attribute delays without logging into APM dashboards:

HTTP/2 200
content-type: text/html; charset=utf-8
cache-control: public, max-age=0, s-maxage=300
server-timing: cdn;desc="HIT", db;dur=14.2, redis;dur=2.1, ssr;dur=38.5, total;dur=54.8

Testing your live server response headers and TTFB breakdown? Inspect your endpoints using our HTTP Header Checker.


3. First Contentful Paint: The Browser Rendering Pipeline

A fast TTFB of 120 ms can still produce a sluggish FCP of 3,800 ms if the frontend critical rendering path is blocked by client-side assets.

HTML Received (120ms TTFB)
   │
   ├── Browser Discovers: <link rel="stylesheet" href="/styles/global.css"> (180 KB)
   │      └── HTML Parser PAUSES until CSS is fully downloaded and parsed into CSSOM!
   │
   ├── Browser Discovers: <script src="/vendor/bundle.js"></script> (Synchronous 1.4 MB)
   │      └── JavaScript Parser BLOCKS DOM construction and executes on Main Thread!
   │
   ├── Browser Discovers: <link rel="stylesheet" href="https://fonts.googleapis.com/css2...">
   │      └── Web Font Flash of Invisible Text (FOIT) blocks text rendering!
   │
   ▼
First Contentful Paint (FCP) Delayed to 3,800 ms!

Root Causes of Slow FCP Despite Fast TTFB:

  1. Synchronous Render-Blocking Scripts: <script> tags without defer or async attributes halt DOM tokenization while downloading and executing.
  2. Un-inlined Critical CSS: Large global CSS bundles delay CSSOM generation. Inlining above-the-fold critical CSS allows the browser to paint immediately upon receiving HTML.
  3. Web Font Layout Shifts & Blocking: Custom web fonts lacking font-display: swap hide text content until external .woff2 files complete transfer.

4. SRE Comparison: Failure Domains Across the Stack

Performance MetricPrimary Measurement LayerArchitectural Failure DomainTypical Root CauseSRE Remediation Action
DNS LatencyClient $\rightarrow$ ResolverNetwork / DNS InfrastructureStale resolver cache / missing AnycastEnable Anycast DNS & increase TTL
TCP / TLS HandshakeClient $\rightarrow$ Edge PoPTransport & Security LayerHigh RTT / un-resumed TLS sessionsDeploy TLS 1.3 & 0-RTT session resumption
Time to First Byte (TTFB)Client $\rightarrow$ Origin First ByteEdge Cache / Backend WorkersUncached HTML / DB lock contentionDeploy CDN edge caching & tune DB pools
Server LatencyIngress $\rightarrow$ Response OutputBackend Application TierSlow SQL queries / synchronous fan-outOptimize SQL queries & add Redis cache
First Contentful Paint (FCP)Browser Layout EngineFrontend Critical PathRender-blocking CSS / sync JSInline critical CSS & defer non-critical JS
Largest Contentful Paint (LCP)Browser Hero RenderingAsset Delivery & DOM SizeUncompressed hero images / client hydrationServe responsive AVIF/WebP with fetchpriority="high"

Need to model how latency improvements translate into customer SLA uptime? Use our interactive SLA Calculator to compute error budgets and allowable latency degradation.


5. Command-Line Latency Dissection with cURL

Measure every discrete phase of network connection and server response time from the terminal:

# Execute stage-by-stage latency analysis
curl -sS -o /dev/null \
  -w '\n============================================\n' \
  -w ' DNS Lookup Time:        %{time_namelookup}s\n' \
  -w ' TCP Handshake Time:     %{time_connect}s\n' \
  -w ' TLS Handshake Time:     %{time_appconnect}s\n' \
  -w ' Pre-Transfer Time:      %{time_pretransfer}s\n' \
  -w ' Start Transfer (TTFB):   %{time_starttransfer}s\n' \
  -w ' Total Duration:         %{time_total}s\n' \
  -w ' HTTP Status Code:       %{http_code}\n' \
  -w ' Transferred Bytes:      %{size_download} bytes\n' \
  -w '============================================\n' \
  https://example.com/

6. Client-Side Telemetry: Capturing Real User Timings

Capture both backend TTFB and browser FCP directly in production using standard W3C APIs:

// Telemetry Hook: Measuring TTFB vs FCP in Browser Sessions
if (typeof window !== "undefined" && "PerformanceObserver" in window) {
  // 1. Capture Network and Server TTFB
  const navEntry = performance.getEntriesByType("navigation")[0] as PerformanceNavigationTiming;
  if (navEntry) {
    const networkMetrics = {
      dnsTime: Math.round(navEntry.domainLookupEnd - navEntry.domainLookupStart),
      tcpTime: Math.round(navEntry.connectEnd - navEntry.connectStart),
      tlsTime: navEntry.secureConnectionStart ? Math.round(navEntry.connectEnd - navEntry.secureConnectionStart) : 0,
      ttfb: Math.round(navEntry.responseStart - navEntry.requestStart),
      totalDownloadTime: Math.round(navEntry.responseEnd - navEntry.responseStart),
    };
    navigator.sendBeacon("/api/analytics/track", JSON.stringify({ event: "network_ttfb", metrics: networkMetrics }));
  }

  // 2. Capture Visual Paint Timing (FCP)
  const paintObserver = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (entry.name === "first-contentful-paint") {
        navigator.sendBeacon("/api/analytics/track", JSON.stringify({
          event: "visual_fcp",
          fcpMs: Math.round(entry.startTime),
          url: window.location.pathname
        }));
      }
    }
  });

  paintObserver.observe({ type: "paint", buffered: true });
}

7. SRE Operational Latency Threshold Matrix

Operational SignalHealthy BaselineWarning SignalCritical (Page On-Call)Primary Investigation Layer
Origin TTFB ($p50$)$< 150\text{ ms}$$200 - 400\text{ ms}$$> 600\text{ ms}$Backend Worker Queue / DB Latency
Origin TTFB ($p95$)$< 350\text{ ms}$$500 - 800\text{ ms}$$> 1200\text{ ms}$Database Lock Contention / Tail Saturation
First Contentful Paint ($p75$)$< 1.5\text{ s}$$1.8 - 3.0\text{ s}$$> 3.5\text{ s}$Render-Blocking CSS / Large JS Bundles
DNS Resolution ($p95$)$< 25\text{ ms}$$50 - 120\text{ ms}$$> 180\text{ ms}$Nameserver Anycast Routing / Stale TTL
TLS Negotiation ($p95$)$< 60\text{ ms}$$100 - 200\text{ ms}$$> 250\text{ ms}$TLS 1.2 Handshake / Missing Session Tickets
Edge Cache Hit Ratio$> 94%$$85% - 92%$$< 80%$Cache Key Fragmentation / Missing s-maxage

8. Troubleshooting Runbook: Diagnosing Latency Regressions

When page performance degrades, follow this ten-step diagnostic workflow:

  1. Compare client-side FCP and TTFB metrics across affected URLs to determine whether delay originates in the browser or the network.
  2. Execute curl -sS -w ... against both the public CDN URL and the direct origin load balancer IP to isolate edge versus origin delays.
  3. Inspect Server-Timing headers to identify which backend subsystem (SQL query, Redis cache, template rendering) consumed the largest duration.
  4. Audit open database connections using pg_stat_activity to detect query lock contention or connection pool starvation.
  5. Analyze Chrome DevTools Network Waterfall for render-blocking stylesheets or synchronous <script> tags loaded in <head>.
  6. Verify whether custom web fonts are utilizing font-display: swap to prevent text layout blocking.
  7. Check whether recent deployments bundled unminified JavaScript or failed to execute Brotli/Gzip static compression.
  8. Inspect container CPU throttling metrics in Kubernetes (container_cpu_cfs_throttled_seconds_total) during peak traffic.
  9. Test SSL/TLS session resumption and ALPN negotiation using openssl s_client -connect example.com:443 -servername example.com.
  10. Calculate error budget consumption using the Downtime Calculator.

9. Engineering Implementation Checklist

  • Stream Dynamic HTML: Enable chunked transfer encoding so browsers receive the <head> early to start downloading CSS while the server renders dynamic markup.
  • Inline Critical CSS: Extract and inline above-the-fold styling directly into <style> tags to achieve sub-second FCP.
  • Defer Non-Critical JavaScript: Add defer or type="module" to all non-essential script tags.
  • Adopt font-display: swap: Prevent invisible text flashes during web font downloads.
  • Expose Server-Timing Headers: Emit backend database and rendering spans in response headers for instant browser visibility.
  • Configure CDN Edge Caching: Cache semi-dynamic HTML using s-maxage and stale-while-revalidate.
  • Deploy TLS 1.3 & Session Tickets: Minimize handshake round trips for returning mobile visitors.
  • Track Percentile Latency ($p50$, $p95$, $p99$): Deprecate average response time reporting and alert on tail latency degradation.

Related Performance & Conversion Guides

To optimize web application response times and user experience:

Zero-Code Uptime Alerts

Stop Finding Out About Outages from Angry Users

Get instant WhatsApp & Discord alerts the second your API, website, or server goes down. Setup in 30 seconds with 60-second checks.

WhatsApp & Discord 60-Second Checks Free Forever Plan
Try Pingzo Free

Know before your users do

Connect official WhatsApp notification channels, Discord webhooks, Telegram bots, and public status pages. Start in 30 seconds.

Create Free Monitor