PubSub - iOS
PubSub is a short acronym for Publish-Subscribe mechanism. This mechanism is used to send and receive 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 room, VideoSDK provides the PubSub class, available as room.pubSub, which allows you to subscribe to any topic and publish to any topic allowing to pass on messages and instructions in the room easily.
publish()
- This method is used for publishing message of specific topic.
- This method can be accessed from
room.pubSub. It isasync throws, so call it withtry await. - This method will accept following parameters as input:
topic: This will be the topic for which you are publishing a message.message: This will be the actual message to be published. It has to be inStringformat.options: This is aPubSubPublishOptionsvalue with 2 properties. It is optional.persist:persistkeeps the message 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. Default:false.sendOnly: If you want to send a message to specific participants, you can pass their respectiveparticipantIdas a[String]. If you leave itnil, the default, the message will be sent to all participants.
payload: Optional[String: Any]data sent along with the message. Subscribers receive it in the message'spayload.
- Swift
//Button that will send the message when tapped
@IBAction func sendMessageTapped(_ sender: Any) {
let options = PubSubPublishOptions(persist: true)
// publish message
Task {
do {
try await self.room?.pubSub.publish(topic: "CHAT", message: "How are you?", options: options)
} catch {
print("error while publish: \(error)")
}
}
}
subscribe()
-
This method is used to subscribe for particular topic.
-
room.pubSub.subscribe(topic:listener:options:)accepts a listener and optionalPubSubSubscribeOptions. It isasync throws. All messages — realtime and old — are delivered exclusively through the listener callbacks; nothing is returned from the awaited call. -
This method will accept following parameters as input:
-
topic: This will be the topic to be subscribed. -
listener: This is an object ofPubSubMessageListenercontaining listener callbacks:-
onMessageReceived(_:)— Called for every realtime message as soon as it is received.- Use this when: You want to handle each message individually, such as appending it to a chat, triggering a notification, or updating message-specific state.
- Don't use this when: The topic is high-throughput / large-scale (busy chats, live reactions, cursor positions). Firing once per message causes excessive re-renders and state updates — use
onBatchReceivedinstead.
-
onBatchReceived(_:)— Called with an array of realtime messages. These are the same messages delivered throughonMessageReceived, but grouped into a single batch.- Use this when: Processing messages in bulk is more efficient, such as performing a single state update or rendering a large list of messages.
-
onOldMessagesReceived(_:info:)— Called with persisted history in batches — fires once per batch until history is fully delivered. Only messages published withpersist: trueare delivered here.info.isLastistrueon the final batch. If the topic has no old messages, it is not called.- Use this when: Loading chat history or restoring previously sent messages when a participant joins the room.
-
onMessageDrop(_:)— Called when incoming realtime messages cannot be delivered. This can happen:- because the client cannot keep up with the incoming message rate (for example, due to a slow network or high CPU usage), causing overflow, or
- because
newMessageLimitis configured, which intentionally limits how many realtime messages are delivered every 500 ms. Any messages exceeding the configured limit within that window are discarded.
info.droppedCountcontains the number of messages that were not delivered.- Use this when: Notifying users that some realtime messages were missed, monitoring the effects of
newMessageLimit, or logging dropped messages for debugging and observability.
-
-
options: This is an object ofPubSubSubscribeOptions. Build it withPubSubSubscribeOptions(oldMessageLimit:realtimeOverflow:maxQueue:newMessageLimit:), or createPubSubSubscribeOptions()and set its properties:-
oldMessageLimit(Int?) — how many old messages to receive. Pass0to receive none. If you leave itnil, all old messages are delivered. Default: all.- When to use: Cap the history for large sessions where loading every persisted message would be wasteful (e.g. only the last 50 messages need to appear when a participant joins).
-
realtimeOverflow(RealtimeOverflow Enum) — behavior when your internet is slow or your device can't keep up.RealtimeOverflow.QUEUE(default) queues remaining messages so you receive them once you catch up;RealtimeOverflow.DROPdrops them instead.- When to use: Use
RealtimeOverflow.QUEUEfor chat where every message matters. UseRealtimeOverflow.DROPfor high-frequency, low-value streams (live reactions, cursor positions) where stale data is worse than missing data.
- When to use: Use
-
maxQueue(Int?) — maximum number of message batches to queue during overflow. Leave itnil(the default) to let the server decide; the server default is70and the maximum is200. Only valid withrealtimeOverflow: .QUEUE.- When to use: Increase this value when you want to retain more messages and catch up after recovering from a slow network or CPU spike. Lower it if memory pressure matters more than history.
-
newMessageLimit(Int) — maximum number of realtime messages to receive per 500 ms.- When to use: Set this when you want to render only a particular number of messages per second — for example, throttle a busy chat topic so the UI doesn't jank, or rate-limit a reactions topic.
-
-
If you call subscribe() again on the same topic with a different listener, the values of realtimeOverflow, maxQueue, and newMessageLimit are overridden by the latest subscribe() call. Other options (such as oldMessageLimit) are not affected.
Every message delivered to the listener contains the following fields:
id— unique identifier for the message.message— the actual message content that was sent.senderId—participantIdof the participant who sent the message.senderName—displayNameof the participant who sent the message.timestamp— the timestamp indicating when the message was published.topic— the topic the message was published to.payload— any additional data sent along with the message (optional).sendOnly— the participant IDs the message was sent to. It is empty when the message was sent to everyone.
- Swift
extension RoomViewController: RoomEventListener {
/// Room joined
func onRoomJoined() {
Task {
var demoOptions = PubSubSubscribeOptions()
demoOptions.oldMessageLimit = 50
demoOptions.realtimeOverflow = .QUEUE
demoOptions.maxQueue = 70
demoOptions.newMessageLimit = 20
do {
try await room?.pubSub.subscribe(
topic: "CHAT",
listener: self,
options: demoOptions
)
} catch {
print("CHAT subscribe failed: \(error)")
}
}
}
}
extension RoomViewController: PubSubMessageListener {
// read message when it is received
func onMessageReceived(_ message: PubSubMessage) {
print("Message Received: " + message.message)
}
func onBatchReceived(_ messages: [VideoSDKRTC.PubSubMessage]) {
// Handle a batch of realtime messages together
print("Batch messages: \(messages.count)")
}
func onOldMessagesReceived(_ messages: [VideoSDKRTC.PubSubMessage], info: PubSubHistoryInfo) {
print("onOldMessagesReceived: \(messages.count) | isLast: \(info.isLast)")
}
func onMessageDrop(_ info: PubSubMessageDropInfo) {
// Called when incoming messages are dropped
print("\(info.droppedCount) message(s) dropped")
}
}
unsubscribe()
-
This method is used to unsubscribe for particular topic.
-
This method will accept two parameters as input:
topic: This will be the topic to be unsubscribed.listener: This is an object ofPubSubMessageListener, which was passed insubscribe().
-
Call it before you leave the room. After you leave, it can fail with
ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED.
- Swift
func unsubscribe() {
//unsubscribe from the topic 'CHAT' when you no longer need it
Task {
do {
try await self.room?.pubSub.unsubscribe(topic: "CHAT", listener: self)
} catch {
print("unsubscribe failed: \(error)")
}
}
}
Errors
All PubSub methods are async throws. Every failure is thrown as a VideoSDKError, so catch it with catch let error as VideoSDKError and read its code, name and message.
publish() throws:
ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED— the operation was attempted before the room was joined (or after it left).ERROR_ROOM_RECONNECTING— the room is reconnecting. Retry once it reconnects.PUBSUB_PUBLISH_FAILED— the publish failed, for example because it timed out. Themessageholds the reason.
subscribe() throws:
ERROR_INVALID_PARAMETER— the options are invalid, or this listener is already subscribed to the topic.- The options are invalid when
oldMessageLimitornewMessageLimitis negative,maxQueueis less than1, ormaxQueueis set whilerealtimeOverflowis.DROP. - A listener can subscribe to a topic only once.
unsubscribe()first if you need to re-subscribe. If you need to listen to the messages in different places, create another listener and callsubscribe()with it.
- The options are invalid when
ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED— the operation was attempted before the room was joined (or after it left).ERROR_ROOM_RECONNECTING— the room is reconnecting. Retry once it reconnects.PUBSUB_SUBSCRIBE_FAILED— the subscribe failed. Themessageholds the reason.
unsubscribe() throws:
ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED,ERROR_ROOM_RECONNECTINGorPUBSUB_UNSUBSCRIBE_FAILED— the topic could not be unsubscribed on the server. This can happen only when you remove the topic's last listener. The listener stops receiving messages either way. Unsubscribing a listener that is not subscribed does nothing.
ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED and the PUBSUB_*_FAILED errors are also sent to onError(error:), so don't show them to the user twice.
Applications of PubSub
Common uses of PubSub in a room 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 in the room, informing everyone else that someone has done so.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.
For live data that matters only at the moment it is sent, such as cursor positions, use the Data Channel instead. Its messages have no topic and are not stored on the server.
Downloading PubSub Messages
All PubSub messages published with persist: true can be downloaded as a .csv file. This file is available in the VideoSDK dashboard and through 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

