What does URLSessionTaskMetrics tell you about a request, and how do you use it to find where time goes?
Mental model. The metrics are the receipt for a delivery: when the order was placed, when the van left, when it arrived and when it was unpacked. The slow step is the line with the big number.
After a task finishes the session delegate (or URLSessionTaskDelegate’s urlSession(_:task:didFinishCollecting:)) receives URLSessionTaskMetrics: the total task interval, the number of redirects, and a list of URLSessionTaskTransactionMetrics, one per transaction (a redirect or retry adds more). Each transaction has timestamps for fetch start, domain lookup, connect, secure connection (TLS), request start and end, response start and end, plus networkProtocolName (h2, h3, http/1.1), isReusedConnection, isProxyConnection, whether it came from the cache, and byte counts. Subtract adjacent timestamps to get phases: DNS, TCP connect, TLS handshake, time to first byte (request end to response start) and download time.
Reading them: a large domain lookup points at DNS; a large connect + secure connection with isReusedConnection == false means each request pays for a new connection (use a shared session, HTTP/2 or 3, and keep-alive); a large TTFB is server time (compare with server logs); a large download phase on small payloads is bandwidth or loss; many redirects add whole round trips. Aggregate by endpoint, protocol and network type and look at percentiles (p50, p95), not means. Keep the overhead small (collect, sample and batch), do not collect on the main thread, and remember metrics may be unavailable for some tasks (for example responses served by a custom URLProtocol, as in tests). Pair them with os_signpost in Instruments for the app-side parts of a user-visible “time to content”.
Common traps
- Looking at average latency. Tail latency (p95, p99) is what users complain about.
- Assuming a slow request means a slow server. DNS, TLS and a lost connection reuse are often the cause.
They might follow up with
- How do I know HTTP/3 was used?
networkProtocolNamein the transaction metrics (h3). - Can I get metrics for
data(for:)async calls? Use a per-task delegate or a session delegate that implementsdidFinishCollecting.
Related questions
- 12.10.3 A request fails or is slow only for some users. How do you diagnose it: what do you log, what tools do you…
- 12.10.2 When do you still need a URLSession delegate, and how do the async APIs and per-task delegates fit?
- 12.2.1 How do HTTP/1.1, HTTP/2 and HTTP/3 differ, and what does that mean for an iOS client?
- 12.7.1 How do you design an image loading pipeline: decoding, downsampling, caching and de-duplication?
← A request fails or is slow only for some users. How do you diagnose…