Introducing "NAMO" Real-Time Speech AI Model: On-Device & Hybrid Cloud šŸ“¢PRESS RELEASE

How to Build an Interactive Live Streaming Application with React: A Comprehensive Guide

Learn how to build an interactive live streaming application using React and VideoSDK. This comprehensive guide covers component structure, implementing host and viewer screens, and adding interactive features like chat, polls, and reactions.

Interactive live streaming has revolutionized digital engagement, with video consumption rising 47% in the past year. While traditional streaming offers one-way communication, interactive streaming creates dynamic, two-way experiences that boost audience retention and provide new monetization opportunities.
However, building robust interactive live streaming applications requires expertise in video processing, real-time communication, and user experience design. React's component-based architecture, efficient rendering, and rich ecosystem make it an ideal framework for tackling these challenges.
This guide will walk you through creating a complete interactive live streaming application with React and VideoSDK.

What Makes React Ideal for Live Streaming Applications?

React offers several advantages for building live streaming applications:
  • Component-Based Structure: Create reusable UI components for video players, chat interfaces, and control panels
  • Virtual DOM: Ensure smooth performance with real-time updates
  • Rich Ecosystem: Access libraries specifically designed for media streaming
  • Declarative Approach: Simplify management of complex state changes
The following diagram illustrates the architecture of a React-based interactive live streaming application, showing how hosts and viewers connect through VideoSDK:
React Interactive Live Streaming Architecture

Planning Your Interactive Live Streaming Application

Before writing code, identify your application's key elements:

User Roles

Understanding the different user roles in your live streaming application is crucial for designing the right experience for each participant type:
User Roles in Interactive Live Streaming
As shown in the diagram above, our application will support three primary roles:
  • Speakers/Hosts: Users who broadcast audio/video and control the stream (SEND_AND_RECV mode)
  • Viewers: Users who watch the stream and participate through interactive features (RECV_ONLY mode)
  • Moderators (optional): Users who can manage chat and interactive elements

Key Features

  • Real-time video and audio streaming
  • Chat functionality
  • Interactive elements (polls, Q&A, reactions)
  • Media controls (camera/microphone toggle)
  • User authentication (optional)

Setting Up Your Development Environment

Let's start by creating a new React application and installing the necessary dependencies:
1# Create a new React application
2npx create-react-app videosdk-live-streaming-app
3
4# Install required packages
5npm install @videosdk.live/react-sdk react-player hls.js

Project Structure

For a clean, maintainable codebase, organize your project with a logical component hierarchy:
React Component Hierarchy for Live Streaming
As shown in the hierarchy diagram, our project will be structured as follows:
1src/
2ā”œā”€ā”€ screens/
3│   ā”œā”€ā”€ WelcomeScreen.js
4│   ā”œā”€ā”€ SpeakerScreen/
5│   │   ā”œā”€ā”€ MediaControls.js
6│   │   ā”œā”€ā”€ ParticipantsGrid.js
7│   │   └── SpeakerScreen.js
8│   └── ViewerScreen.js
9ā”œā”€ā”€ components/
10│   ā”œā”€ā”€ Chat.js
11│   ā”œā”€ā”€ Polls.js
12│   └── Reactions.js
13ā”œā”€ā”€ api.js
14└── App.js

Implementing Core Functionality

API Configuration

First, set up the VideoSDK authentication and room creation:
1// api.js
2export const authToken = "YOUR_VIDEOSDK_TOKEN";
3
4export const createNewRoom = async () => {
5  const res = await fetch(`https://api.videosdk.live/v2/rooms`, {
6    method: "POST",
7    headers: {
8      authorization: authToken,
9      "Content-Type": "application/json",
10    },
11  });
12
13  const { roomId } = await res.json();
14  return roomId;
15};

Welcome Screen

This screen lets users create or join streams:
1// WelcomeScreen.js
2import React, { useState } from "react";
3import { createNewRoom } from "../api";
4
5function WelcomeScreen({ setAppData }) {
6  const [meetingId, setMeetingId] = useState("");
7
8  const createStream = async () => {
9    const roomId = await createNewRoom();
10    setAppData({ mode: "CONFERENCE", meetingId: roomId });
11  };
12  
13  return (
14    <div className="welcome-screen">
15      <h1>Interactive Live Streaming</h1>
16      
17      <button onClick={createStream}>
18        Create New Stream
19      </button>
20      
21      <div className="divider">OR</div>
22      
23      <input
24        placeholder="Enter Stream ID"
25        value={meetingId}
26        onChange={(e) => setMeetingId(e.target.value)}
27      />
28      
29      <div className="buttons">
30        <button onClick={() => setAppData({ mode: "CONFERENCE", meetingId })}>
31          Join as Host
32        </button>
33        
34        <button onClick={() => setAppData({ mode: "VIEWER", meetingId })}>
35          Join as Viewer
36        </button>
37      </div>
38    </div>
39  );
40}

