Skip to main content
Version: 2.x.x

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