Chrome’s network panel has a number of helpful visualizations for understanding network request/response performance. In this post, I’ll break down the request lifecycle waterfall, and show you how to pipe backend tracing information into the network panel.

By default, Chrome breaks down the life of a request into 8 parts:

Queueing and Stalled show the time a requests needs to wait before being acted on by the browser. There are a few reasons that a request could be delayed at this stage. Browsers will sometimes prioritize loading resources like scripts, and CSS, before loading other resources. Also, there is a maximum of 6 concurrent TCP connections allowed for HTTP 1 requests.

DNS Lookup , Initial Connection and SSL are fairly self-explanatory- showing the time spent in these respective parts of the request lifecycle.

Request sent is the amount of time it takes the browser to transmit the request to the server. This step is generally very quick, since it represents only the amount of time it takes the browser to dispatch the request.

Waiting (Time to first bite) shows the amount of time the browser needs to wait to start receiving data from the server after making an initial request. During this time, the server does whatever work is required to return the requested resource. In a typical API request, this is where the majority of latency occurs, and is usually the step that developers have the most control over optimizing. With this in mind, it can be helpful to display more granular data on what’s going on “inside” the server, which I’ll explain shortly.

Finally, Content Download is the amount of time it takes to receive the entire stream of bites from the server, after receiving the “first bite”. Latency here is mostly dependent on network connection speed, but obviously optimizing for smaller resources will reduce time in this step.

Sending backend timings

What goes on in the Waiting (TTFB) step can be a bit of a mystery, since a server could do any number of things when responding to a request. Chrome has an API for sending custom timings from the server using the Server-Timing header:

In this basic node/express server, you can see the format of the timing header, which I set for the / request. Here, I hardcoded some example values, but these would normally be filled in programatically.

Then, when I hit the / route, the timings show up in the Chrome network panel.

It is easy enough to build up the Server-Timing header manually, but there are also some nice helper libraries like server-timing (on NPM) that have a cleaner API for doing this.

Sending Server-Timing headers is useful when you visit your app and notice latency in QA, since you can understand if a particular action on the server was slow. However, this API is particularly useful if you’re using a frontend logging service like LogRocket, that records all network requests and their headers. Then, if you’re investigating a network request that hung or was extremely slow, you can see the backend timings and figure out what went wrong.

Keep in mind, however, that any timing information you expose is publicly visible so if you exposed the duration of a step like validate-password , it could theoretically help a hacker use a timing attack.

Bonus: Working with resource timings programmatically

Calling performance.getEntriesByType('resource') returns a list of resources and their respective timings. This is useful for analyzing timings in the JavaScript console, or to grab programmatically in your app and send to an analytics store.

Further resources

LogRocket: Full visibility into your web apps LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps. Try it for free.