The Protocol You Only Get on the Second Visit
SnapFrom Team · · 10 min read
A browser has two ways to open a connection to a website: TCP, which carries HTTP/1.1 and HTTP/2, and QUIC, which carries HTTP/3. An https:// link looks the same either way. So before the first packet leaves, the browser has to decide which one to try, and for a site it has never visited it usually has nothing to go on.
On 11 October 2026 we asked the 500 top domains on the Tranco list[10] for their home page and looked at how each one announces HTTP/3. 205 distinct hostnames answered with an HTML page. 84 of them advertise HTTP/3. Of those 84, 51 do it only in a response header, which the browser cannot read until it has already connected some other way.
For those 51 sites, which include YouTube, LinkedIn, WhatsApp, Bing and Pinterest, HTTP/3 starts on the second connection at the earliest.
The announcement that arrives late
HTTP/3 does not define a discovery step of its own. The specification points at an older mechanism: “An HTTP origin can advertise the availability of an equivalent HTTP/3 endpoint via the Alt-Svc HTTP response header field”[1]. This is what LinkedIn’s home page sent us:
HTTP/2 200
alt-svc: h3=":443"; ma=86400
Read left to right: HTTP/3 is available, on UDP port 443 of this same hostname, and you may remember that for 86,400 seconds.
That line is an HTTP response header, so it can only arrive on a connection that already exists. On a first visit that connection is TCP. The page that carried the header has been requested over HTTP/2 by the time the browser learns there was another option. The browser does not have to throw that connection away, either. The Alt-Svc specification says the client “does not need to block requests on any existing connection; it can be used until the alternative connection is established”[2].
Apple describes the same limit for apps: “URLSession won’t use HTTP/3 unless it was advertised”[8].
How long the browser remembers
Once seen, the advertisement goes into a cache, and the rules for that cache are short. An entry “is considered fresh for 24 hours from generation of the message”, and the ma parameter can change that[2]. When the entry lapses, “the client can no longer use this alternative service for new connections”[4], and the next visit starts over on TCP.
Here is what the 84 sites in our sample chose:
ma value | lifetime | hostnames |
|---|---|---|
| 86400 | 24 hours | 56 |
| 93600 | 26 hours | 8 |
| 604800 | 7 days | 1 |
| 2592000 | 30 days | 19 |
Two thirds of them set the value to exactly the default they would have got by leaving it out. The 30-day group is mostly Google and Microsoft properties, with Snapchat, Alibaba and Wix among the rest.
So on 56 of these sites, a reader who comes back every day keeps HTTP/3, and a reader who comes back every other day never has a fresh entry. Each of their visits opens on TCP and learns about HTTP/3 again.
There is a second way to lose the entry, and it has nothing to do with time. “By default, cached alternative services will be cleared when the client detects a network change”[2]. A phone that leaves home Wi-Fi for a mobile network has changed networks. A server can opt out with persist=1, which MDN describes plainly: “Entries are not deleted by network configuration changes”[4].
Not one of the 84 sites sent persist.
How strictly each browser applies the network-change rule is not something we could find documented. The specification words it as a SHOULD, and only “when information about network state is available”[2]. Treat it as the behaviour the standard asks for, not as a measurement of what every client does.
The same message, moved into DNS
The fix was to put the announcement somewhere the browser looks before it connects. RFC 9460, published in November 2023, defines an HTTPS record type for DNS, and states its purpose as getting “many of the benefits of Alt-Svc without waiting for a full HTTP connection initiation (multiple round trips) before learning of the preferred alternative”[3].
The browser already has to ask DNS for the site’s address. It asks for this record alongside. This is the answer for www.cloudflare.com:
www.cloudflare.com. 300 IN HTTPS 1 . alpn=h3,h2
ipv4hint=104.16.123.96,104.16.124.96
ipv6hint=2606:4700::6810:7b60,2606:4700::6810:7c60
alpn=h3,h2 is the part that matters here. It lists the protocols the server speaks, and with h3 in the list the browser can open a QUIC connection first. In Apple’s words, “since the information is in DNS, an HTTP/3 connection can be established the very first time your app tries to contact to your server”[8].
Who publishes which
For every hostname that returned a page, we recorded the Alt-Svc header on the final response and asked a public resolver for the HTTPS record of that same hostname.
| how HTTP/3 is announced | hostnames | share of 205 |
|---|---|---|
| Header and DNS record | 33 | 16% |
| Header only | 51 | 25% |
| DNS record only | 0 | 0% |
| Not announced at all | 121 | 59% |
Single vantage point, 11 October 2026, HTTP/2 client in Node.js 24.18 sending the request headers Chrome sends on a navigation, redirects followed to the final page. HTTPS records were fetched over DNS-over-HTTPS from Cloudflare’s resolver and again from Google’s; the two agreed on every hostname. 222 of the 500 domains returned a page, and several pairs redirect to the same place (twitter.com and x.com, youtube.com and youtu.be), which leaves 205 distinct hostnames.
Nobody announces HTTP/3 in DNS without also sending the header. The header is the baseline and the record is the extra, and three in five of the sites that support HTTP/3 have not added it.
The header-only list is not made of small sites. It includes www.youtube.com, www.linkedin.com, www.whatsapp.com, www.bing.com, www.pinterest.com, www.zoom.com, vimeo.com, www.dropbox.com, www.theguardian.com, edition.cnn.com, www.gov.uk and www.nature.com.
Three smaller findings from the same data.
A record can exist and say nothing about HTTP/3. 18 hostnames publish an HTTPS record with no h3 in it. Seventeen list h2 and no h3. The eighteenth is www.youtube.com, whose record is 1 . with no parameters at all, while its header advertises HTTP/3 for 30 days. A record with no alpn describes only the default set, and for this record type that set is http/1.1 alone[3]. On the same day www.google.com published alpn=h2,h3.
One CDN accounts for most of the DNS column. Of the 33 hostnames with both, 21 answered with server: cloudflare. Cloudflare creates the record without being asked: for a domain with “HTTP/2 or HTTP/3 enabled, proxied DNS records, and is also using Universal SSL”, it “automatically generates HTTPS records on the fly”[9]. Those are three conditions, and a customer can miss one. Ten more Cloudflare-fronted hostnames in the sample were header-only, LinkedIn, Zoom and Vimeo among them. www.linkedin.com reaches Cloudflare’s network through a chain of CNAMEs, and the name at the end of it returned no HTTPS record.
Draft versions are still on the wire. 25 hostnames also advertise h3-29, and 7 of those h3-27 as well. Both are tokens for pre-standard drafts of a protocol that was published in June 2022[1].
Why the DNS answer is weaker than it looks
Publishing the record does not guarantee the browser uses it. Four conditions sit in between, and they are written down in four different places.
DNS is not trusted, so the record carries less. The standard models DNS resolution as “an untrusted channel that might be controlled by an attacker”[3]. For that reason there is no persist in the record, and no ma: “server operators encode the expiration time in the DNS TTL”[3]. Most of the records served by Cloudflare came back with a TTL of 300 seconds. That is 5 minutes of memory against the header’s 24 hours. It costs less than it sounds, because the record rides along with an address lookup the browser makes anyway.
The browser will not wait long for it. Chrome asks for the HTTPS record by default, alongside the address queries[5]. If the addresses come back first, Chromium’s source sets a deadline for the straggler: 20% of the time elapsed since the first query began, never less than 5 milliseconds and never more than 50[5]. A resolver that answers type 65 queries slowly, or drops them, gives the same result as no record.
A proxy removes it. In Chromium, “proxied connections perform DNS on the proxy, so they can’t get supported ALPNs from DNS”[6]. The same code requires that QUIC is enabled and that this alternative has not already been marked broken, and if no matching record turns up, “a TCP-based protocol may work instead”[6].
Not every platform asks. Until August 2024, Firefox only resolved HTTPS records when DNS over HTTPS was switched on. Firefox 129 extended that to the operating system’s resolver “on specific platforms (Windows 11, Linux, Android 10+)”[7]. The release note does not list macOS or Windows 10.
Behind all of that is the network itself. QUIC runs over UDP, and “connectivity problems (e.g., blocking UDP) can result in a failure to establish a QUIC connection; clients SHOULD attempt to use TCP-based versions of HTTP in this case”[1]. A network that drops UDP on port 443 sends every visitor back to TCP, whatever the site announced.
What it costs the reader
The cost is paid on first visits, and on return visits after the cache entry has lapsed or the network has changed. Those are also the slowest moments a site has: nothing is cached, and often the visitor has just arrived from a search result on a mobile connection. On a header-only site, that visit sets up a TCP connection and a TLS session, fetches the page, and only then finds out it could have used QUIC.
The memory has a privacy cost too. Alt-Svc lets a server hand each browser a hostname to come back to, and the specification says outright what that allows: “By using unique names, servers could conceivably track client requests.” With persist set, it adds, such tracking “could follow users across multiple networks”[2]. Its defence is that the cache has to be wiped when cookies are: “any alternative service information MUST be removed when origin-specific data is cleared”[2]. The DNS record cannot be used this way, because “groups of clients will necessarily receive the same SvcParams”[3].
A record has one more effect that a site should know about before publishing it. A browser that finds a usable HTTPS record for an http:// URL “SHOULD behave as if it has received an HTTP 307 (Temporary Redirect)” to the https:// version[3]. The record upgrades the scheme whether or not that was the reason for adding it.
Checking a site
Two commands show both channels. The header:
curl -sI https://www.example.com/ | grep -i alt-svc
And the record, from a public resolver:
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=www.example.com&type=HTTPS'
Use the hostname the page is finally served from, after redirects. A record on example.com does nothing for a site that lives at www.example.com.
To see what a real page load used, open the site in a fresh browser profile and run this in the console:
performance.getEntriesByType("navigation")[0].nextHopProtocol
It returns the protocol “as identified by the ALPN Protocol ID”[11]: h2 or h3. On a header-only site a first load reports h2. Close the tab, open the page again, and it will often say h3. That is the header from the first visit taking effect.
Where that leaves you
Whether a site speaks HTTP/3 and whether a visitor gets HTTP/3 are separate questions. The second depends on when the browser finds out. A response header tells it after the first connection, for a day by default, and the standard says to forget it when the network changes. A DNS record tells it before the first connection, as long as the resolver passes the record through quickly enough and the browser on that platform asks for it.
In this sample, 84 sites did the work of deploying HTTP/3 and 51 of them left its discovery to the header. The record is one line of DNS. On Cloudflare it is created automatically when three settings line up[9], so it is worth checking whether yours do.
Sources
- RFC 9114: HTTP/3
- RFC Editor, IETF, accessed
Supports: Published June 2022, Standards Track. Section 3.1.1: 'An HTTP origin can advertise the availability of an equivalent HTTP/3 endpoint via the Alt-Svc HTTP response header field or the HTTP/2 ALTSVC frame ([ALTSVC]) using the "h3" ALPN token', with the example 'Alt-Svc: h3=":50781"'. Section 3.1: 'Connectivity problems (e.g., blocking UDP) can result in a failure to establish a QUIC connection; clients SHOULD attempt to use TCP-based versions of HTTP in this case.'
- RFC 7838: HTTP Alternative Services
- RFC Editor, IETF, accessed
Supports: Published April 2016. Section 3.1: an advertised alternative 'is considered fresh for 24 hours from generation of the message. This can be modified with the "ma" (max-age) parameter', and 'By default, cached alternative services will be cleared when the client detects a network change', unless they 'carry the "persist" parameter with a value "1"'. Section 2.2: 'clients SHOULD remove from cache all alternative services that lack the "persist" flag with the value "1" when they detect such a change, when information about network state is available.' Section 2.4: 'The client does not need to block requests on any existing connection; it can be used until the alternative connection is established.' Section 9.4: 'By using unique names, servers could conceivably track client requests. Such tracking could follow users across multiple networks, when the "persist" flag is used', and 'any alternative service information MUST be removed when origin-specific data is cleared (typically, when cookies [RFC6265] are cleared).'
- RFC 9460: Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)
- RFC Editor, IETF, accessed
Supports: Published November 2023. Section 1.2: 'the HTTPS RR (Section 9) enables many of the benefits of Alt-Svc [AltSvc] without waiting for a full HTTP connection initiation (multiple round trips) before learning of the preferred alternative'. Section 9: 'The default set of ALPN IDs is the single value "http/1.1".' Section 9.2.2: 'The DNS resolution process is modeled as an untrusted channel that might be controlled by an attacker', and 'there is no SvcParamKey corresponding to the Alt-Svc "persist" parameter, because this parameter is not safe to accept over an untrusted channel.' Section 9.2.3: 'There is no SvcParamKey corresponding to the Alt-Svc "ma" (max age) parameter. Instead, server operators encode the expiration time in the DNS TTL.' Section 9.2.4: 'groups of clients will necessarily receive the same SvcParams.' Section 9.5: on finding a usable HTTPS record for an http URL, 'the client SHOULD behave as if it has received an HTTP 307 (Temporary Redirect) status code with this "https" URL'.
- Alt-Svc header
- MDN Web Docs, Mozilla, accessed
Supports: On the ma parameter: 'If omitted, it defaults to 24 hours', and 'Once the cached entry expires, the client can no longer use this alternative service for new connections.' On persist=1: 'Entries are not deleted by network configuration changes.'
- net/base/features.cc and features.h (Chromium source)
- The Chromium Authors, accessed
Supports: kUseDnsHttpsSvcb, described in features.h as 'Enables querying HTTPS DNS records that will affect results from HostResolver and may be used to affect connection behavior', is declared FEATURE_ENABLED_BY_DEFAULT. Its timeout parameters default to UseDnsHttpsSvcbInsecureExtraTimePercent = 20, UseDnsHttpsSvcbInsecureExtraTimeMin = 5 milliseconds and UseDnsHttpsSvcbInsecureExtraTimeMax = 50 milliseconds. The header comment explains them: 'If we are still waiting for an HTTPS transaction after all the other transactions in an insecure DnsTask have completed, we will compute a timeout for the remaining transaction', a percentage of 'the time delta since the first query began', clamped by the min and max.
- net/http/http_stream_factory_job_controller.cc (Chromium source)
- The Chromium Authors, accessed
Supports: The comment 'Getting ALPN for H3 from DNS has a lot of preconditions. Among them: proxied connections perform DNS on the proxy, so they can't get supported ALPNs from DNS', above a condition that also requires alternative services to be enabled, an https URL, QUIC to be enabled, a direct connection, and that the alternative service is not marked broken. Also: 'If the job failed because there were no matching HTTPS records in DNS, run the backup job. A TCP-based protocol may work instead.'
- Firefox 129.0 release notes
- Mozilla, accessed
Supports: Released August 6, 2024: 'HTTPS DNS records can now be resolved with the operating system's DNS resolver on specific platforms (Windows 11, Linux, Android 10+). Previously this required DNS over HTTPS to be enabled. This capability allows the use of HTTP/3 without needing to use the Alt-Svc header, upgrades requests to HTTPS when the DNS record is present, and enables wider use of ECH'.
- Accelerate networking with HTTP/3 and QUIC (WWDC21 session 10094)
- Apple, accessed
Supports: From the session transcript: 'URLSession won't use HTTP/3 unless it was advertised. In this example, HTTP/3 was advertised through the Alt-Svc HTTP header.' On the DNS record: 'since the information is in DNS, an HTTP/3 connection can be established the very first time your app tries to contact to your server.' On failure: 'In that case, we'll fall back to HTTP/2.' The session introduces HTTP/3 and QUIC as 'two new protocols available in iOS 15 and macOS Monterey'.
- DNS record types: SVCB and HTTPS
- Cloudflare, accessed
Supports: 'If your domain has HTTP/2 or HTTP/3 enabled, proxied DNS records, and is also using Universal SSL, Cloudflare automatically generates HTTPS records on the fly, to advertise to clients how they should connect to your server.' And: 'Manually-added HTTPS records on proxied names are not served'.
- Tranco list 8PXYV (generated 2026-10-10)
- Tranco, accessed
Supports: The sample for the survey: the first 500 domains of Tranco list 8PXYV, generated on 10 October 2026. Tranco ranks registrable domains, not websites, so a share of its top entries (API, CDN and telemetry hostnames) serve no page at all.
- PerformanceResourceTiming: nextHopProtocol property
- MDN Web Docs, Mozilla, accessed
Supports: 'The nextHopProtocol read-only property is a string representing the network protocol used to fetch the resource, as identified by the ALPN Protocol ID (RFC7301).'