Main App Component

The App component manages application state and renders the appropriate screen:
1// App.js
2import React, { useState } from "react";
3import SpeakerScreen from "./screens/SpeakerScreen/SpeakerScreen";
4import ViewerScreen from "./screens/ViewerScreen";
5import WelcomeScreen from "./screens/WelcomeScreen";
6
7function App() {
8  const [appData, setAppData] = useState({ meetingId: null, mode: null });
9
10  // Render different screens based on app state
11  if (!appData.meetingId) {
12    return <WelcomeScreen setAppData={setAppData} />;
13  }
14  
15  return appData.mode === "CONFERENCE" 
16    ? <SpeakerScreen meetingId={appData.meetingId} /> 
17    : <ViewerScreen meetingId={appData.meetingId} />;
18}

Speaker Screen Implementation

The speaker screen consists of:
  1. A container to initialize VideoSDK
  2. Media controls for audio, video, and streaming
  3. A grid to display participants
1// SpeakerScreen.js
2import { MeetingProvider } from "@videosdk.live/react-sdk";
3import React from "react";
4import MediaControls from "./MediaControls";
5import ParticipantsGrid from "./ParticipantsGrid";
6import { authToken } from "../../api";
7
8function SpeakerScreen({ meetingId }) {
9  return (
10    <MeetingProvider
11      token={authToken}
12      config={{
13        meetingId,
14        name: "Host",
15        micEnabled: true,
16        webcamEnabled: true,
17      }}
18      joinWithoutUserInteraction
19    >
20      <div className="speaker-screen">
21        <MediaControls />
22        <ParticipantsGrid />
23      </div>
24    </MeetingProvider>
25  );
26}
The media controls component manages audio, video, and HLS streaming:
1// MediaControls.js
2import { useMeeting, Constants } from "@videosdk.live/react-sdk";
3import React, { useMemo } from "react";
4
5function MediaControls() {
6  const { toggleMic, toggleWebcam, startHls, stopHls, hlsState } = useMeeting();
7
8  // Determine HLS state
9  const { isHlsStarted, isHlsStopped } = useMemo(() => ({
10    isHlsStarted: hlsState === Constants.hlsEvents.HLS_STARTED,
11    isHlsStopped: hlsState === Constants.hlsEvents.HLS_STOPPED,
12  }), [hlsState]);
13
14  // Toggle HLS streaming
15  const toggleHls = () => {
16    if (isHlsStarted) {
17      stopHls();
18    } else if (isHlsStopped) {
19      startHls({ quality: "high" });
20    }
21  };
22
23  return (
24    <div className="controls">
25      <div className="stream-info">
26        <p>Stream Status: {hlsState}</p>
27      </div>
28      
29      <div className="buttons">
30        <button onClick={toggleMic}>Toggle Mic</button>
31        <button onClick={toggleWebcam}>Toggle Camera</button>
32        <button onClick={toggleHls}>
33          {isHlsStarted ? "Stop Stream" : "Start Stream"}
34        </button>
35      </div>
36    </div>
37  );
38}
The participants grid displays all connected users:
1// ParticipantsGrid.js
2import { useMeeting } from "@videosdk.live/react-sdk";
3import React, { useMemo } from "react";
4import Participant from "./Participant";
5
6function ParticipantsGrid() {
7  const { participants } = useMeeting();
8  
9  // Get list of participant IDs
10  const participantIds = useMemo(() => 
11    [...participants.keys()], [participants]
12  );
13
14  return (
15    <div className="participants-grid">
16      {participantIds.map(participantId => (
17        <Participant 
18          key={participantId} 
19          participantId={participantId} 
20        />
21      ))}
22    </div>
23  );
24}

Viewer Screen Implementation

The viewer screen shows the HLS stream once the speaker starts broadcasting:
1// ViewerScreen.js
2import { MeetingProvider, MeetingConsumer, Constants } from "@videosdk.live/react-sdk";
3import React, { useEffect, useRef } from "react";
4import Hls from "hls.js";
5import { authToken } from "../api";
6
7function HLSPlayer({ playbackUrl }) {
8  const videoRef = useRef(null);
9  
10  useEffect(() => {
11    if (playbackUrl && Hls.isSupported()) {
12      const hls = new Hls({
13        capLevelToPlayerSize: true,
14        maxLoadingDelay: 4,
15        minAutoBitrate: 0,
16      });
17      
18      hls.loadSource(playbackUrl);
19      hls.attachMedia(videoRef.current);
20    }
21  }, [playbackUrl]);
22
23  return (
24    <video 
25      ref={videoRef} 
26      autoPlay 
27      controls
28      className="hls-player"
29    />
30  );
31}
32
33function ViewerScreen({ meetingId }) {
34  return (
35    <MeetingProvider
36      token={authToken}
37      config={{ 
38        meetingId, 
39        name: "Viewer",
40        mode: "VIEWER" 
41      }}
42      joinWithoutUserInteraction
43    >
44      <MeetingConsumer>
45        {({ hlsState, hlsUrls }) =>
46          hlsState === Constants.hlsEvents.HLS_PLAYABLE ? (
47            <HLSPlayer playbackUrl={hlsUrls.playbackHlsUrl} />
48          ) : (
49            <div className="waiting">
50              <p>Waiting for the host to start streaming...</p>
51            </div>
52          )
53        }
54      </MeetingConsumer>
55    </MeetingProvider>
56  );
57}

