WebTransport is how a browser reaches the voice stack over raw QUIC. It gives you a single bidirectional session to the relay, with no TCP, no WebSocket framing, and no separate signalling socket. Every voice track, control message, and data stream for a call rides inside that session. You open one session and publish or subscribe. The transport handles the rest. The stack terminates QUIC, HTTP/3, and WebTransport on one :443. There is no second media port to open, no UDP range to whitelist beyond 443, and no raw protocol port to reason about. The browser dials https://relay.clutchcall.dev and gets a WebTransport session on the same endpoint that serves everything else.

Open a session

You never touch the WebTransport object directly. Every SDK ships a MoqtClient that opens the session, negotiates the protocol version, and keeps it alive across drops. Call connect and start publishing.
A few things happen under the hood that you can rely on:
  • The SDK rewrites the quic:// URL to https:// and attaches the tenant token as a query parameter. The relay’s control plane checks the token before any track flows.
  • The client advertises the MoQT version as the WebTransport subprotocol (moqt-16). The relay refuses a session that does not offer it, so this is not optional. The SDK always sends it for you.
  • connect returns as soon as the session is up. The client auto-reconnects with capped backoff if the link drops, and it replays every publication and subscription. The onState callback reports Connecting / Connected / Reconnecting / Closed / Failed.
The browser SDK is WebTransport-only today. If QUIC is blocked (some corporate proxies, UDP-filtered networks), the browser client cannot fall back on its own. The QUIC→WebSocket fallback ladder currently ships only in the native SDK cores. For those environments, use the WebRTC media leg described in Browser compatibility.

How MoQT rides the session

MoQT (Media-over-QUIC Transport) carries your named tracks (voice/<sid>/uplink and voice/<sid>/downlink for a call) inside the one WebTransport session. It uses two of WebTransport’s primitives:
  • A control stream — a single bidirectional stream carries MoQT setup and the subscribe/publish signalling. This is where the client and relay agree on versions, announce namespaces, and track subscriptions.
  • Object streams — each track group opens its own unidirectional stream of objects. Audio rolls over to a fresh group roughly once a second, so a live call is a rolling series of short-lived streams, each carrying ~1 s of encoded audio objects. Each group on its own stream means a lost or slow group cannot head-of-line-block the next one. The transport keeps moving.
You do not manage streams by hand. You publish objects to a track and subscribe to a track by name. The SDK maps that onto the streams above. See Sessions, calls, tracks & streams for the track model.

Streams vs datagrams

WebTransport offers two ways to move bytes, and they trade reliability for latency differently:
The per-group stream design gives you the best of both: reliable, in-order audio within the ~1 s a group lives, without one bad group stalling the whole call. You get datagram-like isolation between groups and stream reliability inside them. You write no datagram loss handling yourself.

The server certificate hash

In production, the relay presents a normal CA-issued certificate with multi-brand SNI, so the browser trusts it like any HTTPS origin. You pass no hash, and the serverCertificateHashes machinery never engages. For local development against a self-signed relay, WebTransport lets you pin the exact certificate by its SHA-256 fingerprint, so you do not need to install a CA. Pass the base64 hash, and the SDK wires it into the session:
The certificate-hash path has strict rules the browser enforces:
  • The certificate must be ECDSA (not RSA) with a validity window of 14 days or less. Regenerate it on that cadence for local dev.
  • Dial 127.0.0.1, not ::1. The IPv6 loopback breaks the WebTransport handshake.
  • It only covers self-signed dev relays. Never ship a pinned hash to production. Use a real certificate.

Transport to web & apps

How browser and mobile clients reach the voice stack over QUIC.

Browser audio capture

Capture and encode the microphone, then publish it over this session.

One-line WebRTC diversion

Divert an existing WebRTC audio pipeline onto QUIC in one call.

Browser compatibility

What works where, and the fallback when QUIC is blocked.