: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.telequick.dev
and gets a WebTransport session on the same endpoint that serves everything else.
Open a session
You never touch theWebTransport 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.
- TypeScript
- Python
- The
quic://URL is rewritten tohttps://and the tenant token is attached as a query parameter, verified at the relay’s control plane before any track flows. - The client advertises the MoQT version as the WebTransport subprotocol
(
moqt-16). The relay refuses a session that doesn’t offer it, so this is not optional — the SDK always sends it for you. connectreturns as soon as the session is up and auto-reconnects with capped backoff if the link drops, replaying every publication and subscription. TheonStatecallback reportsConnecting/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) is what 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. Putting each group on its own stream means a lost or slow group can’t head-of-line-block the next one — the transport keeps moving.
Streams vs datagrams
WebTransport offers two ways to move bytes, and they trade reliability for latency differently:| Primitive | Delivery | Ordering | Voice uses it for |
|---|---|---|---|
| Streams | Reliable — retransmitted until delivered | Ordered within a stream | All voice media today. Each track group is one stream, so audio objects arrive in order and complete, while separate groups stay independent. |
| Datagrams | Unreliable — sent once, may be dropped | Unordered | Not used by the browser voice path. A WebTransport capability MoQT can carry single-object payloads over; reserved for latency-critical, loss-tolerant data. |
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 theserverCertificateHashes machinery never engages.
For local development against a self-signed relay, WebTransport lets you pin
the exact certificate by its SHA-256 fingerprint instead of installing a CA. Pass
the base64 hash and the SDK wires it into the session:
- Dev (self-signed)
- Production (CA cert)
Related
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.