Data Channels
Data channel is a powerful feature of WebRTC that allows you to exchange arbitrary data between peers in a room. In Peerix , you can open data channels to send messages, files, or any other type of data that does not fit into media streams.
sequenceDiagram
autonumber
Note over Peer A, Peer B: Open a data channel
Peer B ->> Peer A: Is polite?<br>signaling DC: channel + options
Peer A ->> Peer A: Is impolite?<br>Create the data channel
Peer A ->> Peer B: channel event: new
Note over Peer A, Peer B: Channel is created
Opening Data Channels
You can open data channels to exchange arbitrary data with other peers in the room using the open method:
// listen for data channel open event
peer.on("channel:open", (e) => {
const { remote, label } = e;
console.log("Channel was opened with peer:", remote.id, "label:", label);
});
// open a data channel
await peer.open({ label: "chat" });Peerix allows you to open multiple data channels with unique labels. You can also specify options for each channel, such as ordered or unordered message delivery and other channel-specific settings.
Closing Data Channels
To stop exchanging data over a data channel, you can close it specifically by its label:
// listen for data channel close event
peer.on("channel:close", (e) => {
const { remote, label } = e;
console.log("Channel was closed with peer:", remote.id, "label:", label);
});
// close a data channel with a specific label
await peer.close({ label: "chat" });Note
You can open a data channel before or after connecting to a room, and the library will handle the sharing of the channel as needed with other peers in the room.
Sending and Receiving Messages
Use the send method to send messages to all connected peers over open data channels. The send method supports streaming any data through a single channel. Large payloads are automatically chunked and buffered on the wire, so you can transmit files and binary blobs without worrying about maximum message size limits.
On the receiving side, the channel:message event fires as soon as the first chunk arrives. The data payload is a ReadableStream/Promise that you can iterate over to receive chunks incrementally — or consume as a promise to get the fully assembled message when you don’t need progress tracking.
You can use the send method with the message and a channel label:
// send a message to all connected peers
await peer.send("Hello, peers!", { label: "chat" });To listen for incoming messages on a data channel, you can use the channel:message event:
// listen for incoming messages on a specific channel
peer.on("channel:message", async (e) => {
const { remote, label, data } = e;
// you should await data to get the full message
const message = await data;
console.log("Message from:", remote.id, "label:", label, "message:", message);
});The transfer object returned by send is an async iterator. By looping over it, you can observe how much data has been sent at each step. Also, you can provide additional metadata with each message by the info field.
The following example shows how to send a large file to all connected remote peers:
const file = new File([new Uint8Array(1024 * 1024)], "example.dat");
const transfer = peer.send(file, {
label: "chat", // channel label
info: { name: file.name, size: file.size }, // metadata
signal: AbortSignal.timeout(10000), // abort signal
});
// track the progress of the transfer
for await (const progress of transfer) {
const { id, label, current, total } = progress;
const percent = Math.round((current / total) * 100);
console.log(`[${id}:${label}] Sending... ${percent}%`);
}Receiving the file and tracking progress on the other end:
peer.on("channel:message", async (e) => {
const { remote, label, data, info } = e;
let current = 0;
const chunks = [];
// read data by chunks
for await (const chunk of data) {
chunks.push(chunk);
current += chunk.length;
const percent = Math.round((current / info.size) * 100);
console.log(`[${remote.id}:${label}] Receiving... ${percent}%`);
}
const file = new File(chunks, info.name);
console.log("Received:", file);
// cancel the stream if needed
// data.cancel();
});You can cancel a transmission at any time using AbortSignal. The example above uses AbortSignal.timeout(10000) to auto-cancel after 10 seconds, but you can also create an AbortController and call .abort() manually whenever your application logic dictates.
Cancellation works on the receiver side as well. Since incoming data is a ReadableStream, you can call data.cancel() at any point during iteration to stop receiving further chunks.
Selective Operations
Peerix allows you to open, close, send messages and listen for events on specific peer connections, rather than on all of them in the room.
To send a message to a specific peer over a data channel, you can get the remote peer instance and use the send method with the message:
const remote = peer.connections.get("peer-id");
if (remote) {
await remote.send("Hello, peer!", { label: "chat" });
}The same way you can use the open and close methods on the remote peer instance and listen for events with the remote.on method to handle data channels with specific peers in the room.
Please note that these operations continue to run as long as the peer connection is established. If the connection is closed, you will need to open the data channels again to exchange data with that peer, even if they reconnect later.