Skip to content

Anatomy of a Check

For every check processed by latency a timeline of segments (spans of time) are recorded: each segment has a name, a start offset, and a duration. Those segments are what you chart, alert on, and drill into to diagnose issues.

We say timeline and not "waterfall" on purpose. A basic http 1.1 request where one phase starting exactly where the last ended, is only the simple case. Real requests overlap and skip phases (see What is TTFB and conditions that bend the timeline).

What a check recordsdomainLookupStartconnectStartsecureConnectionStartconnectEnd / requestStart*responseStart**responseEndRedirectif 3xxDNSTCPTLSQUIC (HTTP/3)Requestsent → first byte103Early HintsResponseProcessing · Loadbrowser only, not measureddns_usconnect_ustls_usserver_ustransfer_usttfb_usdns + connect + tls + wait, up to the first bytetotal_us* requestStart can precede connectEnd: with TCP Fast Open or TLS 1.3 0-RTT the request rides the handshake.** responseStart is the first byte: an Early Hints 103 if the server sends one, otherwise the final response headers.Dashed phases are conditional. On HTTP/3 the TCP and TLS boxes fuse into one QUIC handshake.

The headline number

An http check defaults to ttfb_us — time to the first response byte (DNS + connect + TLS + wait). total_us adds the body transfer. Both roll up the segment timeline, stored in microseconds. Each check has its own total, see the primary metric.

The phases

dns — resolve the name. Trade api.acme.io for an IP: one round trip if the answer is cached upstream, several if the resolver walks root → TLD → authoritative. dns_us covers the whole detour, CNAMEs included; it is 0 for an IP literal.

tcpConnect — open the socket. SYN, SYN-ACK, ACK. One round trip and no work, so connect_us is your cleanest read on raw network distance — a probe in Frankfurt hitting Virginia pays ~90ms here no matter how fast the server is.

tls — prove identity, agree on keys. ClientHello → certificate → Finished. A slow tls_us is almost always a fat certificate chain or a cold connection with no session resumption. Plain http skips it; HTTP/3 fuses it (see below).

wait — the server thinks. The request is on the wire, then silence while the backend routes, queries and renders. server_us is "request sent → first byte" — the place backend slowness hides.

response — the body arrives. transfer_us is how long the bytes take to land, a function of payload size and bandwidth, not the server's brain.

TTFB is a roll-up, not a segment

ttfb_us = dns + connect + tls + wait — the whole stretch to the first byte, the honest "how long until the server started answering." To find why it is slow, read the leaves underneath. When a check hangs, the segment it died in is marked failed or timeout, so the timeline points straight at the break.

The primary metric

Every monitor has a total latency — the whole time to a useful response.

CheckPrimary (default)The total is
httpLatency (TTFB) = ttfb_usDNS + connect + TLS + wait (total excluding transfer).
tcpLatency (total) = latency_usDNS + the TCP connect handshake.
tlsLatency (total) = latency_usDNS + the connect and TLS handshake.
icmp / udpLatency (total) = latency_usDNS + the echo / datagram round trip.
dnsLatency (total) = latency_usThe resolution itself.

Swap it for any phase (make server_us the headline for a backend-bound API), and alert on any of them — including deviations (deviates_pct)

Conditions that bend the timeline

The serial picture above is one case. Real requests take shortcuts and detours — the reason every segment carries an explicit start and duration instead of chaining off the previous one. In terms of the Resource Timing model:

  • Redirects. Each 3xx is a full extra round trip with its own DNS, connect, TLS and wait. We follow them and sum every phase across the chain (dns_us is the whole chain, not just the final URL), nested under a redirect segment per hop. Point the monitor at the final URL to skip them.
  • HTTP/3 (QUIC). Transport and crypto are a single handshake over UDP, so you get one quicHandshake segment instead of tcpConnect + tls. (Beta.)
  • A warm / reused connection. DNS, TCP and TLS happened on an earlier request, so those segments are simply absent and wait is the whole story — zeros mean "reused," not "instant." (Our probe opens a fresh connection each check, so you'll always see them; browsers and keep-alive clients won't.)
  • Happy Eyeballs (RFC 8305). A and AAAA resolve in parallel and IPv4/IPv6 connects race, so several tcpConnect segments run at once — the winner is ok, the losers cancelled.
  • TCP Fast Open / TLS 1.3 0-RTT. The request rides the first flight, so request overlaps the handshake — it starts before TLS finishes.
  • Early Hints (103). The server may send an interim 103 before the real response, so the "first byte" that ends wait can be that hint, not the final headers.
  • Cache & service workers. In a browser, an HTTP cache or service worker can short-circuit the network entirely. An availability probe deliberately doesn't cache — every check measures the real path. (The browser-only Processing and Load phases in the reference diagram don't apply to a server-side check.)
  • Multiplexing (HTTP/2 & /3). Many requests share one connection, so their response spans interleave on the wire.

So the strict dns + connect + tls + wait = ttfb identity only holds for the clean serial case. What is always true is interval math:

ttfb_us is the wall-clock envelope from the first activity to the first response byte. Each phase metric is the sum of its segments' durations — and because segments can overlap, they can sum to more than the envelope, equal only in the serial case.

Types of metrics

MetricKindThe question it answers
latency_usroll-up (default primary)The kind's total — its "now" number.
ttfb_usroll-up (http default)End to end up to the first byte.
total_usroll-upEnd to end, transfer included.
dns_ussegmentIs name resolution the bottleneck?
connect_ussegmentHow far away is the server, really?
tls_ussegmentIs the certificate / crypto exchange slow?
server_ussegmentIs the backend slow (pure think time)?
transfer_ussegmentIs the payload / bandwidth the cost?
rtt_ussegmentHow long is the echo / datagram round trip?

Any of these can be a monitor's primary or the subject of an alert rule.

The segments

Each check stores its timeline as a small array of segments:

FieldMeaning
indexits position in the array (its identity within the check)
parentIndexthe segment that contains it, or -1 for a top-level phase
kinddns, tcpConnect, tls, quicHandshake, request, wait, response, redirect
startUsoffset from the start of the check, in microseconds
durationUshow long it took, in microseconds
statusok, failed, timeout, or cancelled (a raced-but-lost attempt)

Nesting via parentIndex carries the structure: a redirect chain is one redirect parent per hop, with that hop's own dns/connect/tls/wait segments beneath it.

Why microseconds

latency is unlike other monitors, every timing is stored and computed as an integer number of microseconds (µs). Here's the difference in units:

UnitSymbolIn one second
seconds1
millisecondms1,000
microsecondµs1,000,000

A millisecond is one thousandth of a second, the human friendly unit for latency (aka "180 ms"). A microsecond is one thousandth of a millisecond, a millionth of a second. So 1 ms = 1,000 µs, and a 10-second timeout is 10,000,000 µs.

Probes measure with a high-resolution clock, which returns fractional milliseconds, sub-millisecond precision. Real phases live down there: a warm DNS answer is around 300 µs (0.3 ms), a local TCP connect can be around 40 µs. Round those to whole milliseconds and they collapse to 0, and the breakdown that makes these metrics useful is lost.

So Latency picks µs as its canonical unit and refuses to convert early:

  • Capture — the probe's fractional-ms measurement is turned into an integer µs once, at the moment it is recorded.
  • Storage — ClickHouse holds each phase (and each segment's start and duration) as a UInt32 of µs. Integer, compact, exact.
  • Rules and the wire — the alerting engine compares in µs and the API serves the same. No floating-point drift to creep in.
  • Display — the only place µs becomes ms or s is the screen and you can always expand for detail.
© 2026 Latency Labs LLC