DEV Community

Muhammad Ahmad
Muhammad Ahmad

Posted on Edited on

Turning a Production .HAR Capture into a 7-Phase Latency Audit, Playwright Test, and k6 Load Script

When a web app feels sluggish in production or fails intermittently during a multi-step checkout flow, a browser HTTP Archive (.har) capture contains the ground truth. Yet most developers only open .har files to glance at status codes, missing two massive productivity wins:

  1. Automated 7-Phase Network Bottleneck Diagnostics (distinguishing DNS/TLS handshakes from HTTP/1.1 connection pool starvation and backend TTFB stalls).
  2. Instant Replay Code Generation (converting the exact filtered network sequence into a runnable Playwright E2E test, a k6 load test script, or an OpenAPI 3.1 schema).

Let's look at how the HAR 1.2 timing specification works under the hood and how to transform raw network traces into executable tests.


1. Reading the 7 Timing Phases in entry.timings

Per the HAR 1.2 spec, every network entry records seven timing deltas (in milliseconds, where -1 indicates the phase did not apply, such as ssl on a reused keep-alive socket):

export interface HarTimingPhases {
  blocked: number; // Waiting for an available TCP socket (6-connection browser limit!)
  dns: number;     // Domain Name System lookup time
  connect: number; // TCP 3-way handshake (SYN / SYN-ACK / ACK)
  ssl: number;     // TLS 1.2 / 1.3 handshake negotiation
  send: number;    // Time spent transmitting request headers & body
  wait: number;    // Time to First Byte (TTFB) — server processing + network RTT
  receive: number; // Time spent downloading the response payload
  total: number;
}
Enter fullscreen mode Exit fullscreen mode

When analyzing a waterfall across hundreds of requests, three patterns immediately pinpoint the bottleneck:

  • High blocked (> 100 ms) with connect: -1: The browser is hitting the 6-connections-per-origin limit on HTTP/1.1, or main-thread JavaScript is starving the network queue. Upgrading the origin to HTTP/2 or HTTP/3 (multiplexing over a single connection) eliminates the blocked queue.
  • High wait (TTFB > 500 ms) with low receive: The bottleneck is strictly server-side (database query latency, cold-start serverless execution, or upstream microservice contention).
  • High receive on JSON/JS responses: Check response.headers for Content-Encoding: br or gzip. If response.bodySize equals response.content.size on a 500 KB payload, compression is missing at the CDN edge.

2. Generating Playwright E2E and k6 Load Scripts Directly from Filtered HAR Entries

Instead of manually writing page.request.post(...) or k6 http.batch(...) calls from scratch to reproduce a bug, you can filter a HAR capture down to the XHR/Fetch API calls (resourceType === 'fetch' || resourceType === 'xhr'), sanitize any live credentials into environment variable placeholders ({{BEARER_TOKEN_1}}), and compile the trace directly into test code:

// Auto-generated k6 load script from a sanitized HAR sequence:
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 10,
  duration: '30s',
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.01'],
  },
};

export default function () {
  const params = {
    headers: {
      'Accept': 'application/json',
      'Authorization': __ENV.BEARER_TOKEN_1 || 'Bearer REDACTED',
    },
  };
  const res = http.get('https://api.example.com/v1/orders?limit=25', params);
  check(res, { 'status is 200': (r) => r.status === 200 });
  sleep(1);
}
Enter fullscreen mode Exit fullscreen mode

If you want to inspect 7-phase waterfalls, compare two HAR captures ("Before vs. After Deployment" regression diffing), or export sanitized traces to k6, Playwright, OpenAPI 3.1, Postman v2.1, or cURL/Fetch/Python without uploading your HAR file to any server, you can run the KivaroTools Client-Side HAR Analyzer & Sanitizer locally in your browser.

Top comments (0)