Skip to main content
Version: 4.x.x

Audience Polls during Live Stream - iOS

Interactive polls are a great way to increase engagement during livestreams. Using VideoSDK’s PubSub mechanism, you can easily implement real-time audience polling, where viewers can vote and the host can see live results instantly.

This guide walks you through how to create, send, and visualize poll results during a livestream.

note

PubSub works only after the livestream is joined, so the view controllers below expect room to be joined already. PubSub methods are async throws, so call them with try await inside a Task. PubSub lists the errors each method throws.

Step 1: Creating and Publishing a Poll​

The host initiates a poll by publishing a message to the POLL topic using the publish() method of the pubSub property from the Room class. The poll message includes a unique identifier, a question, and multiple options. Setting the persist option to true ensures that the poll message is retained and delivered to participants who join the room later.

PollHostViewController.swift
import UIKit
import VideoSDKRTC

class PollHostViewController: UIViewController {
var room: Room!

@IBAction func startPollTapped(_ sender: UIButton) {
let pollData: [String: Any] = [
"id": "\(Date().timeIntervalSince1970)",
"question": "Which feature do you love the most?",
"options": ["Reactions", "Screen Share", "Whiteboard", "Polls"]
]
let options = PubSubPublishOptions(persist: true)
if let pollMessage = try? JSONSerialization.data(withJSONObject: pollData, options: []),
let pollString = String(data: pollMessage, encoding: .utf8) {
Task {
do {
try await room.pubSub.publish(topic: "POLL", message: pollString, options: options)
} catch {
print("Error while publish: \(error)")
}
}

}
}
}

Step 2: Subscribing to Polls and Displaying Options​

Participants subscribe to the POLL topic using the subscribe() method of the pubSub property. Upon receiving a new poll message, they can parse the content and render the voting options dynamically. The senderId of the received poll message identifies the host. Publish the vote with sendOnly set to that id, so only the host receives it and other participants can't see who voted for what.

A poll that was published before the participant subscribed arrives in onOldMessagesReceived(_:info:), not in onMessageReceived(_:). Implement that callback too if participants who join later should see the current poll.

import UIKit
import VideoSDKRTC

class PollParticipantViewController: UIViewController, PubSubMessageListener {
var room: Room!
var currentPoll: [String: Any]?
var hostId: String?

override func viewDidLoad() {
super.viewDidLoad()
Task {
do {
try await room.pubSub.subscribe(topic: "POLL", listener: self)
} catch {
print("Error while subscribe: \(error)")
}
}
}

func onMessageReceived(_ message: PubSubMessage) {
if let data = message.message.data(using: .utf8),
let poll = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
currentPoll = poll
hostId = message.senderId
DispatchQueue.main.async {
self.displayPoll(poll)
}
}
}

func displayPoll(_ poll: [String: Any]) {
// Implement UI to display poll question and options
// For each option, add a button that calls submitVote(option:)
}

func submitVote(option: String) {
guard let pollId = currentPoll?["id"] as? String, let hostId = hostId else { return }
let response: [String: Any] = [
"pollId": pollId,
"option": option
]
if let responseData = try? JSONSerialization.data(withJSONObject: response, options: []),
let responseString = String(data: responseData, encoding: .utf8) {
let options = PubSubPublishOptions(sendOnly: [hostId])
Task {
do {
try await room.pubSub.publish(topic: "POLL_RESPONSE", message: responseString, options: options)
} catch {
print("Error while publish: \(error)")
}
}
}
}
}

Step 3: Aggregating and Displaying Poll Results​

The host subscribes to the POLL_RESPONSE topic to collect participants' responses in real-time. By parsing each incoming message, the host can aggregate the results and update the UI accordingly.

import UIKit
import VideoSDKRTC

class PollResultsViewController: UIViewController, PubSubMessageListener {
var room: Room!
var pollResults: [String: [String: Int]] = [:] // [pollId: [option: count]]

override func viewDidLoad() {
super.viewDidLoad()
Task {
do {
try await room.pubSub.subscribe(topic: "POLL_RESPONSE", listener: self)
} catch {
print("Error while subscribe: \(error)")
}
}
}

func onMessageReceived(_ message: PubSubMessage) {
if let data = message.message.data(using: .utf8),
let response = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let pollId = response["pollId"] as? String,
let option = response["option"] as? String {
var results = pollResults[pollId] ?? [:]
results[option] = (results[option] ?? 0) + 1
pollResults[pollId] = results
DispatchQueue.main.async {
self.updateResultsUI(for: pollId)
}
}
}

func updateResultsUI(for pollId: String) {
// Implement UI update to display poll results
}
}

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