Reading a HAR File Like a Flight Recorder

The browser recorded the entire incident, every request, every wait, every byte, before anyone knew there was one.

Share
Reading a HAR File Like a Flight Recorder. Abstract tooling illustration in orange and dark grey on debugly.dev

The complaint arrived as "the page is slow sometimes", which is not a diagnosis, it is a weather report, and the reproduction failed on the first five attempts because nobody had captured the conditions. The sixth attempt began differently: the reporter recorded a HAR before reproducing, and the file contained the entire incident, every request with its timings, every redirect, every byte count, recorded by the browser at the moment it happened, which is the property that makes the HAR the flight recorder of the web: it is written continuously, before the incident is known, so the black box is always already there.

I have lost on-call weeks to this exact shape of slow burn, so the order below is the order I fix it in.

This is how to read it like an investigator, because the HAR's value is not in having it, everyone has it, it is in the readout, and the readout has a structure that names the stall.

This was Chrome 133 exporting HAR from devtools and from a headless recorder, and the reading below is the one that turns a two megabyte JSON into a one paragraph diagnosis.

The waterfall is the primary readout

The HAR's entries carry timing phases per request, queued, DNS, connect, TLS, waiting (TTFB), content download, and laid out in time they form the waterfall, which is the same partition the curl timing template gives for one request, extended to the whole page, per the curl flag that tells you which part of the request was slow. The first read is the shape: which request's bar is long, and which phase of that bar is long, because the phase names the owner. A long TTFB is the server thinking. A long download is payload or bandwidth. A long queue is the browser's connection limit or a blocked main thread. A long connect or TLS is the network or the handshake.

The waterfall also shows the critical path, the chain of requests where each waits on the previous, and the chain's total is the load time, so the investigation follows the longest chain, not the longest single bar, because a fast request late in a long chain is a victim, not a cause.

The five reads that answer the common incidents

The redirect chain. Entries that are 301s and 302s at the head of the chain are pure tax, each a round trip added before any content, and a chain of three redirects is three round trips of nothing, visible instantly as short bars that delay everything behind them.

The serialised waterfalls of third parties. A column of small requests each waiting for the previous script to execute is the third party daisy chain, the shape from the third party script that held the main thread hostage, and the HAR shows it as scripts whose content download is small but whose gap to the next request is large, the gap being main thread time, which the HAR records as the silence between bars.

The cache that missed. Entries carry the cache state and the response headers, so a resource that should be cached and is not, missing cache headers or a varying URL, shows as a full network fetch on a repeat visit, and the repeat visit HAR diffed against the first shows exactly which resources re downloaded, which is the cache audit in one comparison.

The payload that bloated. The size fields give encoded and decoded size per entry, so the entry whose decoded size dwarfs the others is the blob, and the ratio of encoded to decoded shows whether compression is even on, which is the Brotli saved forty percent on text question answered per resource.

The request that waited on the main thread. A request whose queued time is long, sitting in the queue while nothing else happens, is blocked by the main thread, and the long queue with an idle network is the signature of a script holding the thread, separating the network innocent from the renderer guilty.

The diff is the regression tool

Two HARs, before and after a change, or good day and bad day, diffed on the entry timings, name the regression directly: the request whose TTFB grew, the resource that newly appears, the cache entry that started missing. The diff is the performance bisect's evidence, and because the HAR is recorded at the user's moment, it carries the conditions, the network shape, the cookie state, that the lab repro lacks, which is the sampling lesson from measuring TTFB when a CDN is answering for you: the HAR is the user's conditions, preserved.

The hygiene of the black box

The HAR contains everything the browser saw, which includes cookies and authorisation headers, so it is a credential dump, and sharing a HAR is sharing a session, which makes the HAR the same export as the log in the pull request that logged an email address: strip the sensitive headers before it leaves the machine, or record with the sensitive state absent, because the flight recorder's completeness is exactly its danger.

Record with the conditions labelled, throttled network, cold cache, the extension state, because an unlabelled HAR is a fact without its context, and the context is half the diagnosis, as ever.

If it happens again

The browser records the whole incident before anyone knows there is one, so the HAR is the black box, and reading it is reading the waterfall's phases to name the owner, following the critical chain, and diffing two recordings to name the regression.

The slow page that was never recorded is a rumour, and the slow page that was recorded is a fact with a readout, and the difference between the two is one click made before the reproduction, which is the cheapest instrumentation in this archive, and the most neglected.


Published on debugly.dev by Rohit Bhadani | Founder of Krova Cloud