Audience Polls during Live Stream - Flutter
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 see live results instantly.
This guide walks you through how to create, send, and visualize poll results during a livestream.
Step 1: Creating and Publishing a Poll​
To initiate a poll, use the PubSub
object with a POLL
topic. The poll structure should include a question and multiple options. This message will be published to all participants.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class PollHostView extends StatelessWidget {
final Room room;
const PollHostView({required this.room});
void startPoll() {
final pollData = {
"id": DateTime.now().millisecondsSinceEpoch,
"question": "Which feature do you love the most?",
"options": ["Reactions", "Screen Share", "Whiteboard", "Polls"],
"responses": {},
};
room.pubSub.publish(
"POLL",
jsonEncode(pollData),
const PubSubPublishOptions(persist: true),
);
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: startPoll,
child: const Text("Start Poll"),
);
}
}
Step 2: Subscribing to Polls and Displaying Options​
Participants can listen to the POLL topic and render voting options dynamically based on the incoming data.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class PollAudienceView extends StatefulWidget {
final Room room;
const PollAudienceView({required this.room});
@override
State<PollAudienceView> createState() => _PollAudienceViewState();
}
class _PollAudienceViewState extends State<PollAudienceView> {
Map<String, dynamic>? activePoll;
@override
void initState() {
super.initState();
widget.room.pubSub.subscribe("POLL", handlePollReceived);
}
@override
void dispose() {
widget.room.pubSub.unsubscribe("POLL", handlePollReceived);
super.dispose();
}
void handlePollReceived(PubSubMessage message) {
setState(() {
activePoll = jsonDecode(message.message);
});
}
void submitVote(String option) {
if (activePoll != null) {
widget.room.pubSub.publish(
"POLL_RESPONSE",
jsonEncode({
"pollId": activePoll!['id'],
"option": option,
}),
const PubSubPublishOptions(persist: true),
);
}
}
@override
Widget build(BuildContext context) {
if (activePoll == null) return const SizedBox();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
activePoll!['question'],
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
...(activePoll!['options'] as List<dynamic>).map((option) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: ElevatedButton(
onPressed: () => submitVote(option.toString()),
child: Text(option.toString()),
),
);
}).toList(),
],
);
}
}
Step 3: Aggregating and Displaying Poll Results​
The host can subscribe to the POLL_RESPONSE topic to collect responses and render the result in real-time.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class PollResultsView extends StatefulWidget {
final Room room;
const PollResultsView({required this.room});
@override
State<PollResultsView> createState() => _PollResultsViewState();
}
class _PollResultsViewState extends State<PollResultsView> {
final Map<String, Map<String, int>> results = {};
@override
void initState() {
super.initState();
widget.room.pubSub.subscribe("POLL_RESPONSE", handleResponse);
}
@override
void dispose() {
widget.room.pubSub.unsubscribe("POLL_RESPONSE", handleResponse);
super.dispose();
}
void handleResponse(PubSubMessage message) {
final data = jsonDecode(message.message);
final pollId = data['pollId'].toString();
final option = data['option'].toString();
setState(() {
final pollResult = results[pollId] ?? {};
pollResult[option] = (pollResult[option] ?? 0) + 1;
results[pollId] = pollResult;
});
}
@override
Widget build(BuildContext context) {
if (results.isEmpty) return const Text("No poll results yet.");
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: results.entries.map((entry) {
final pollId = entry.key;
final pollResult = entry.value;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Poll ID: $pollId", style: const TextStyle(fontWeight: FontWeight.bold)),
...pollResult.entries.map((e) => Text("${e.key}: ${e.value} votes")).toList(),
const SizedBox(height: 16),
],
);
}).toList(),
);
}
}
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