Sending data between two browsers for communication, gaming, or file transfer can be a rather involved process. It requires setting up and paying for a server to relay data, and perhaps scaling this to multiple data centers. In this scenario there is potential for high latency, and it's difficult to keep data private.

These problems can be alleviated by using WebRTC's RTCDataChannel API to transfer data directly from one peer to another. In this article we will cover the basics of how to set up and use data channels, as well as the common use cases on the web today.

To make the most of this article, you will need to have some knowledge of the RTCPeerConnection API, and an understanding of how STUN, TURN, and signaling work. We recommend you take a look at Getting Started With WebRTC.

Why another data channel?

We have WebSocket, AJAX and Server Sent Events. Why do we need another communication channel? WebSocket is bidirectional, but all these technologies are designed for communication to or from a server.

RTCDataChannel takes a different approach:

It works with the RTCPeerConnection API, which enables peer to peer connectivity. This can result in lower latency: no intermediary server, fewer 'hops'.

RTCDataChannel uses Stream Control Transmission Protocol (SCTP), allowing configurable delivery semantics: out-of-order delivery and retransmit configuration.

RTCDataChannel is available now, with SCTP support, in Chrome, Opera and Firefox for desktop and Android.

A caveat: signaling, STUN and TURN

Although WebRTC enables peer-to-peer communication, it still needs servers:

For signaling: to enable the exchange of media and network metadata to bootstrap a peer connection.

to enable the exchange of media and network metadata to bootstrap a peer connection. To cope with NATs and firewalls: by using the ICE framework to establish the best possible network path between peers, by working with STUN servers (to ascertain a publicly accessible IP and port for each peer) and TURN servers (if direct connection fails and data relaying is required).

The HTML5 Rocks article WebRTC in the real world: STUN, TURN, and signaling explains in detail how WebRTC works with servers for signaling and networking.

The capabilities

The RTCDataChannel API supports a flexible set of data types. The API is designed to mimic WebSocket exactly, and RTCDataChannel supports strings as well as some of the binary types in JavaScript such as Blob, ArrayBuffer and ArrayBufferView. These types can be helpful when working with file transfer and multiplayer gaming.

TCP UDP SCTP Reliability reliable unreliable configurable Delivery ordered unordered configurable Transmission byte-oriented message-oriented message-oriented Flow control yes no yes Congestion control yes no yes

(From High Performance Browser Networking by Ilya Grigorik.)

RTCDataChannel can work in unreliable and unordered mode (analogous to User Datagram Protocol or UDP), reliable and ordered mode (analogous to Transmission Control Protocol or TCP) and partial reliable modes:

Reliable and ordered mode guarantees the transmission of messages and also the order in which they are delivered. This takes extra overhead, thus potentially making this mode slower.

guarantees the transmission of messages and also the order in which they are delivered. This takes extra overhead, thus potentially making this mode slower. Unreliable and unordered mode does not guarantee every message will get to the other side nor what order they get there. This removes the overhead, allowing this mode to work much faster.

does not guarantee every message will get to the other side nor what order they get there. This removes the overhead, allowing this mode to work much faster. Partial reliable mode guarantees the transmission of message under a specific condition (such as a retransmit timeout or a maximum amount of retransmissions). The ordering of messages is also configurable.

Performance for the first two modes is about the same when there are no packet losses. However, in reliable and ordered mode a lost packet will cause other packets to get blocked behind it, and the lost packet might be stale by the time it is retransmitted and arrives. It is, of course, possible to use multiple data channels within the same application, each with their own (un)reliable semantics.

We show below how to configure RTCDataChannel to use reliable and ordered or unreliable and unordered mode.

Configuring data channels

There are several simple demos of RTCDataChannel online:

In these examples the browser is making a peer connection to itself. It is then creating a data channel and sending the message along the peer connection. Finally, your message appears in the box on the other side of the page!

The code to get started with this is short:

const peerConnection = new RTCPeerConnection(); // Establish your peer connection using your signaling channel here const dataChannel = peerConnection.createDataChannel("myLabel", dataChannelOptions); dataChannel.onerror = (error) => { console.log("Data Channel Error:", error); }; dataChannel.onmessage = (event) => { console.log("Got Data Channel Message:", event.data); }; dataChannel.onopen = () => { dataChannel.send("Hello World!"); }; dataChannel.onclose = () => { console.log("The Data Channel is Closed"); };

The dataChannel object is created from an already established peer connection. It can be created before or after signaling happens. You then pass in a label to distinguish this channel from others and a set of optional configuration settings:

