{"attribution":"PQ Crypta Post-Quantum QUIC & HTTP/3 Analyzer, https://pqcrypta.com/http3-quic/","data":{"capabilities":[{"capability":"HTTP/2","level":"negotiated","measured":634,"pct":97.8,"population":"all","supported":620,"vantage":null},{"capability":"HTTP/1.1 still accepted","level":"negotiated","measured":634,"pct":97.8,"population":"all","supported":620,"vantage":null},{"capability":"HTTP/3","level":"negotiated","measured":634,"pct":30.0,"population":"all","supported":190,"vantage":null},{"capability":"DNS HTTPS record present","level":"advertised","measured":623,"pct":20.5,"population":"dns","supported":128,"vantage":null},{"capability":"DNS HTTPS advertises h3","level":"advertised","measured":623,"pct":13.3,"population":"dns","supported":83,"vantage":null},{"capability":"DNS HTTPS carries ech=","level":"advertised","measured":623,"pct":4.5,"population":"dns","supported":28,"vantage":null},{"capability":"Connection migration allowed","level":"advertised","measured":217,"pct":50.7,"population":"migration","supported":110,"vantage":null},{"capability":"RFC 9218 priorities","level":"advertised","measured":217,"pct":100.0,"population":"quic","supported":217,"vantage":null},{"capability":"Address validation (Retry)","level":"exercised","measured":217,"pct":100.0,"population":"quic","supported":217,"vantage":null},{"capability":"QPACK dynamic table","level":"advertised","measured":217,"pct":45.2,"population":"quic","supported":98,"vantage":null},{"capability":"CONNECT-UDP handler","level":"reachable","measured":217,"pct":40.6,"population":"quic","supported":88,"vantage":"Any status code counts: the request reached a handler that parsed it."},{"capability":"0-RTT resumption","level":"advertised","measured":217,"pct":39.2,"population":"quic","supported":85,"vantage":"Read from max_early_data_size in the NewSessionTicket the origin sends over QUIC — the origin's own statement that it will accept early data, not a replay we performed. A lower bound: origins that completed a QUIC handshake but sent no ticket said nothing about early data, and they remain in the denominator."},{"capability":"Extended CONNECT","level":"advertised","measured":217,"pct":26.3,"population":"quic","supported":57,"vantage":null},{"capability":"HTTP/3 datagrams","level":"advertised","measured":217,"pct":23.5,"population":"quic","supported":51,"vantage":null},{"capability":"QUIC v2 offered (RFC 9369)","level":"advertised","measured":217,"pct":10.1,"population":"quic","supported":22,"vantage":null},{"capability":"WebTransport in SETTINGS","level":"advertised","measured":217,"pct":0.9,"population":"quic","supported":2,"vantage":null},{"capability":"QUIC bit greasing (RFC 9287)","level":"negotiated","measured":217,"pct":0.5,"population":"quic","supported":1,"vantage":null},{"capability":"Multipath QUIC","level":"exercised","measured":217,"pct":0.0,"population":"quic","supported":0,"vantage":"Needs a genuine second network path from this vantage point. A failure here can be ours rather than the origin."},{"capability":"MASQUE CONNECT-UDP session","level":"exercised","measured":217,"pct":0.0,"population":"quic","supported":0,"vantage":"Requires a 2xx. A relay declining an unauthenticated stranger is behaving correctly, so a low rate here is expected and is not an adoption figure."},{"capability":"WebTransport session","level":"exercised","measured":217,"pct":0.0,"population":"quic","supported":0,"vantage":"A session is opened against one path. An origin serving WebTransport at a path we do not know reads as absent."},{"capability":"TLS 1.3","level":"negotiated","measured":623,"pct":89.4,"population":"tls","supported":557,"vantage":null},{"capability":"Post-quantum key exchange","level":"negotiated","measured":623,"pct":68.1,"population":"tls","supported":424,"vantage":null},{"capability":"OCSP stapling","level":"exercised","measured":623,"pct":23.4,"population":"tls","supported":146,"vantage":null},{"capability":"ECH offered in TLS","level":"advertised","measured":623,"pct":4.5,"population":"tls","supported":28,"vantage":null}],"classification":{"below_floor":132,"confidence_floor":0.7,"note":"The fingerprinter is part of the instrument. Domains classified below the confidence floor, and those it could not name at all, are left out of the implementation table rather than averaged into it.","ruleset":"v1","unclassified":91},"cohort":{"baseline":{"derivation":"corpus_stats v1","fingerprint_ruleset":"v1","grader_version":"2026.09.09","methodology":"public/ent/docs/MEASUREMENT_METHODOLOGY.md v1","probe_version":"2026.09.10"},"cohort":"pqcrypta_transport v1","design":{"comparability":"A change to any instrument in `baseline` is a boundary in this series, handled by the release gate in the measurement methodology: either an overlap window is planned or a baseline reset is declared.","frozen_on":"2026-09-10","known_skew":"The candidate pool is heavily CDN-fronted — roughly a quarter of members fingerprint as Cloudflare — because people scan sites they already care about and those sit behind large CDNs. A per-implementation rate over this cohort describes these domains, not that vendor's customer base.","membership":"Fixed. Immutable for the baseline period. A domain that stops answering keeps its place and is reported as not currently measurable; it is never replaced and the denominator never shrinks. A rolling panel, if wanted, will be a separate cohort.","population":"Every third-party domain in the public HTTP/3 directory that had answered at least one probe as of the freeze. Domains this platform operates are excluded (corpus_domain_ownership).","represents":"Domains someone chose to scan through this scanner before 2026-09-10. NOT a sample of the web, and not weighted toward any registry, sector or region. Any rate over this cohort inherits that self-selection.","sampling":"None. All eligible candidates were admitted. Selecting a round number from them would have required a rule that changes what the population represents; taking the whole eligible set requires none.","schedule":"Re-measured weekly by scripts/http3_rescan_directory.sh. Weekly rather than nightly because each pass makes real connections to third-party origins and protocol configuration does not change hourly.","stratification":{"basis":"Server implementation as identified by fingerprint ruleset v1, at or above the 0.70 confidence floor.","caveat":"The confidence floor is itself a source of selection bias: it preferentially names vendors that send a distinctive Server header. A stratum is therefore \"domains confidently classified as X by ruleset v1\", never \"domains running X\".","frozen":"Assigned once at freeze and stored. A later fingerprinter improvement must not move domains between strata mid-series; re-stratification requires a new cohort version.","unclassified":"A full stratum, not an exclusion. A domain the fingerprinter cannot name is measured like any other member."},"unreachability":{"confirmed_unavailable":"Two consecutive failed observations, matching the rule the directory already uses.","effect_on_rates":"Neither removes the member. Rates are reported as \"N of 604 measurable\", so a series never improves by losing its worst members.","temporarily_unreachable":"One failed observation. Not yet a state change; a single failed probe is a bad minute, not a dead origin."}},"frozen_at":"2026-09-10T19:50:49.925009-05:00","instruments_unchanged":false,"measurable":{"confirmed_unavailable":10,"measurable":593,"note":"Members are never removed. A rate over this cohort is reported against the frozen size, so the series cannot improve by losing its worst members.","temporarily_unreachable":1},"size":604,"strata":{"AWS (ELB/ALB/S3)":27,"Akamai":52,"Apache (mod_h3)":30,"Bun":2,"Caddy (quic-go)":2,"Cloudflare":159,"Envoy Proxy":9,"Facebook (mvfst)":1,"Fastly (H2O)":2,"Google Frontend (GFE)":6,"HAProxy":2,"Kestrel (ASP.NET)":3,"LiteSpeed":6,"Meta (mvfst)":1,"Microsoft (msquic)":1,"OpenResty":5,"Reddit":1,"Sucuri":1,"Tengine (Alibaba nginx)":1,"Varnish":14,"nginx":60,"nginx-quic":1,"unclassified":218}},"denominators":{"all":{"label":"of all domains measured","n":634},"dns":{"label":"of domains whose DNS was resolved","n":623},"migration":{"label":"of domains whose QUIC transport parameters were read","n":217},"quic":{"label":"of domains where a QUIC handshake completed — transport parameters were actually read, not merely an h3 advertisement seen","n":217},"tls":{"label":"of domains where a TLS handshake completed","n":623}},"drift":{"comparable_from":"2026-09-14T13:36:56.881314-05:00","comparable_pairs":9720,"current_probe_rows":625,"domains_with_history":634,"movements":[{"count":7204,"direction":"change","movement":"instrument_changed"},{"count":11,"direction":"improvement","movement":"grade_up"},{"count":10,"direction":"regression","movement":"grade_down"},{"count":9,"direction":"change","movement":"response_class_changed"},{"count":7,"direction":"improvement","movement":"http3_gained"},{"count":7,"direction":"regression","movement":"http3_lost"},{"count":6,"direction":"regression","movement":"became_unreachable"},{"count":4,"direction":"regression","movement":"alt_svc_lost"},{"count":1,"direction":"change","movement":"quic_version_changed"},{"count":1,"direction":"change","movement":"http3_unreachable_once"}],"note":"Movement is only visible where the same domain has been observed twice, under one set of instrument semantics.","stale_probe_rows":9,"sufficient":true},"excluded":{"domains":12,"http3":12,"multipath":12,"reason":"Infrastructure we operate, held out of every rate above. Counting our own WebTransport and multipath deployment as corpus adoption would measure this platform, not the Internet.","webtransport":11},"generated_at":"2026-10-11T11:43:44.088867-05:00","grades":{"A":83,"A+":107,"C":35,"F":409},"instruments":{"declaration_note":"Every instrument version must declare what it changed, or declare explicitly that it changed nothing. A version listed as undeclared has done neither, so nothing measured across it can be compared until someone says what moved.","derivation":{"actual":"3b3a4f95f9b023ab39d7308e0317c24b","expected":"eb0f372b2fef4b6b96bd44f44591c8f6","note":"The implementation has changed since this version was registered. Numbers below were produced by a derivation this contract no longer describes — bump the version and re-register, or revert.","objects":["classical_strength_bits","corpus_answer_unstable","corpus_measurement_bound","corpus_observation_scope","corpus_steering_bound","get_http3_corpus_stats","http3_scan_latest","is_self_operated","pqc_key_role","undeclared_instrument_versions"],"verified":false,"version":"v7"},"grader_versions":{"2026.09.09":630,"unversioned":4},"note":"The probe decides what was observed, the grader what it is worth, the fingerprinter which implementation it is. Each changes independently; a NULL predates versioning and its semantics are unknown rather than known-equal.","probe_versions":{"2026.09.11":4,"2026.09.12":3,"2026.09.13.12":1,"2026.09.13.5":1,"2026.09.14.1":625},"undeclared":[]},"ladders":[{"note":"The session probe targets one path. An origin serving WebTransport at a path we do not know reads as absent on the last rung.","population":"quic","rungs":[{"level":"negotiated","n":217,"rung":"QUIC handshake completed"},{"level":"advertised","n":57,"rung":"Extended CONNECT"},{"level":"advertised","n":51,"rung":"HTTP/3 datagrams"},{"level":"advertised","n":2,"rung":"WebTransport in SETTINGS"},{"level":"exercised","n":0,"rung":"Session opened from here"}],"technology":"WebTransport"},{"note":"These rungs are not nested: answering a CONNECT-UDP request with 4xx needs no Extended CONNECT advertisement, so the reachable count can exceed the advertised one.","population":"quic","rungs":[{"level":"negotiated","n":217,"rung":"QUIC handshake completed"},{"level":"advertised","n":57,"rung":"Extended CONNECT"},{"level":"reachable","n":88,"rung":"Handler answered the request"},{"level":"exercised","n":0,"rung":"Session accepted (2xx)"}],"technology":"MASQUE CONNECT-UDP"},{"note":"Negotiation needs a genuine second network path from this vantage point, so a zero here is partly a statement about the measurement position and not only about the origins.","population":"quic","rungs":[{"level":"negotiated","n":217,"rung":"QUIC handshake completed"},{"level":"advertised","n":110,"rung":"Migration not disabled"},{"level":"exercised","n":0,"rung":"Second path validated"},{"level":"exercised","n":0,"rung":"Multipath negotiated"}],"technology":"Multipath QUIC"}],"not_measurable":{"certificate_metadata.delegated_credentials":{"class":"not_implemented","fix":"Implement client-side RFC 9345 in a TLS stack we can build against.","reason":"RFC 9345 requires the CLIENT to offer the delegated_credential extension (type 34), and the credential rides in the Certificate message, which TLS 1.3 encrypts — so no raw-socket probe substitutes. Neither TLS stack here offers it: OpenSSL 3.5 has no delegated-credential support and rustls 0.23 does not implement it. This is the narrow question of whether THIS handshake used one. The adjacent question that IS answerable — whether the leaf certificate is authorised to issue them (RFC 9345 section 4.2: DelegationUsage extension AND digitalSignature KeyUsage) — is measured and reported as certificate_metadata.delegation_usage."},"connection_metrics.packets_retransmitted":{"class":"not_applicable","fix":null,"reason":"QUIC never retransmits a packet. A lost frame is re-sent in a new packet with a new packet number (RFC 9002 §2), so there is no packet-level retransmission count to read — in any QUIC stack, not just this one. Lost packets and lost bytes are reported instead and are the meaningful figures."},"http3_settings.priority_incremental_supported":{"class":"not_observable","fix":null,"reason":"As with priority_urgency_supported: RFC 9218 §4 obliges a server to ignore an unrecognised i= parameter rather than reject the frame, so acceptance is silent on whether incremental delivery is implemented. Reported as priority_enabled, which is the one thing the exchange establishes."},"http3_settings.priority_urgency_supported":{"class":"not_observable","fix":null,"reason":"RFC 9218 §4 requires a server to ignore priority parameters it does not recognise, so an origin implementing no urgency handling still accepts a PRIORITY_UPDATE frame carrying u=. Frame acceptance cannot distinguish per-parameter support, and no frame a client could send would make it distinguishable. What IS observable — that the origin accepted a well-formed PRIORITY_UPDATE — is reported as priority_enabled."},"http3_settings.qpack_dynamic_table_size":{"class":"not_applicable","fix":null,"reason":"As a property of the origin, the only dynamic-table figure that exists is the capacity it advertises, and that is already reported as qpack_max_table_capacity. Populating this too would put one measurement on the page twice under two names. The related qpack_encoder_stream field is NOT a substitute: this client advertises no table capacity, so it records whether the peer opens its encoder stream unprompted, not whether it can maintain a table."},"security_features.max_connections_per_ip":{"class":"out_of_scope","fix":null,"reason":"A server-side configuration limit. Establishing it means opening connections until the origin refuses, which is the attack the setting exists to stop. We will not run that probe against someone else's server."},"tls_extensions.early_data_accepted":{"class":"not_observable","fix":null,"reason":"Whether a server ACCEPTS replayed early data is only knowable by replaying some, which means sending a request twice and hoping the origin treats it as idempotent. We will not do that to someone else's server. What is read instead is the offer — max_early_data_size in the NewSessionTicket — reported as supports_0rtt. An origin that offers early data may still reject it at resumption time, so a true supports_0rtt is an upper bound on this."},"tls_extensions.signature_algorithms":{"class":"not_applicable","fix":null,"reason":"A TLS 1.3 server does not tell a client which signature algorithms it supports; the client offers a list and the server simply picks one to sign with. The only origin-side fact is the algorithm on the certificate it presented, and that is reported as certificate_metadata.signature_algorithm. This field previously carried our own ClientHello offer and read ML-DSA-44 on 599 of 600 domains, including origins serving RSA certificates."},"webtransport_capabilities.close_codes_supported":{"class":"out_of_scope","fix":null,"reason":"Only observable by closing a session in every way the spec allows and recording which the peer accepts. That is not a read-only probe."},"webtransport_capabilities.datagram_only_mode":{"class":"not_observable","fix":null,"reason":"Application policy. The wire protocol carries no signal for it, so no client can measure it from outside."},"webtransport_capabilities.session_auth_required":{"class":"not_observable","fix":null,"reason":"Application policy. The wire protocol carries no signal for it, so no client can measure it from outside."},"webtransport_capabilities.session_pooling":{"class":"not_observable","fix":null,"reason":"Application policy. The wire protocol carries no signal for it, so no client can measure it from outside."},"webtransport_capabilities.session_resumption":{"class":"not_observable","fix":null,"reason":"Application policy. The wire protocol carries no signal for it, so no client can measure it from outside."}},"providers":[{"domains":163,"http3":91,"http3_pct":55.8,"implementation":"Cloudflare","median_confidence":0.95,"post_quantum":160,"post_quantum_pct":98.2},{"domains":65,"http3":22,"http3_pct":33.8,"implementation":"nginx","median_confidence":0.85,"post_quantum":29,"post_quantum_pct":44.6},{"domains":51,"http3":3,"http3_pct":5.9,"implementation":"Akamai","median_confidence":0.9,"post_quantum":47,"post_quantum_pct":92.2},{"domains":32,"http3":3,"http3_pct":9.4,"implementation":"Apache (mod_h3)","median_confidence":0.75,"post_quantum":8,"post_quantum_pct":25.0},{"domains":30,"http3":2,"http3_pct":6.7,"implementation":"AWS (ELB/ALB/S3)","median_confidence":0.9,"post_quantum":18,"post_quantum_pct":60.0},{"domains":16,"http3":2,"http3_pct":12.5,"implementation":"Varnish","median_confidence":0.85,"post_quantum":13,"post_quantum_pct":81.3},{"domains":13,"http3":6,"http3_pct":46.2,"implementation":"Envoy Proxy","median_confidence":0.85,"post_quantum":9,"post_quantum_pct":69.2}],"sample":{"answer_unstable":21,"bot_mitigated":71,"comparable_pairs":9720,"domains":634,"domains_with_history":634,"first_observation":"2025-12-25T13:02:48.406115-06:00","last_observation":"2026-10-11T04:36:59.902527-05:00","measurement_bound":"They answer that way because the scanner is not a browser. What they served is a real observation of what the origin gives this client, but not of the site behind it: a challenge page sends security headers and a Server of its own, and advertises no HTTP/3. Those rows are counted rather than dropped, and the scanner does not put on a browser User-Agent to get past them — a row obtained that way would describe a client we are not.","note":"Domains someone chose to scan, not a survey of the web. Read every rate as \"of the domains measured here\".","observation_scope":"Scans run to verify the scanner against a known target are held out of these counts. They remain in each domain's history and can still be its most recent observation; they are simply not evidence of how much of the web has been measured.","observations":10354,"self_selected":true,"steering_bound":"Some hostnames answer from different infrastructure on different lookups. A CNAME into a multi-CDN steering layer can hand one client a CDN that serves HTTP/3 and the next a backend that does not, on a TTL measured in seconds, and the two need not be configured alike. Each scan reads whichever backend answered it, so for these origins there is no single grade to be right about — a browser gets the same lottery. Counted by alternation rather than by variety: a hostname that returned to an advertisement it had made before, after making a different one, is being steered, whereas a site that migrated changes its answer once and keeps it.","verification_held_out":219}},"license":"https://creativecommons.org/licenses/by/4.0/","success":true}