---
title: 'Network Panel Diagnostics'
source: 'https://academia.sh/en/courses/browser-platform/network-panel-diagnostics'
course: 'The Browser and the Web Platform'
language: en
updated: '2026-08-17T18:09:11+00:00'
license: 'CC BY-SA 4.0'
---

# Network Panel Diagnostics

Which cause a request's timing stages point to; the distinction between transferred size and resource size, headers' role in diagnosis, reading a dependency chain in the waterfall, and making a measurement reproducible.

The previous lesson answered why an element looks the way it does, not why its content is
what it is. If the number on the badge is stale, the problem is not in the style: either
the request was never made, it was served from cache, the server returned stale data, or
the response arrived much later than expected.

The Network panel separates these four possibilities. This lesson covers the measures the
panel produces and which cause each measure points to.

## The Questions the Panel Answers

The panel shows a list of requests, and every row carries an answer to four questions.

**Was the request actually made?** A request not in the list was never made. An expected
request never showing up says the code never ran that path, or a condition was not met —
there is no need to look at the server.

**Where was it served from?** Whether it came from the network, the browser's own cache,
or a service worker is marked separately. A cache-served request appears in the list but
never reached the network; this is the most common source of the stale-data problem.

**How long did it take, and where did it wait?** Total time alone is not a diagnosis; its
breakdown into stages is.

**What did it return?** Status code, headers, body. Most wrong-content problems show up
here.

## The Stages of Timing

A request's total time splits into consecutive stages, and each stage taking longer
points to a different cause.

**Queued time** is the time before the request has started at all. The browser limits how
many simultaneous connections it opens to the same host; once that limit fills, new
requests wait. A long queue says something about how many requests the page starts at
once, not about the server.

**Connection setup** consists of name resolution, transport connection, and the secure
handshake. It shows up only on new connections; on a persistent connection it is near
zero. Taking longer points to network distance and certificate verification, not server
load.

**Waiting for first byte** is the time between the request being sent and the first
response byte arriving, including the server's time to produce the response. Taking
longer here moves the diagnosis to the server side; there is nothing to do on the client.

**Downloading the body** is the time from the first byte to the last. Taking longer
relates to size or bandwidth; compression and minification affect this, server speed does
not.

The distinction is measurable. The following server produces two delays separately: a
processing time up to the first byte, then a transfer time for the rest of the body.

```js
// delayed-server.mjs — waits 300 ms until the first byte, then 200 ms for the rest of the body
import { createServer } from "node:http";

const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

createServer(async (request, response) => {
  response.sendDate = false;
  await wait(300);                      // the server's processing time: delays the first byte
  response.writeHead(200, { "Content-Type": "application/json" });
  response.write('{"measurements":[{"temperature":-4.2}');
  await wait(200);                      // the rest of the body: extends the download time
  response.end(',{"temperature":-4.6}]}');
}).listen(8138, "127.0.0.1", () => console.log("listening: 127.0.0.1:8138"));
```

```bash
#!/usr/bin/env bash
# Starts delayed-server.mjs, measures one request's stage timings, then stops it.
node delayed-server.mjs > /dev/null &
server=$!
sleep 1

curl -sS -o /dev/null http://127.0.0.1:8138/measurements.json \
  -w 'name lookup   : %{time_namelookup} s
connect       : %{time_connect} s
first byte    : %{time_starttransfer} s
total         : %{time_total} s
downloaded    : %{size_download} bytes
'

kill "$server"
```

```
name lookup   : 0.000152 s
connect       : 0.000438 s
first byte    : 0.306938 s
total         : 0.508153 s
downloaded    : 60 bytes
```

Times depend on the environment and vary in decimal places from run to run; what does not
change is the structure. Name resolution and connection setup are too short to measure,
since the request went to the loopback address; on a real server, these two values take a
noticeable share of the total. The first-byte time reflects the 300 milliseconds the
server held back. The roughly 200-millisecond gap after it is body download.

The diagnostic rule follows: **the time up to the first byte and the time after it
measure two separate problems**, and a single total number hides both.

## Transferred Size and Resource Size

The panel shows two sizes for a request. **Transferred size** is the bytes that went over
the wire; it includes headers and, if compressed, is the compressed form. **Resource
size** is the content's size once unpacked.

