WebTransport API
Limited availability
This feature is not Baseline because it does not work in some of the most widely-used browsers.
Secure context: This feature is available only insecure contexts (HTTPS), in some or allsupporting browsers.
Note: This feature is available inWeb Workers.
TheWebTransport API provides a modern update toWebSockets, transmitting data between client and server usingHTTP/3 Transport. WebTransport provides support for multiple streams, unidirectional streams, and out-of-order delivery. It enables reliable transport viastreams and unreliable transport via UDP-like datagrams.
Concepts and usage
HTTP/3 has been in progress since 2018. It is based on Google's QUIC protocol (which is itself based on UDP), and fixes several issues around the classic TCP protocol, on which HTTP and WebSockets are based.
These include:
- Head-of-line blocking
HTTP/2 allows multiplexing, so a single connection can stream multiple resources simultaneously. However, if a single resource fails, all other resources on that connection are held up until any missing packets are retransmitted. With QUIC, only the failing resource is affected.
- Faster performance
QUIC is more performant than TCP in many ways. QUIC can handle security features by itself, rather than handing responsibility off to other protocols like TLS — meaning fewer round trips. And streams provide better transport efficiency than the older packet mechanism. That can make a significant difference, especially on high-latency networks.
- Better network transitions
QUIC uses a unique connection ID to handle the source and destination of each request — to ensure that packets are delivered correctly. This ID can persist between different networks, meaning that, for example, a download can continue without getting interrupted if you switch from Wi-Fi to a mobile network. HTTP/2, on the other hand, uses IP addresses as identifiers, so network transitions can be problematic.
- Unreliable transport
HTTP/3 supports unreliable data transmission via datagrams.
The WebTransport API provides low-level access to two-way communication via HTTP/3, taking advantage of the above benefits, and supporting both reliable and unreliable data transmission.
Initial connection
To open a connection to an HTTP/3 server, you pass its URL to theWebTransport()
constructor. Note that the scheme needs to be HTTPS, and the port number needs to be explicitly specified. Once theWebTransport.ready
promise fulfills, you can start using the connection.
Also note that you can respond to the connection closing by waiting for theWebTransport.closed
promise to fulfill. Errors returned by WebTransport operations are of typeWebTransportError
, and contain additional data on top of the standardDOMException
set.
const url = "https://example.com:4999/wt";async function initTransport(url) { // Initialize transport connection const transport = new WebTransport(url); // The connection can be used once ready fulfills await transport.ready; // …}// …async function closeTransport(transport) { // Respond to connection closing try { await transport.closed; console.log(`The HTTP/3 connection to ${url} closed gracefully.`); } catch (error) { console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`); }}
Unreliable transmission via datagrams
"Unreliable" means that transmission of data is not guaranteed, nor is arrival in a specific order. This is fine in some situations and provides very fast delivery. For example, you might want to transmit regular game state updates where each message supersedes the last one that arrives, and order is not important.
Unreliable data transmission is handled via theWebTransport.datagrams
property — this returns aWebTransportDatagramDuplexStream
object containing everything you need to send datagrams to the server, and receive them back.
TheWebTransportDatagramDuplexStream.writable
property returns aWritableStream
object that you can write data to using a writer, for transmission to the server:
const writer = transport.datagrams.writable.getWriter();const data1 = new Uint8Array([65, 66, 67]);const data2 = new Uint8Array([68, 69, 70]);writer.write(data1);writer.write(data2);
TheWebTransportDatagramDuplexStream.readable
property returns aReadableStream
object that you can use to receive data from the server:
async function readData() { const reader = transport.datagrams.readable.getReader(); while (true) { const { value, done } = await reader.read(); if (done) { break; } // value is a Uint8Array. console.log(value); }}
Reliable transmission via streams
"Reliable" means that transmission and order of data are guaranteed. That provides slower delivery (albeit faster than with WebSockets), and is needed in situations where reliability and ordering are important (such as chat applications, for example).
When using reliable transmission via streams you can also set the relative priority of different streams over the same transport.
Unidirectional transmission
To open a unidirectional stream from a user agent, you use theWebTransport.createUnidirectionalStream()
method to get a reference to aWritableStream
. From this you canget a writer to allow data to be written to the stream and sent to the server.
async function writeData() { const stream = await transport.createUnidirectionalStream(); const writer = stream.writable.getWriter(); const data1 = new Uint8Array([65, 66, 67]); const data2 = new Uint8Array([68, 69, 70]); writer.write(data1); writer.write(data2); try { await writer.close(); console.log("All data has been sent."); } catch (error) { console.error(`An error occurred: ${error}`); }}
Note also the use of theWritableStreamDefaultWriter.close()
method to close the associated HTTP/3 connection once all data has been sent.
If the server opens a unidirectional stream to transmit data to the client, this can be accessed on the client via theWebTransport.incomingUnidirectionalStreams
property, which returns aReadableStream
ofWebTransportReceiveStream
objects. These can be used to readUint8Array
instances sent by the server.
In this case, the first thing to do is set up a function to read aWebTransportReceiveStream
. These objects inherit from theReadableStream
class, so can be used in just the same way:
async function readData(receiveStream) { const reader = receiveStream.getReader(); while (true) { const { done, value } = await reader.read(); if (done) { break; } // value is a Uint8Array console.log(value); }}
Next, callWebTransport.incomingUnidirectionalStreams
and get a reference to the reader available on theReadableStream
it returns, and then use the reader to read the data from the server. Each chunk is aWebTransportReceiveStream
, and we use thereadFrom()
set up earlier to read them:
async function receiveUnidirectional() { const uds = transport.incomingUnidirectionalStreams; const reader = uds.getReader(); while (true) { const { done, value } = await reader.read(); if (done) { break; } // value is an instance of WebTransportReceiveStream await readData(value); }}
Bidirectional transmission
To open a bidirectional stream from a user agent, you use theWebTransport.createBidirectionalStream()
method to get a reference to aWebTransportBidirectionalStream
.This containsreadable
andwritable
properties returning references toWebTransportReceiveStream
andWebTransportSendStream
instances that can be used to read from and write to the server.
Note:WebTransportBidirectionalStream
is similar toWebTransportDatagramDuplexStream
, except that in that interface thereadable
andwritable
properties areReadableStream
andWritableStream
respectively.
async function setUpBidirectional() { const stream = await transport.createBidirectionalStream(); // stream is a WebTransportBidirectionalStream // stream.readable is a WebTransportReceiveStream const readable = stream.readable; // stream.writable is a WebTransportSendStream const writable = stream.writable; // …}
Reading from theWebTransportReceiveStream
can then be done as follows:
async function readData(readable) { const reader = readable.getReader(); while (true) { const { value, done } = await reader.read(); if (done) { break; } // value is a Uint8Array. console.log(value); }}
And writing to theWebTransportSendStream
can be done like this:
async function writeData(writable) { const writer = writable.getWriter(); const data1 = new Uint8Array([65, 66, 67]); const data2 = new Uint8Array([68, 69, 70]); writer.write(data1); writer.write(data2);}
If the server opens a bidirectional stream to transmit data to and receive it from the client, this can be accessed via theWebTransport.incomingBidirectionalStreams
property, which returns aReadableStream
ofWebTransportBidirectionalStream
objects. Each one can be used to read and writeUint8Array
instances as shown above. However, as with the unidirectional example, you need an initial function to read the bidirectional stream in the first place:
async function receiveBidirectional() { const bds = transport.incomingBidirectionalStreams; const reader = bds.getReader(); while (true) { const { done, value } = await reader.read(); if (done) { break; } // value is an instance of WebTransportBidirectionalStream await readData(value.readable); await writeData(value.writable); }}
Interfaces
WebTransport
Provides functionality to enable a user agent to connect to an HTTP/3 server, initiate reliable and unreliable transport in either or both directions, and close the connection once it is no longer needed.
WebTransportBidirectionalStream
Represents a bidirectional stream created by a server or a client that can be used for reliable transport. Provides access to a
ReadableStream
for reading incoming data, and aWritableStream
for writing outgoing data.WebTransportDatagramDuplexStream
Represents a duplex stream that can be used for unreliable transport of datagrams between client and server. Provides access to a
ReadableStream
for reading incoming datagrams, aWritableStream
for writing outgoing datagrams, and various settings and statistics related to the stream.WebTransportError
Represents an error related to the WebTransport API, which can arise from server errors, network connection problems, or client-initiated abort operations (for example, arising from a
WritableStream.abort()
call).WebTransportReceiveStream
Provides streaming features for an incoming WebTransport unidirectional or bidirectional
WebTransport
stream.WebTransportSendStream
Provides streaming features for an outgoing WebTransport unidirectional or bidirectional
WebTransport
stream.
Examples
For complete examples, see:
Specifications
Specification |
---|
WebTransport # web-transport |