Data Channel - Flutter
The data channel sends text or binary data to all other participants in the room with low delay. Use it for live data that matters only at that moment, such as cursor positions, reactions, typing indicators or game moves.
Messages are not stored on the server. A participant who joins later does not receive the messages that were sent before they joined.
Data Channel or PubSub
Both send messages to other participants. Choose by what your messages need.
| Data channel | PubSub | |
|---|---|---|
| Who receives a message | All other participants | Participants subscribed to the topic. With sendOnly, only the participants you list. |
| Kept for participants who join later | No | Yes, when you publish with persist: true |
| Content | A String or a List<int>, up to 15 KiB | A String message, with an optional payload map |
| Unreliable delivery | Yes, with reliable: false | No |
Send a message
The send() method of the Room class sends a String or a List<int> to all other participants.
- Call it after the
roomJoinedevent, and await it insidetry/catch. reliable: true, the default, resends a message until it arrives, and messages arrive in the order you sent them.reliable: falsesends a message once. It can be lost or arrive out of order, so use it for data where a newer message replaces an older one, such as cursor positions.- A message can be at most 15 KiB. For text, this is the size of the string in UTF-8.
- Only participants in
Mode.SEND_AND_RECVcan send.
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:videosdk/videosdk.dart';
// Send text, reliably and in order
Future<void> sendHello(Room room) async {
try {
await room.send("Hello everyone");
} on VideoSDKError catch (error) {
debugPrint("Message not sent: ${error.code} ${error.name}");
}
}
// Send binary data once. A newer position replaces a lost one.
Future<void> sendCursorPosition(Room room, double x, double y) async {
final List<int> bytes = utf8.encode(jsonEncode({'x': x, 'y': y}));
try {
await room.send(bytes, reliable: false);
} on VideoSDKError catch (error) {
debugPrint("Position not sent: ${error.code} ${error.name}");
}
}
Errors
When the message is not sent, send() throws a VideoSDKError:
| Error | When |
|---|---|
UNKNOWN_ERROR (4000) | Before you call join(). |
ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED (3035) | While the room is joining, or after it has left. |
ERROR_ROOM_RECONNECTING (3065) | While the room reconnects. Send the message again after it reconnects. |
ERROR_ACTION_NOT_SUPPORTED_IN_MODE (3066) | In Mode.RECV_ONLY or Mode.SIGNALLING_ONLY. |
ERROR_PAYLOAD_TOO_LARGE (3072) | The message is larger than 15 KiB. |
ERROR_MEDIA_NOT_READY (3048) | The data channel is not open yet. |
ERROR_OPERATION_TIMED_OUT (3079) | The data channel did not open in time. |
ERROR_SEND_FAILED (3070) | The data channel could not send the message. |
Some of these failures, such as 3070, are also reported on the error event of the room. Handle each failure in one place. A message that is neither a String nor a List<int> throws an ArgumentError.
Receive messages
The dataReceived event of the Room class fires for every message that another participant sends. You do not receive the messages that you send. Add the handler before you call join(), so that you do not miss any message.
The DataMessage it receives has these properties:
senderId: The id of the participant who sent the message.isBinary:truewhen the sender sent aList<int>.text: The text, whenisBinaryisfalse.nullfor binary data.data: The binary data as aUint8List, ornullfor text.reliable:truewhen the sender used reliable delivery.timestamp: When the message was sent, in milliseconds.
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:videosdk/videosdk.dart';
void listenForData(Room room) {
room.on(Events.dataReceived, (DataMessage message) {
if (message.isBinary) {
final Uint8List? bytes = message.data;
if (bytes == null) return;
final Map<String, dynamic> position = jsonDecode(utf8.decode(bytes));
debugPrint("${message.senderId} moved the cursor to ${position['x']}, ${position['y']}");
} else {
debugPrint("${message.senderId}: ${message.text}");
}
});
}
API Reference
The API references for all the methods and events utilized in this guide are provided below.
Got a Question? Ask us on discord

