Live polls & score predictions

Engagement is a key driver of success in live sports, media streaming, and interactive user apps. Real-time polling keeps fans and users connected, enhancing the experience with instantaneous feedback and predictions. By the end of this document, you will:

  • Understand how to implement real-time polling in your application
  • Learn how to create and manage polls efficiently
  • Enhance engagement with different types of polls and predictions
  • Discover how to handle poll results and user feedback
  • Implement secure and scalable polling systems

How PubNub helps

PubNub provides a robust infrastructure for implementing real-time polling systems. The platform's features enable you to create engaging polling experiences that scale globally.

Role in the solutionPubNub feature (click to learn more!)
  • Create and announce polls
  • Collect votes
  • Publish results
Pub/Sub
  • Store important polls
  • Access historical poll data
Message Storage
  • Secure channel access
  • Manage user permissions
Access Manager

Use case overview

PubNub's real-time infrastructure enables you to create various types of polls for different engagement scenarios. Whether you're running a live sports event, a virtual conference, or an interactive game show, PubNub provides the tools to implement real-time polling that keeps your audience engaged.

Match vs Side Poll

The Live Events demo app showcases PubNub's real-time capabilities for implementing match polls and side polls, but there are many other polling scenarios you can implement:

Poll TypeDescription
Event Predictions
  • High-stakes polls that require strategic thinking
  • Often tied to specific moments in an event
  • Can be used for score predictions, MVP voting, or outcome forecasting
  • Typically remain open for longer periods to allow for strategic decision-making
Quick Engagement
  • Lightweight polls for frequent interaction
  • Perfect for maintaining engagement throughout an event
  • Can be used for sentiment tracking, opinion gathering, or fun interactions
  • Typically remain open for shorter periods to maintain momentum
Audience Feedback
  • Real-time feedback collection during presentations or performances
  • Can be used for Q&A sessions, satisfaction ratings, or topic voting
  • Helps presenters adjust content based on audience response
  • Duration varies based on the feedback type
Gamification & Quizzes
  • Polls and quizzes integrated with scoring systems
  • Can be used for trivia, knowledge tests, skill challenges, or educational content
  • Often includes leaderboards, rewards, and progress tracking
  • Supports multiple question types (multiple choice, true/false, timed responses)
  • Duration varies based on the game mechanics and quiz complexity
Planning your poll timing

When planning your poll timing strategy, it's important to consider the event flow and critical moments where polls would be most engaging. Take into account your audience's engagement patterns and time zones, especially for global audiences. The complexity of your poll and the time needed for decision-making should also influence your timing choices. Don't forget to consider how your polls integrate with other engagement features. Getting the timing right can make a significant difference in participation rates and overall engagement.

icon

Required Admin Portal config


Basic setup for polling

To implement real-time polling with PubNub, you'll need to set up your channels and configure proper security settings.

First, initialize the PubNub client with your credentials and security settings:

const pubnub = new PubNub({
publishKey: 'your-publish-key',
subscribeKey: 'your-subscribe-key',
userId: 'ID-to-uniquely-identify-the-poll-participant'
});
SDK configuration

You can use any PubNub SDK to implement this solution. For optimal performance and security:

  • Use unique user IDs for each user, but reuse it for different client devices ( mobile, tablet, via browser) of the same user.
  • Keep your publish and subscribe keys secure.
  • Consider using environment variables for sensitive data.

For more information on available configuration options, refer to the Configuration documentation of the SDK you're using. The Live Events demo app uses the JavaScript SDK via the JavaScript Chat SDK, which provides chat-specific methods as well as the core JavaScript SDK operations, but that's not important to illustrate how to work with polls.

Architectural approaches

When implementing polling systems, there are two main architectural approaches to consider:

Minimal channel approach

This approach uses a minimal set of channels to handle the entire polling lifecycle. It's suitable for most polling implementations and provides a good balance of simplicity and functionality.

Channel TypeChannel NamePurposePermissions
Poll Broadcasting
game.new-poll
Broadcast poll questions and choices
Users need read permission
Vote Submission
game.poll-votes
Submit individual votes
Users need write permission
Results
game.poll-results
Broadcast ongoing and final results
Users need read permission

