PubSub - Flutter
PubSub is a short acronym for Publish-Subscribe mechanism. This mechanism is used to send and recieve messages from a particular topic. As the name suggests, for someone to send a message, they have to specify the topic and the message which should be published and for someone to receive a message, they should be subscribed to that topic.
Here is a visual to better understand publish-subscribe mechanism.

PubSub
In order to use PubSub in a meeting, VideoSDK provides the pubSub property on the Room object, which allows you to subscribe to any topic and publish to any topic, allowing you to pass on messages and instructions during the meeting easily.
From v4.x, publish(), subscribe() and unsubscribe() throw a PubSubException when the call does not take effect. Every call site needs a catch or a .catchError — see Handling failures below and section 1 of the Migration Guide.
publish()
- This method is used for publishing message of specific topic.
- This method can be accessed from the
pubSubfrom theRoom. - This method will accept following parameters as input:
topic: This will be the topic where the message will be published.message: This will be the actual message to be published. It has to be inStringformat.options: This is an object ofPubSubPublishOptionswhich specifies the options for publish.PubSubPublishOptionshas 2 properties.persist:persistoffered the option of keeping the message around for the duration of the session. Whenpersistis set totrue, that message will be retained for upcoming participants and will be available in VideoSDK Session Dashboard with.CSVformat after completion of session.sendOnly: If you want to send a message to specific participants, you can pass their respectiveparticipantIdin form ofList<String>. If you don't provide any IDs, the message will be sent to all participants by default. This is optional parameter.
payload: If you need to include additional information along with a message, you can pass here asMap<String, dynamic>. This is optional parameter.
- From v4.x the returned
Futurecompletes once the server has acknowledged the message, and throws aPubSubExceptionif the publish is rejected or is not acknowledged within 30 seconds.
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class MeetingScreen extends StatefulWidget {
...
}
class _MeetingScreenState extends State<MeetingScreen> {
late Room _room;
@override
void initState() {
...
}
@override
Widget build(BuildContext context) {
return Column(
children:[
//These will publish "Hello World!" on the "CHAT" topic
ElevatedButton(
onPressed:() async {
try {
await _room.pubSub.publish("CHAT", "Hello World!");
} on PubSubException catch (e) {
// Not sent — mark the message unsent or offer a retry here.
debugPrint("Publish failed: ${e.message}");
}
},
child: const Text("Send Message"),
),
]
);
}
}
Receiving the messages
-
All the previous messages for the particular topic can be recieved by subscribing to the topic.
-
To subscribe to a specific topic, use can use the
subscribe()method which will return theFuture<PubSubMessages>and accepts thetopicto be subscribed and acallback functionwhich will be called when ever any new message is received. -
PubSubMessagescontains themessagesas a list ofPubSubMessagewhich will contain following properties:senderId: This represents theparticipantIdof the participant who send the message.senderName: This represents thedisplayNameof the participant who send the message.message: This will be the acatual message that was send.timestamp: This wil the timestamp for when the message was published.topic: This will be the name of the topic message was published to.payload: This will be the data that you have send with message.sendOnly: This will be the list ofparticipantIds the message was addressed to, when it was published withPubSubPublishOptions.sendOnly. It is empty for a message that was broadcast to everyone on the topic.
-
A subscription survives a reconnect — subscribe once and it keeps working after the connection recovers, without subscribing again.
Subscription options and callbacks
From v4.x, subscribe() also accepts options and three optional callbacks that control how much history is replayed and how live messages are delivered on a busy topic.
room.pubSub.subscribe(
"CHAT",
messageHandler,
options: const PubSubSubscribeOptions(
oldMessageLimit: 100,
realtimeOverflow: PubSubRealtimeOverflow.queue,
maxQueue: 70,
),
onOldMessagesReceived: (messages, isLast) {
// Past messages, oldest first, so a long conversation starts rendering
// before all of it has arrived. isLast is true on the final batch.
},
onBatchReceived: (messages) {
// On a busy topic live messages arrive in groups.
},
onMessageDrop: (count) {
// This many live messages could not be delivered.
},
);
oldMessageLimit: How many stored messages are replayed when you subscribe.nullreplays all of them,0replays none, andN > 0replays the last N. Only messages published withpersistenabled are stored at all.realtimeOverflow: What happens to live messages arriving faster than they can be delivered.PubSubRealtimeOverflow.queuebriefly holds them so a subscriber that falls behind can catch up;PubSubRealtimeOverflow.dropdiscards them. Usedroponly where stale data has no value, such as typing indicators.maxQueue: How far a subscriber may fall behind, counted in delivery batches, before the server gives up on it. Only allowed withPubSubRealtimeOverflow.queue.newMessageLimit: Caps how many live messages this subscriber accepts at a time.
An out-of-range value makes subscribe() throw an ArgumentError before anything is sent — the same rules iOS and Android enforce:
| Rule | Example that throws |
|---|---|
oldMessageLimit must be >= 0, or null for all history | oldMessageLimit: -1 |
maxQueue must be >= 1 | maxQueue: 0 |
newMessageLimit must be >= 0, or null for unlimited | newMessageLimit: -5 |
maxQueue is not allowed with PubSubRealtimeOverflow.drop | realtimeOverflow: PubSubRealtimeOverflow.drop, maxQueue: 70 |
An ArgumentError is not a PubSubException, so on PubSubException catch will not catch it and it never reaches Events.error. These are programming errors — fix the call rather than handle it at runtime.
Handling failures
From v4.x, publish(), subscribe() and unsubscribe() throw a PubSubException when the call does not take effect. In v3.x.x they failed silently, and Dart cannot flag an unhandled one at compile time — an unawaited onPressed: () => room.pubSub.publish(...) turns a failure into a runtime async error. Give every call site a catch or a .catchError.
| Situation | Exception | Code |
|---|---|---|
publish() was rejected | PubSubPublishFailed | 4087 |
subscribe() was rejected | PubSubSubscribeFailed | 4088 |
unsubscribe() was rejected | PubSubUnsubscribeFailed | 4089 |
| Called before joining, or after leaving | PubSubMeetingNotJoined | 3022 |
| Called while reconnecting | PubSubMeetingReconnecting | 3027 |
PubSubException is sealed, so a switch over these is exhaustive and the analyzer tells you when a case is missing. It carries code, name and message.
try {
await room.pubSub.publish("CHAT", text);
} on PubSubException catch (e) {
switch (e) {
case PubSubMeetingNotJoined():
showToast("Join the meeting before publishing");
case PubSubMeetingReconnecting():
showToast("Reconnecting — try again shortly");
case PubSubPublishFailed():
markUnsent(id, e.message);
default:
debugPrint(e.toString());
}
}
The same failure is also delivered to Events.error with the same code, name and message. Catch to handle one call; listen on the event for centralized logging.
A few things behave differently from what you might expect:
- A failed
subscribe()leaves nothing behind. Your handler is not registered, so no messages arrive for that topic. unsubscribe()detaches your handler before anything that can throw, so adispose()teardown always completes. From v4.x it also waits for the server to answer, bounded by the same 30 second timeout aspublish().- Not every failure can throw. A subscription the server drops later, or one that cannot be restored after a reconnect, has no call left to throw from and reaches you on
Events.erroronly. Keep that listener if your UI shows subscription state. - Using
.catchError()onsubscribe()? It returnsFuture<PubSubMessages>, so the callback has to return a value —PubSubMessages(messages: const [])will do.
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class ChatView extends StatefulWidget {
final Room room;
...
}
class _ChatViewState extends State<ChatView> {
// PubSubMessages
PubSubMessages? messages;
@override
void initState() {
...
// Subscribing 'CHAT' Topic
widget.meeting.pubSub
.subscribe("CHAT", messageHandler)
.then((value) => setState((() => messages = value)))
// initState() cannot await, so failures are caught here.
.catchError((Object e) => debugPrint("Subscribe failed: $e"));
}
//Handler which will be called when new mesasge is received
void messageHandler(PubSubMessage message) {
setState(() => messages!.messages.add(message));
}
@override
Widget build(BuildContext context) {
return Column(
children:[
Expanded(
child: messages == null
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
reverse: true,
child: Column(
children: messages!.messages
.map(
(message) => Text(
message.message
),
)
.toList(),
),
),
),
]
);
}
@override
void dispose() {
// Unsubscribe. dispose() cannot await, so the failure is logged instead.
widget.room.pubSub
.unsubscribe("CHAT", messageHandler)
.catchError((Object e) => debugPrint("Unsubscribe failed: $e"));
super.dispose();
}
}
Applications of PubSub
PubSub is a very powerful mechanism which can be used to do alot of things which can make your meeting experience much more interactive. Some of the most common usecase that we have come across for the PubSub during a meeting are listed below:
Chat: You can utilise this to develop various Chat features, such as Private Chat and Group Chat. You can follow our chat integration guide here.Raise Hand: You can allow attendees to raise their hands at any time during the meeting, informing everyone else that someone has done so.Layout Switching: You can change the meeting's layout for every participant at once during the meeting, such as from Grid layout to Spotlight or Grid Layout to Sidebar Layout, etc.Poll: You may make polls, let users respond to them, and display the results at the end of a poll.Question Answer Session: You can also design interactive functionality that is question-and-answer based.
Downloading PubSub Messages
All the messages from the PubSub which were published with persist : true and can be downloaded as an .csv file. This file will be available in the VideoSDK dashboard as well as throught the Sessions API.
API Reference
The API references for all the methods and events utilised in this guide are provided below.
Got a Question? Ask us on discord

