HTTP/2 passes through proxies without difficulty because it runs over TCP, and TCP is exactly what a CONNECT tunnel or a SOCKS5 connection carries. HTTP/3 does not: it runs over QUIC, which is UDP-based, and ordinary HTTP proxies cannot tunnel UDP at all while most SOCKS5 deployments do not either. The practical consequence is that a proxied client almost always talks HTTP/2 (or HTTP/1.1) to a site even when the site supports HTTP/3 — the browser falls back silently. That is fine for most work, but it changes what the destination sees, and it is worth understanding rather than discovering.
The three protocols in one minute
- HTTP/1.1 (1997): text-based, one request at a time per connection; browsers open several connections in parallel to compensate.
- HTTP/2 (2015): binary framing, many concurrent streams multiplexed over one TCP connection, header compression (HPACK), server push (now largely abandoned). Same TCP + TLS underneath as HTTP/1.1.
- HTTP/3 (2022): the same semantics as HTTP/2 but carried by QUIC, a transport that runs over UDP, builds TLS 1.3 into its handshake, avoids TCP head-of-line blocking, and lets a connection survive an IP change (a phone moving from Wi-Fi to 4G).
A browser learns that a site offers HTTP/3 in one of two ways: an Alt-Svc: h3=":443" response header on an earlier HTTP/2 response, or a DNS HTTPS record advertising it. Once it knows, it tries QUIC on the next connection and remembers the result.
How proxies carry each one
HTTP proxy
For an HTTPS destination the client sends CONNECT host:443, the proxy opens a TCP connection to the destination and turns itself into a dumb byte pipe. Whatever the client and destination negotiate inside that pipe — TLS 1.3, then HTTP/1.1 or HTTP/2 via ALPN — is invisible to the proxy and works unchanged. HTTP/2 through an HTTP proxy is therefore completely normal.
UDP has no place in this model. CONNECT creates a TCP tunnel; there is no standard way for a plain HTTP/1.1 proxy to say “forward my UDP datagrams to this host.” A browser that is configured with an HTTP proxy simply does not attempt QUIC to origins — Chrome and Firefox disable HTTP/3 for proxied connections — and uses HTTP/2 through the tunnel instead. No error, no warning.
SOCKS5 proxy
SOCKS5 does define a UDP ASSOCIATE command for relaying datagrams. In principle a SOCKS5 proxy could carry QUIC. In practice:
- many commercial SOCKS5 proxies implement only
CONNECT(TCP) and reject or ignore UDP ASSOCIATE; - UDP relay through SOCKS5 requires the proxy to have a reachable UDP port and the client to support the association dance, which browsers do not do for HTTP/3;
- Chrome and Firefox treat a SOCKS proxy the same as an HTTP one for this purpose: HTTP/3 is not attempted.
So even where the proxy could forward UDP, the browser will not ask it to. Command-line QUIC clients and some libraries can be pointed at a UDP-capable SOCKS5 proxy, but that is a specialist configuration, not the default. Our SOCKS5 vs HTTP comparison covers the TCP/UDP distinction more broadly.
What would carry HTTP/3: MASQUE and CONNECT-UDP
The IETF's MASQUE working group standardised CONNECT-UDP (RFC 9298), an extension that lets an HTTP/3 (or HTTP/2) proxy tunnel UDP payloads — and by extension QUIC to an origin. It is what Apple's iCloud Private Relay and some newer privacy proxies use. Support in general-purpose commercial proxies and in browser proxy settings is still uncommon; when a provider advertises “HTTP/3 support” it is worth asking whether they mean the proxy speaks HTTP/3 to you or can tunnel HTTP/3 to origins — those are different things.
What actually happens, step by step
- Your proxied browser requests
https://example.com. It opensCONNECT example.com:443through the proxy. - Inside the tunnel it does a TLS 1.3 handshake, offering ALPN
h2andhttp/1.1. The origin picksh2. You are on HTTP/2. - The response carries
Alt-Svc: h3=":443". The browser notes it — and, because a proxy is configured, ignores it for connection purposes. - Every subsequent request to that origin continues over HTTP/2 through the tunnel.
Turn the proxy off and reload: the browser now honours Alt-Svc and the same site is served over HTTP/3. Nothing is broken in either case; the protocol simply differs.
Why it matters
Performance
HTTP/3's advantages — faster handshakes, no head-of-line blocking on lossy links, connection migration — are lost through a proxy. For datacenter proxies on good links the difference is small. For mobile proxies, where the last hop is a lossy cellular link, QUIC would have helped most and is exactly where you cannot have it. Budget a little more latency than a direct HTTP/3 connection would show; see the methodology in how to measure proxy speed.
Fingerprinting and consistency
This is the subtle one. Anti-bot systems record which protocol a client used and what its HTTP/2 SETTINGS looked like (see how anti-bot systems work). A modern Chrome on a direct connection reaches most large sites over HTTP/3. The same Chrome through a proxy arrives over HTTP/2. On its own that is not suspicious — plenty of real users sit behind corporate proxies and never use HTTP/3 — but it is one more data point, and it means your HTTP/2 fingerprint (SETTINGS values, header order) is now always exposed and must be consistent with the claimed browser. HTTP clients that impersonate browsers must impersonate the HTTP/2 layer, not just the TLS layer, for exactly this reason; the TLS fingerprinting article explains the stack.
Scraping tools
Python's requests speaks HTTP/1.1 only; httpx can do HTTP/2 with the h2 extra; aiohttp is HTTP/1.1. None does HTTP/3 through a proxy. Since a proxied browser is on HTTP/2 anyway, using HTTP/2 in your client (where the library supports it) keeps you closest to what a real proxied user looks like. Examples in Proxies in Python.
Practical guidance
| Situation | What you get | Action |
|---|---|---|
| Browser + HTTP proxy, HTTP/3 site | HTTP/2 via CONNECT tunnel | Nothing to do; this is normal |
| Browser + SOCKS5 proxy, HTTP/3 site | HTTP/2 (browser does not attempt QUIC over SOCKS) | Nothing to do |
| You need HTTP/3 to an origin through a proxy | Requires CONNECT-UDP/MASQUE support end to end | Ask the provider specifically; assume no unless confirmed |
| Site behaves differently proxied vs direct | Possibly protocol-related, more likely IP-related | Compare with a real browser on the same proxy before blaming HTTP/3 |
| Impersonating client for protected sites | Must match a browser's HTTP/2 SETTINGS and header order | Use a client that impersonates HTTP/2, not only TLS |
| Measuring proxy latency | Compare like with like: HTTP/2 direct vs HTTP/2 proxied | Do not compare HTTP/3 direct against HTTP/2 proxied |
Frequently asked questions
Does HTTP/2 work through a proxy?
Yes. HTTP/2 runs over TCP and TLS, which a CONNECT tunnel or SOCKS5 connection carries transparently. The proxy does not need to understand HTTP/2 at all.
Does HTTP/3 work through a proxy?
Generally no. HTTP/3 uses QUIC over UDP; HTTP proxies cannot tunnel UDP and browsers do not attempt QUIC when a proxy is configured. The browser falls back to HTTP/2 automatically. Only proxies supporting CONNECT-UDP (MASQUE) can carry HTTP/3 to origins, and that is rare.
Can a SOCKS5 proxy carry QUIC?
The protocol has a UDP relay command, but many commercial SOCKS5 services do not implement it and browsers do not use it for HTTP/3. Specialist clients can, if the proxy genuinely supports UDP ASSOCIATE.
Will using HTTP/2 instead of HTTP/3 get me detected?
Not by itself — many legitimate users are behind proxies that force HTTP/2. But it means your HTTP/2 fingerprint is always visible, so it must be consistent with the browser you claim to be.
Is HTTP/3 faster through a proxy?
You do not get HTTP/3 through an ordinary proxy, so the question does not arise; you get HTTP/2, which is slightly slower on lossy links than HTTP/3 would be. On good datacenter links the difference is negligible.
What is Alt-Svc?
An HTTP response header by which a site tells the client that the same resource is available over another protocol or port — typically h3=":443" to advertise HTTP/3. Browsers honour it on direct connections and ignore it for connection purposes when a proxy is configured.