For vote submission, you have two options for structuring the data:

  • include IDs in the channel name:

    Channel: game.poll-votes.{pollId}
    Message: {"choice": "A"}
  • include IDs in the message payload:

    Channel: game.poll-votes
    Message: {"pid": "p1", "qid": "q1", "choice": "A"}

Many channels approach

This approach uses a more granular channel structure, creating separate channels for different aspects of the polling system. It's useful for:

  • Complex polling scenarios with multiple question types
  • Systems requiring fine-grained access control
  • Applications needing to scale to very large numbers of concurrent polls

If you decide to go with the multiple channel approach, you can customize the channel structure based on your specific requirements such as separate channels for different question types, dedicated channels for specific user groups, and specialized channels for analytics or monitoring.

Match and side polls

In the Live Events demo app, we implement two types of polls: match polls and side polls, but you can implement any type of poll you want using PubNub.

The actual polls are regular messages with some additional metadata. Real-time messaging forms the core of PubNub's platform, delivering messages globally in under 100 milliseconds.

A PubNub message can contain any kind of serializable data, like objects, numbers and UTF-8 encoded strings. Its format may be plain text, a URL-encoded object, or most commonly, JavaScript Object Notation (JSON). The max size of a message is 32 Kibibytes (KiB). You can check the size of your message payload using our message size calculator.

Configure PubNub channels

Channels are the fundamental building blocks of PubNub's communication infrastructure. Think of channels as dedicated pathways or rooms where messages flow between connected clients. For more information on channels, refer to Channels.

To implement real-time polling, you'll need to establish dedicated channels for different aspects of the polling lifecycle.

const pollDeclarations = 'game.new-poll'     // New poll announcements
const pollVotes = 'game.poll-votes' // User votes
const pollResults = 'game.poll-results' // Poll results

Create and announce polls

Creating a poll involves publishing a message to the poll declarations channel.

At its foundation, PubNub operates a global network of data centers that manage message delivery through persistent socket connections. When a user sends a message, it travels to the nearest PubNub edge server, is instantly replicated across the network, and delivered to all subscribers on that channel.

The Live Events demo app uses the PubNub JavaScript SDK under the hood, so the code snippets will be written in TypeScript. However, you can use any PubNub SDK to implement this solution.

Each poll is designed to contain a single question, but you can also implement polls with multiple questions.

Here's a basic example:

const poll = {
id: "unique-poll-id",
title: "Who will win the match?",
type: "prediction",
duration: 600, // Duration in seconds
showAt: Date.now(), // When to show the poll
options: [
{ id: 1, text: "Home Team" },
{ id: 2, text: "Away Team" },
{ id: 3, text: "Draw" }
]
};

