VisualEther Case Study · Web Performance

HTTP/3 + QUIC·Page Load Latency

Cross-layer triage of a mixed HTTP/3, HTTP/2 and TLS 1.3 capture — pinning page-load delay to DNS, profiling the HTTP version mix, and ranking destinations by volume.

Pcap: traffic.pcapng
01UserInitial request

Identify the sources of page load latency in traffic.pcapng. Also, check whether TCP or QUIC retransmissions are slowing page load.

02ClaudeCross-layer page-load analysis

Capture: 12,266 packets, ~42 s, ~600 sessions across DNS, TCP/TLS, QUIC, HTTP, HTTP/2, HTTP/3. Single client 192.168.184.137, gateway-resolver 192.168.184.2. TLS keylog decryption enabled.

Session outcomes

TypeOutcomeCount
dns-querysuccess::dns-resolved121
http3-streamsuccess::http3-2xx366
http3-streamfailure::http3-client-error4
http3-streamincomplete::no-close29
http2-streamsuccess::http2-2xx21
http2-streamfailure::http2-rst-stream8
quic-connectionincomplete::no-close38
tcp-connectionfailure::tcp-reset2
tcp-connectionsuccess::graceful-fin40

Primary latency source — DNS (the smoking gun)

Every DNS lookup against 192.168.184.2 reports dns.time ≈ 2.0–2.3 s, with a handful at 3.3 s. The first www.google.com A query goes out at T=0.000 — its reply does not arrive until T=2.079 s. The first TCP SYN to Google is at T=2.086 s, i.e. the page can't start dialing for ~2 s, every name.

Examples (all No-Error, just slow):
  www.google.com       A      2.079 s
  www.google.com       AAAA   2.078 s
  www.mozilla.org      A      2.041 s
  fonts.gstatic.com    A      2.041 s
  static.doubleclick…  A      2.117 s
  (slowest A)                 3.365 s

The tight 2.0 s clustering is a classic forwarder-timeout-then-fallback signature — not real resolver latency.

The rest of the path is healthy

  • TCP iRTT (SYN→SYN-ACK) to Google: 30–55 ms; gstatic mirrors 60–80 ms.
  • TLS 1.3 handshakes complete in 1 RTT directly after SYN-ACK.
  • QUIC Initial→Handshake→HANDSHAKE_DONE: ~70–90 ms.

DNS therefore adds 40–60× the actual network RTT on every new name.

TCP / QUIC retransmissions — not a meaningful factor

CounterCount
tcp.analysis.retransmission0
tcp.analysis.fast_retransmission0
tcp.analysis.spurious_retransmission0
tcp.analysis.out_of_order0
tcp.analysis.duplicate_ack0
tcp.analysis.zero_window / window_full0
QUIC "reused stream offset (retransmission?)"6 of 12,266 (~0.05%)

The 6 QUIC retransmissions are scattered across 4 connections and recover immediately. The 38 ⚠️ events in the explore output are all TLS Close-Notify alerts (warning-level) — normal end-of-connection markers, not loss.

Bottom line

  • DNS ~2 s per query — fix the upstream at 192.168.184.2 or switch to 1.1.1.1 / 8.8.8.8. Single biggest win.
  • H3/H2 stream resets, TCP RSTs exist (8 H2 RST, 4 H3 client-errors, 2 TCP RSTs) but are by-design Happy Eyeballs / image-cancel behavior.
  • TCP / QUIC loss not a contributor — transport layer is clean.
03UserFollow-up

Thanks for the info. What is the distribution of HTTP 1.x, HTTP 2, and HTTP 3 traffic?

04ClaudeHTTP version distribution

By application-layer transactions — one stream / one request = one transaction:

VersionTransactionsShareNotes
HTTP/1.x40.9%4 GETs total — 3 × 200 OK, 1 × redirect
HTTP/2327.4%22 × 2xx, 3 × redirect, 8 × RST_STREAM (cancelled image fetches on encrypted-tbn0.gstatic.com)
HTTP/340091.7%366 × 2xx, 1 × redirect, 4 × client-error, 29 × incomplete-no-close
Total436100%

And on the wire, sampled from the explore NDJSON labels:

VersionRequestsResponsesFrame-type chatter
HTTP/1.x4 GETs3 × 2xx + redirectsminimal
HTTP/231 GETs22 × 2xx + 3 × 3xx168 SETTINGS, 66 DATA, 37 GOAWAY, 8 RST_STREAM, 21 PING
HTTP/3876 HEADERS frames (req + resp)84 SETTINGS, 22 DATA, 65 Stream Reset, 517 uni-streams (QPACK / control)

Takeaways

  • HTTP/3 dominates — ~92% of all HTTP transactions. Modern Google/YouTube/gstatic endpoints all negotiated h3.
  • HTTP/2 is the fallback path (~7%) — mostly image-CDN traffic to encrypted-tbn0.gstatic.com where some streams hit RST_STREAM.
  • HTTP/1.x is negligible (~1%) — 4 transactions, likely captive-portal / connectivity-check style requests (Mozilla detect).
05UserFollow-up

Show me the top 10 hosts by traffic volume. Also, what is the distribution of IPv4 vs IPv6 traffic?

06ClaudeTop hosts & IP-version mix

Top 10 hosts by traffic volume

Excluding the local client 192.168.184.137 (~10 MB aggregate) and the LAN resolver 192.168.184.2 (30 kB). Ranked by bytes, from tshark -z endpoints,ip:

#IPHostPacketsBytes
174.125.130.93🎬 www.youtube.com3,9284.52 MB
274.125.24.105🌐 www.google.com4,2983.70 MB
3203.117.34.146🎬 rr7.sn-…googlevideo.com (video CDN)744824 kB
474.125.24.94🔤 fonts.gstatic.com348201 kB
574.125.130.119🖼 i.ytimg.com230184 kB
674.125.200.94🔤 fonts.gstatic.com / gstatic197125 kB
7142.250.4.132(Google edge)108109 kB
8142.251.12.94🌐 www.google.com.sg / fonts153103 kB
9142.251.12.95🌐 jnn-pa.googleapis.com11092 kB
10172.253.118.139🖼 encrypted-tbn0.gstatic.com20788 kB

YouTube plus its video CDN (googlevideo.com) and google.com together account for ~9 MB of the ~10 MB total — this capture is overwhelmingly a YouTube / Google session.

IPv4 vs IPv6 distribution

LayerFramesBytesShare
IPv412,23210,962,05299.98%
IPv621770.002%
ARP (L2, no IP)321,9200.018%

The IPv6 traffic is just one link-local mDNS announce + one ICMPv6 packet — essentially zero application IPv6. Even though many DNS responses returned AAAA records (e.g. www.google.com → 2404:6800:4003:c00::67), the client opened all TCP/QUIC connections over IPv4. Likely the host has no usable IPv6 default route, so Happy Eyeballs fell back to v4 every time.

Method. Capture rendered with VisualEther using its MCP integration with Claude — analyze_captureexplore for the master sequence diagram, then extract_sessions for per-session outcome buckets. Volume and protocol-mix counters cross-checked with tshark -2 -z endpoints,ip, -z io,phs, and _ws.expert.message queries against the TLS-key-decrypted pcap.