Their ratio says whether compression is working. Equal sizes show compression was not
applied — for a text-type resource, a configuration gap. Transferred size near zero shows
the request was served from cache.

The distinction matters for performance too. Parsing cost is proportional to resource
size, transfer cost to transferred size. Compression lowers the second, not the first: a
large script that compresses well does not tire the network, but it does tire the main
thread.

## Reading Headers

Response headers are the evidence for the previous topic's freshness decision. Why a
resource arrived stale is answered by reading the caching permission and lifetime
headers; if a validator exists, whether a conditional request was made and an
empty-body response came back is visible in the list.

Three more headers come up often. Content type determines how the browser interprets the
response; a wrong type causes a correctly arrived response to be processed incorrectly.
Content encoding says in which form compression was applied. The header declaring which
request header the response varies by keeps the cache from serving the same response to
different users; its absence lets one user's response reach another.

Request headers are read too: whether credentials were sent, whether a conditional
request carried a validator, and which origin made the request.

## Reading a Chain in the Waterfall

The waterfall view shows every request as a bar on a timeline. What is read is not
individual durations, it is the bars' **position relative to each other**.

Bars starting side by side are parallel requests. If one does not start until another
finishes, there is a dependency between them, usually unwanted: a resource discovered
only after a script has downloaded and run can only be requested at that point. The
preload scan from the Resource Loading Order lesson exists to shorten this chain; a
staircase pattern says the scan could not see the resource.

Bars starting together but waiting a long while point to a connection limit. Resources
holding up first render are compared against timeline markers: a request finishing after
first contentful paint did not delay that render.

## An Intervening Layer's Appearance in the List

When a service worker is registered, the list can double. The page's own request produces
one row; if the worker goes to the network to fulfill it, that appears as a second row.
Both rows belong to the same address, and confusing them makes the request count look
doubled.

The distinction is the diagnosis itself. If the page's row marks the request as served
from the worker with no network row beneath it, the response came from cache. If both
rows are present, the worker went to the network; the gap between their durations is its
own processing time. If the page's row appears but the worker never engages, either the
request is out of scope or the page is not yet controlled — the control rule from the
Service Workers lesson becomes observable here.

The worker's own lifecycle leaves a trace in the list too: the update request for the
worker script itself and the requests for resources collected during install show up as
rows the page never asked for.

## Reproducible Measurement

Network measurement cannot be compared until measurement conditions are fixed. Three
conditions need to be stated explicitly.

**Cache state.** A first visit and a repeat visit are two completely different scenarios,
and both are real. Whichever the measurement is for, that state is set up; measuring with
cache disabled describes only the first visit.

**Network condition.** Tools can artificially limit bandwidth and latency. A local
measurement on a development machine never represents a field user's conditions;
throttling is the only client-side way to bring it closer to reality.

**Extensions and background activity.** Installed extensions mix their own requests into
the list and affect timing. Measurement is done in a profile with none.

The recording itself needs preserving too: the list clears on navigation by default, and
the record of a problem that results in navigation is lost with it. Preserving the log is
requested explicitly.

## Summary

- The Network panel separates four questions: was the request made, where was it served
  from, how long did it wait at which stage, what did it return. Stages point to
  different causes: queueing to the page's request count, connection setup to distance,
  first byte to the server, download to size.
- With a service worker registered, the same address can produce two rows; the absence of
  the second row shows the response came from cache.
- The gap between transferred size and resource size measures compression; parsing cost is
  proportional to resource size.
- Headers are the evidence for the freshness decision, content interpretation, and cache
  separation.
- What is read in the waterfall is not durations but the bars' position relative to each
  other; a staircase pattern means a discovery chain.
- A measurement cannot be reproduced without fixing cache state, network condition, and
  browser profile.

## Next Step

The Network panel says when a request finished, not why the page still stays frozen after
the response arrives. If the measurement list downloaded but the screen updates late, the
cause is not the network but work queued on a single thread: parsing, style calculation,
layout, painting, and every intervening script share the same queue. Where it gets stuck
is seen not from the request list but from a breakdown of work over time. The next lesson
covers the recording that produces this breakdown and how to read it.