// Store the poll in history for reference
await pubnub.publish({
show all 19 lines
Managing message storage

When deciding on message storage, you'll want to think about your specific needs. For important polls that you'll want to reference later or use for analytics, storing them in history is essential. On the other hand, quick engagement polls might work better with short-term storage.

Keep an eye on message size to maintain storage efficiency, and set appropriate TTL values based on your requirements. Message persistence is particularly useful for maintaining audit trails and supporting analytics (unless you're using Events & Actions which doesn't require message persistence).

For more information on message storage, refer to the Message Persistence documentation.

Rate limiting and scaling

When implementing live polls at scale, it's important to consider rate limiting and scaling strategies to ensure reliable performance and prevent system overload.

Message rate limits

PubNub enforces certain rate limits to maintain system stability. For more information on PubNub's limits and scaling capabilities, refer to the API Limits documentation.

Scaling strategies

To handle high-volume polling scenarios:

Collect and process votes

When a user votes, send their choice to the votes channel. Your backend server should handle vote validation and counting:

// Client-side code for submitting votes with timestamps
async function submitVote(pollId, questionId, choiceId) {
await pubnub.publish({
channel: pollVotes,
message: {
pollId: pollId,
questionId: questionId,
choiceId: choiceId
// No need to include userId - PubNub will add publisher automatically
}
});
}

// PubNub Function for handling vote updates with timetoken
export default async (request) => {
show all 56 lines

Vote validation and counting

Always perform validation on the server side to ensure the integrity of your polls. Here are some key considerations:

  • Prevent duplicate votes from the same user
  • Validate that votes are submitted within the poll's active period
  • Verify that the selected option is valid for the poll
  • Handle concurrent votes to prevent race conditions
  • Implement proper error handling and logging
  • Ensure the user has permission to vote in the poll
  • Verify the poll is currently live when the user attempts to vote

The Live Events demo app uses a simplified approach to vote validation and counting. In a production environment, your code needs to be more robust.

Single vote per user

To enforce single votes per user, you have two options:

  • Using PubNub Functions with KV Store (recommended for serverless implementations):

    // In a PubNub Function
    const db = require('kvstore');

    export default (request) => {
    const userId = request.message.userId;
    const pollId = request.message.pollId;
    const questionId = request.message.questionId;
    const choice = request.message.choice;

    // Create unique key for this user's vote
    const voteKey = `${userId}-${pollId}-${questionId}`;

    return db.getItem(voteKey)
    .then(existingVote => {
    if (existingVote) {
    show all 38 lines
  • Using a backend server (recommended for more complex implementations):

    // In your backend server
    async function handleVoteMessage(msg) {
    const userId = msg.userId;
    const pollId = msg.pollId;
    const questionId = msg.questionId;
    const choice = msg.choice;

    // Create unique key for this user's vote
    const voteKey = `${userId}-${pollId}-${questionId}`;

    try {
    // Check if user has already voted
    const existingVote = await yourDatabase.get(voteKey);

    if (existingVote) {
    show all 35 lines

Choose the approach that best fits your architecture:

  • Use PubNub Functions with KV Store for serverless implementations where you want to keep everything within the PubNub ecosystem.
  • Use a backend server when you need more complex logic, integration with other services, or have specific database requirements.
Multiple question polls

When implementing polls with multiple questions, you need to consider how to handle partial completion and result inclusion.

ScenarioDescription
Polls and quizzes with multiple questions
  • Require all questions to be answered for the vote to be counted
  • Allow partial completion and include all answered questions in results
  • Remember user answers for the duration of the poll, but only include them in results if all questions are completed
Abandoned polls
  • Store partial answers temporarily during the poll's active period
  • Only include completed polls in the final results
  • Optionally allow users to return and complete their answers before the poll ends
Viewing results
  • Implement a "see results" option that publishes a results message when requested
  • Optionally, show results in real-time as votes come in
  • Consider implementing a delay before showing results to prevent influencing other voters
Timestamp tracking for vote updates

When handling vote updates, it's important to implement proper timetoken tracking to ensure data consistency and handle edge cases:

  • Determine the most recent vote in case of multiple submissions from the same user
  • Track when votes were submitted relative to the poll's active period
  • Resolve conflicts when votes are submitted simultaneously
  • Maintain an audit trail of voting activity

The timetoken of the last received update should be used to determine the most recent vote in case of multiple submissions from the same user.

Using PubNub's timetoken

PubNub automatically adds a timetoken to every message when it's published. To convert a timetoken to a Unix timestamp (seconds), divide the timetoken by 10,000,000 (10^7).

Here's sample code that demonstrates handling timestamp tracking for votes:

// Client-side code for submitting votes with timestamps
async function submitVote(pollId, questionId, choiceId) {
await pubnub.publish({
channel: pollVotes,
message: {
pollId: pollId,
questionId: questionId,
choiceId: choiceId
// No need to include userId or timestamp - PubNub will add publisher and timetoken automatically
}
});
}

// PubNub Function for handling vote updates with timetoken
export default async (request) => {
show all 56 lines

For multiple question polls, you can extend this approach to track completion status:

// Track completion status for multi-question polls
async function trackPollCompletion(pollId, userId) {
const db = require('kvstore');
const userPollKey = `${pollId}-${userId}`;

try {
// Get poll configuration
const pollConfig = await db.get(`poll-config-${pollId}`);
if (!pollConfig) return false;

// Get all votes for this user in this poll
const votes = await db.get(`poll-votes-${pollId}-${userId}`);
if (!votes) return false;

// Count unique questions answered
show all 58 lines

Publish and handle results

After the voting period ends, publish the results.

Vote submission UI showing voting options and feedback

Your backend server should calculate the final vote counts and publish the results

Even though it's not a requirement for polls, you might want to gamify the poll experience by rewarding the user for completing a poll.

async function publishResults(pollId, correctOption, pollType) {
await pubnub.publish({
channel: pollResults,
message: {
id: pollId,
correctOption: correctOption,
pollType: pollType
},
storeInHistory: true
});
}
Processing poll results

When processing poll results, you'll need to carefully calculate and validate the final vote counts. It's often helpful to implement a short delay before publishing results to ensure all votes are properly counted. Make sure to store the results for future analytics and reference. If you're using a scoring system or leaderboards, remember to update them with the new results. Don't forget to send notifications to relevant users to keep them informed about the outcome.

For more information on receiving messages, refer to the Receive Messages documentation.

User interface

Creating an engaging user interface is crucial for successful polling implementation. This section covers key considerations and best practices for building effective polling interfaces.

Poll display components

When designing your polling interface, focus on creating a cohesive experience that guides users through the entire polling process.

Start with a well-designed poll container that makes the current poll immediately visible, with a clear, easy-to-read question and accessible voting options. This foundation ensures users can quickly understand what they're voting on and how to participate.

Poll display components

The voting interface should be intuitive, with a straightforward selection mechanism and clear visual feedback when options are selected or votes are submitted. Make sure to handle invalid votes gracefully with appropriate error messages, helping users correct their mistakes without frustration.

For the results display, you may consider implementing real-time updates to show votes as they come in, with clear visualizations that make the data easy to understand. When available, include historical context to help users understand the significance of the current results.

Poll results display

Throughout the interface, maintain a mobile-responsive design that works seamlessly across all devices. This ensures a consistent experience regardless of how users access your polls, whether they're on a desktop computer, tablet, or smartphone.

Here's a basic example of a poll component:

interface Poll {
id: string;
title: string;
options: Array<{
id: number;
text: string;
score?: number;
}>;
isActive: boolean;
userVote?: number;
}

function PollComponent({ poll }: { poll: Poll }) {
const [selectedOption, setSelectedOption] = useState<number | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
show all 182 lines

More features

The above scenario presents the minimum use of PubNub features to increase fan participation. Take a look at the following additional features that can further enhance your fan engagement.

Poll security

To implement real-time polling, you'll need to establish dedicated channels for different aspects of the polling lifecycle. These channels should be secured using Access Manager:

const pollDeclarations = 'game.new-poll'     // New poll announcements
const pollVotes = 'game.poll-votes' // User votes
const pollResults = 'game.poll-results' // Poll results

// Configure Access Manager for secure channel access
await pubnub.grant({
channels: [pollDeclarations, pollVotes, pollResults],
authKeys: ['user-auth-key'],
read: true,
write: true,
ttl: 1440 // Token expiration in minutes (24 hours)
});

When securing your channels, consider the following:

  • Set appropriate TTL (Time-To-Live) values for tokens to ensure they expire as needed.
  • Use unique authentication keys tailored to different user roles.
  • Regularly update credentials to enhance security.
  • Keep track of access patterns to detect any anomalies.
  • Grant write access to the poll declarations channel only to poll creators.
  • Allow write access to the votes channel only to voters.
  • Provide write access to the results channel only to results publishers.
  • Ensure all users have read access to the necessary channels.

For more information, refer to the Access Manager documentation.

Interactive quizzes

Interactive quizzes are a powerful way to engage your audience while testing their knowledge, from simple trivia to complex educational assessments.

Quiz types and features

Quiz TypeDescriptionUse Cases
Multiple choice
  • Questions with predefined answer options
  • Can include single or multiple correct answers
  • Supports image-based questions
  • Trivia games
  • Knowledge assessments
  • Educational content
True/False
  • Simple binary questions
  • Quick to answer
  • Fact checking
  • Quick knowledge tests
  • Warm-up questions
Timed quizzes
  • Questions with time limits
  • Adds excitement and challenge
  • Can be combined with other question types
  • Competitive quizzes
  • Speed challenges
  • Tournament-style events

Simple quiz implementation example

Consider the following example of a simple quiz implementation an addition to the basic polling implementation. Here's an example of how to implement a simple quiz using PubNub:

// Quiz question structure
const quizQuestion = {
id: "q1",
type: "multiple-choice",
question: "What is the capital of France?",
options: [
{ id: "a", text: "London" },
{ id: "b", text: "Paris" },
{ id: "c", text: "Berlin" },
{ id: "d", text: "Madrid" }
],
correctAnswer: "b",
timeLimit: 30, // seconds
points: 10
};
show all 36 lines
Last updated on