const dataChannelOptions = { ordered: false, // do not guarantee order maxPacketLifeTime: 3000, // in milliseconds };

It is also possible to add a maxRetransmits option (the number of times to try before failing) but you can only specify maxRetransmits or maxPacketLifeTime, not both. For UDP semantics, set maxRetransmits to 0 and ordered to false . For more information, see RFC 4960 (SCTP) and RFC 3758 (SCTP partial reliability).

ordered: If the data channel should guarantee order or not

If the data channel should guarantee order or not maxPacketLifeTime: The maximum time to try and retransmit a failed message

The maximum time to try and retransmit a failed message maxRetransmits: The maximum number of times to try and retransmit a failed message

The maximum number of times to try and retransmit a failed message protocol: Allows a subprotocol to be used which provides meta information towards the application

Allows a subprotocol to be used which provides meta information towards the application negotiated: If set to true, it removes the automatic setting up of a data channel on the other peer, meaning that you are provided your own way to create a data channel with the same id on the other side

If set to true, it removes the automatic setting up of a data channel on the other peer, meaning that you are provided your own way to create a data channel with the same id on the other side id: Allows you to provide your own ID for the channel (can only be used in combination with negotiated set to true )

The only options most people will need to use are the first three: ordered , maxPacketLifeTime , and maxRetransmits . With SCTP (now used by all browsers that support WebRTC) reliable and ordered is true by default. It makes sense to use unreliable and unordered if you want full control from the application layer, but in most cases, partial reliability is helpful.

Note that, as with WebSocket, RTCDataChannel fires events when a connection is established, closed, or errors, and when it receives a message from the other peer.

Is it safe?

Encryption is mandatory for all WebRTC components. With RTCDataChannel all data is secured with Datagram Transport Layer Security (DTLS). DTLS is a derivative of SSL, meaning your data will be as secure as using any standard SSL based connection. DTLS is standardized and built in to all browsers that support WebRTC. You can find more information about DTLS on the Wireshark wiki.

Change how you think about data

Handling large amounts of data can be a pain point in JavaScript. As the developers of Sharefest pointed out, this required thinking about data in a new way. If you are transferring a file that is larger than the amount of memory you have available you have to think about new ways to save this information. This is where technologies such as the FileSystem API come into play, as we show below.

Build a file sharing application

Creating a web application that can share files in the browser is now possible with RTCDataChannel. Building on top of RTCDataChannel means that the transferred file data is encrypted and does not touch an application provider's servers. This functionality, combined with the possibility of connecting to multiple clients for faster sharing, makes WebRTC file sharing a strong candidate for the web.

Several steps are required to make a successful transfer:

Read a file in JavaScript using the File API Make a peer connection between clients, using RTCPeerConnection. Create a data channel between clients, using RTCDataChannel.

There are several points to consider when trying to send files over RTCDataChannel:

File size: if file size is reasonably small and can be stored and loaded as one Blob, you can load into memory using the File API and then send the file over a reliable channel as is (though bear in mind that browsers impose limits on maximum transfer size). As file size get larger, things get trickier. A chunking mechanism is required: file chunks are loaded and sent to another peer, accompanied with chunkId metadata so the peer can recognize them. Note that in this case you will also need to save the chunks first to offline storage (for example, using the FileSystem API) and only when you have the file in its entirety save it to the user's disk.

if file size is reasonably small and can be stored and loaded as one Blob, you can load into memory using the File API and then send the file over a reliable channel as is (though bear in mind that browsers impose limits on maximum transfer size). As file size get larger, things get trickier. A chunking mechanism is required: file chunks are loaded and sent to another peer, accompanied with chunkId metadata so the peer can recognize them. Note that in this case you will also need to save the chunks first to offline storage (for example, using the FileSystem API) and only when you have the file in its entirety save it to the user's disk. Chunk size: these are the smallest 'atoms' of data for your application. Chunking is required, since there is currently a send size limit (though this will be fixed in a future version of data channels). The current recommendation for maximum chunk size is 64 KiB.

Once the file is fully transferred to the other side, it can be downloaded using an anchor tag:

function saveFile(blob) { const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = 'File Name'; link.click(); };

The file sharing apps at pubnub.github.io/rtc-pubnub-fileshare and github.com/Peer5/ShareFest use this technique; they are both open source and provide a good foundation for a file sharing application based on RTCDataChannel.

So what can we do?

RTCDataChannel opens the doors to new ways to build apps for file sharing, multiplayer gaming, and content delivery.

Peer to peer file sharing as described above.

Multiplayer gaming, paired with other technologies like WebGL, as seen in Mozilla's Banana Bread.

Content delivery: as being reinvented by PeerCDN, a framework that delivers web assets through peer to peer data communication.

Change the way you build applications

We can now provide more engaging applications by using high performance, low latency connections via RTCDataChannel. Frameworks such as PeerJS and the PubNub WebRTC SDK make RTCDataChannel easier to implement, and the API now has wide support across platforms.

The advent of RTCDataChannel can change the way we think about data transfer in the browser.

Find out more

Thanks to Hadar Weiss and Shachar Zohar for their help in preparing this article.