Adding Interactive Features

Now, let's add key interactive features to enhance engagement.

Chat Component

Implement real-time chat using VideoSDK's PubSub:
1// Chat.js
2import React, { useState, useEffect } from "react";
3import { usePubSub } from "@videosdk.live/react-sdk";
4
5function Chat() {
6  const [messages, setMessages] = useState([]);
7  const [messageText, setMessageText] = useState("");
8  const { publish, messages: pubSubMessages } = usePubSub("CHAT");
9
10  useEffect(() => {
11    if (pubSubMessages) {
12      // Format and set messages
13      const formattedMessages = pubSubMessages.map(msg => ({
14        text: msg.message,
15        sender: msg.senderName,
16        timestamp: msg.timestamp
17      }));
18      
19      setMessages(formattedMessages);
20    }
21  }, [pubSubMessages]);
22
23  const sendMessage = () => {
24    if (messageText.trim()) {
25      publish(messageText, { persist: true });
26      setMessageText("");
27    }
28  };
29
30  return (
31    <div className="chat">
32      <div className="messages">
33        {messages.map((msg, index) => (
34          <div key={index} className="message">
35            <span className="sender">{msg.sender}</span>
36            <p>{msg.text}</p>
37          </div>
38        ))}
39      </div>
40      
41      <div className="message-input">
42        <input
43          value={messageText}
44          onChange={(e) => setMessageText(e.target.value)}
45          placeholder="Type your message..."
46          onKeyPress={(e) => e.key === "Enter" && sendMessage()}
47        />
48        <button onClick={sendMessage}>Send</button>
49      </div>
50    </div>
51  );
52}

Polls Component

Create interactive polls for audience engagement:
1// Polls.js
2import React, { useState, useEffect } from "react";
3import { usePubSub } from "@videosdk.live/react-sdk";
4
5function Polls() {
6  const [polls, setPolls] = useState([]);
7  const [newPoll, setNewPoll] = useState({ question: "", options: ["", ""] });
8  const { publish, messages } = usePubSub("POLLS");
9
10  useEffect(() => {
11    if (messages) {
12      const pollsData = messages.map(msg => JSON.parse(msg.message));
13      setPolls(pollsData);
14    }
15  }, [messages]);
16
17  const createPoll = () => {
18    // Create and publish poll
19    const poll = {
20      id: Date.now(),
21      question: newPoll.question,
22      options: newPoll.options.map(text => ({ text, votes: 0 })),
23    };
24    
25    publish(JSON.stringify(poll), { persist: true });
26    
27    // Reset form
28    setNewPoll({ question: "", options: ["", ""] });
29  };
30
31  const vote = (pollId, optionIndex) => {
32    // Handle voting logic
33    const updatedPolls = polls.map(poll => {
34      if (poll.id === pollId) {
35        const newOptions = [...poll.options];
36        newOptions[optionIndex].votes += 1;
37        return { ...poll, options: newOptions };
38      }
39      return poll;
40    });
41    
42    // Find and publish updated poll
43    const updatedPoll = updatedPolls.find(p => p.id === pollId);
44    publish(JSON.stringify(updatedPoll), { persist: true });
45  };
46
47  return (
48    <div className="polls">
49      {/* Poll creation form */}
50      <div className="create-poll">
51        <input
52          placeholder="Enter your question"
53          value={newPoll.question}
54          onChange={(e) => setNewPoll({ ...newPoll, question: e.target.value })}
55        />
56        
57        {/* Option inputs */}
58        {newPoll.options.map((option, index) => (
59          <input
60            key={index}
61            placeholder={`Option ${index + 1}`}
62            value={option}
63            onChange={(e) => {
64              const newOptions = [...newPoll.options];
65              newOptions[index] = e.target.value;
66              setNewPoll({ ...newPoll, options: newOptions });
67            }}
68          />
69        ))}
70        
71        <button onClick={() => setNewPoll({
72          ...newPoll,
73          options: [...newPoll.options, ""]
74        })}>
75          Add Option
76        </button>
77        
78        <button onClick={createPoll}>Create Poll</button>
79      </div>
80      
81      {/* Polls list */}
82      <div className="polls-list">
83        {polls.map(poll => (
84          <div key={poll.id} className="poll">
85            <h4>{poll.question}</h4>
86            
87            {poll.options.map((option, index) => (
88              <div key={index} className="option">
89                <span>{option.text} ({option.votes} votes)</span>
90                <button onClick={() => vote(poll.id, index)}>
91                  Vote
92                </button>
93              </div>
94            ))}
95          </div>
96        ))}
97      </div>
98    </div>
99  );
100}

Reactions Component

Add emoji reactions for simple audience participation:
1// Reactions.js
2import React, { useState, useEffect } from "react";
3import { usePubSub } from "@videosdk.live/react-sdk";
4
5const REACTIONS = ["šŸ‘", "ā¤ļø", "šŸ˜‚", "šŸ‘", "šŸŽ‰"];
6
7function Reactions() {
8  const { publish, messages } = usePubSub("REACTIONS");
9  const [activeReactions, setActiveReactions] = useState([]);
10
11  // Handle sending reactions
12  const sendReaction = (emoji) => {
13    publish(emoji);
14    showReaction(emoji);
15  };
16
17  // Display reaction animation
18  const showReaction = (emoji) => {
19    const newReaction = {
20      id: Date.now(),
21      emoji,
22      position: Math.random() * 80 + 10, // Random position
23    };
24    
25    setActiveReactions(prev => [...prev, newReaction]);
26    
27    // Remove reaction after animation
28    setTimeout(() => {
29      setActiveReactions(prev => 
30        prev.filter(r => r.id !== newReaction.id)
31      );
32    }, 3000);
33  };
34
35  // Listen for reactions from others
36  useEffect(() => {
37    if (messages && messages.length > 0) {
38      const lastMessage = messages[messages.length - 1];
39      showReaction(lastMessage.message);
40    }
41  }, [messages]);
42
43  return (
44    <div className="reactions">
45      <div className="reaction-buttons">
46        {REACTIONS.map(emoji => (
47          <button 
48            key={emoji} 
49            onClick={() => sendReaction(emoji)}
50          >
51            {emoji}
52          </button>
53        ))}
54      </div>
55      
56      <div className="floating-reactions">
57        {activeReactions.map(reaction => (
58          <div
59            key={reaction.id}
60            className="floating-emoji"
61            style={{ left: `${reaction.position}%` }}
62          >
63            {reaction.emoji}
64          </div>
65        ))}
66      </div>
67    </div>
68  );
69}

Integrating Components

To use these interactive features, integrate them into your Speaker and Viewer screens:
1// Enhanced SpeakerScreen.js
2function SpeakerScreen({ meetingId }) {
3  return (
4    <MeetingProvider config={...}>
5      <div className="app-container">
6        <div className="main-content">
7          <MediaControls />
8          <ParticipantsGrid />
9        </div>
10        
11        <div className="sidebar">
12          <Chat />
13          <Polls />
14          <Reactions />
15        </div>
16      </div>
17    </MeetingProvider>
18  );
19}
20
21// Enhanced ViewerScreen.js
22function ViewerScreen({ meetingId }) {
23  return (
24    <MeetingProvider config={...}>
25      <div className="app-container">
26        <div className="main-content">
27          <HLSPlayer />
28        </div>
29        
30        <div className="sidebar">
31          <Chat />
32          <Polls />
33          <Reactions />
34        </div>
35      </div>
36    </MeetingProvider>
37  );
38}

Styling Your Application

Add CSS to create a professional look and feel. Use a design system or create custom styles for your components. Here's a basic styling example for the application container:
1/* App.css */
2.app-container {
3  display: flex;
4  height: 100vh;
5}
6
7.main-content {
8  flex: 1;
9  padding: 20px;
10  background-color: #f8f9fa;
11}
12
13.sidebar {
14  width: 300px;
15  background-color: white;
16  border-left: 1px solid #dee2e6;
17  padding: 20px;
18  overflow-y: auto;
19}
20
21/* Add more styles for other components */

Conclusion

Building an interactive live streaming application with React and VideoSDK enables you to create engaging, real-time experiences for your users. By implementing features like chat, polls, and reactions, you can significantly increase audience participation and retention.
This guide has provided a foundation for creating your own interactive streaming application. As you continue development, consider adding features like:
  • User authentication
  • Screen sharing
  • Recording capabilities
  • Analytics and monitoring
  • Custom branding and themes
With React's component-based architecture and VideoSDK's powerful capabilities, you're well-equipped to build a production-ready interactive live streaming platform that engages your audience and stands out from traditional streaming applications.

Get 10,000 Free Minutes Every Months

No credit card required to start.

Want to level-up your learning? Subscribe now

Subscribe to our newsletter for more tech based insights

FAQ