How to Set Up a WebRTC-Based Video and Audio Calling Feature with Node.js, Express.js, and React.js

How to Set Up a WebRTC-Based Video and Audio Calling Feature with Node.js, Express.js, and React.js

This blog explains how to build a WebRTC-based video and audio calling feature using Node.js, Express.js, and React.js. It covers setting up the backend server, creating a React frontend for real-time communication, and integrating WebRTC technology. Follow these steps to add live video chat to your web applications and enhance user interaction.

date

Published On: 28 August, 2024

time

3 min read

In This Article:

The Global village that we live in is hugely connected. Here, each string leads to another. World is more connected than ever! Henceforth, having the ability to communicate in real-time can make a significant difference in how we work and interact online. 

WebRTC (Web Real-Time Communication) provides a powerful framework for building video and audio calling features right into your web applications. 

In order to save the day, this guide will walk you through setting up a webrtc-based calling system using node.js, express.js, and react.js. You can hire developers to get the job done on time, everytime. 

You’ll discover how to:

  • Build and integrate a WebRTC-based calling system from scratch.
  • Add real-time video and audio features to your web applications.
  • Follow clear, hands-on instructions to implement WebRTC technology.
  • Hire software developers that enhance your app with live video chat capabilities.
  • Gain essential skills for modern web applications and prepare for common development challenges

Even if you’re looking to boost your app with easy video chats or just exploring new technologies, this step-by-step tutorial will give you a solid foundation to get started and bring your real-time communication ideas to life. 

Prerequisites

Before we start, make sure you have the following installed:

  • Node.js (v14.x or higher)
  • npm (Node package manager)
  • React.js (create-react-app)
  • Basic knowledge of JavaScript, Node.js, Express.js, and React.js

Step 1: Setting Up the Backend with Node.js and Express.js

1. Initialize Your Node.js Project

We start by creating a new directory for our project and initializing it with npm. This creates a package.json file to manage our project’s dependencies.

mkdir webrtc-app
cd webrtc-app
npm init -y

2. Install Required Dependencies

Next, we install the necessary packages for building our server:

npm install express http socket.io uuid
  • express: A web framework for Node.js that helps us create a server.
  • http: Node.js module to create HTTP servers.
  • socket.io: Provides real-time, bidirectional communication between web clients and servers.
  • uuid: Generates unique identifiers, which we’ll use to create unique room IDs for video calls.

3. Create the Server

Here, we create a file named server.js and set up a basic server:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const { v4: uuidV4 } = require('uuid');

const app = express();
const server = http.createServer(app);
const io = new Server(server);
  • express(): Initializes an Express application.
  • http.createServer(app): Creates an HTTP server instance.
  • new Server(server): Creates a new Socket.io server instance attached to our HTTP server.

We then set up a route and socket event handlers:

app.use(express.static('public'));

app.get('/', (req, res) => {
  res.redirect(`/${uuidV4()}`);
});

app.get('/:room', (req, res) => {
  res.sendFile(__dirname + '/public/index.html');
});

io.on('connection', (socket) => {
  socket.on('join-room', (roomId, userId) => {
    socket.join(roomId);
    socket.to(roomId).emit('user-connected', userId);

    socket.on('disconnect', () => {
      socket.to(roomId).emit('user-disconnected', userId);
    });
  });
});

server.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});
  • app.use(express.static(‘public’)): Serves static files from the public directory.
  • app.get(‘/’, (req, res) => {…}): Redirects the root URL to a unique room URL using uuidV4().
  • app.get(‘/:room’, (req, res) => {…}): Serves an HTML file for a specific room.
  • io.on(‘connection’, (socket) => {…}): Listens for socket connections.
  • socket.join(roomId): Adds the socket to a specific room.
  • socket.to(roomId).emit(‘user-connected’, userId): Notifies other users in the room when a new user connects.
  • socket.on(‘disconnect’, …): Handles user disconnections.

Step 2: Setting Up the Frontend with React.js

1. Create a React App

We create a React application using create-react-app:

npx create-react-app client
cd client
npm install socket.io-client peer
 
  • socket.io-client: Allows the client to connect to the Socket.io server.

  • peer: Simplifies WebRTC peer-to-peer connections.

2. Create Video Call Component

In the src directory, we create VideoCall.js to handle video calls:

import React, { useEffect, useRef } from 'react';
import io from 'socket.io-client';
import Peer from 'peerjs';

const VideoCall = ({ roomId }) => {
  const myVideo = useRef();
  const peers = useRef({});
  const socket = useRef();
  • useRef(): React hook to create references for video elements, socket connections, and peer instances.
  • socket.current = io(‘http://localhost:3000’): Connects to the Socket.io server.
  • const myPeer = new Peer(…): Creates a new Peer instance for managing WebRTC connections.
useEffect(() => {
    socket.current = io('http://localhost:3000');
    const myPeer = new Peer(undefined, {
      host: '/',
      port: '3001'
    });

    myPeer.on('open', id => {
      socket.current.emit('join-room', roomId, id);
    });

    navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    }).then(stream => {
      myVideo.current.srcObject = stream;
      myVideo.current.play();
  • useEffect(() => {…}, [roomId]): Sets up connections and event listeners on component mount.
  • navigator.mediaDevices.getUserMedia(…): Requests access to the user’s webcam and microphone.
 myPeer.on('call', call => {
        call.answer(stream);
        const video = document.createElement('video');
        call.on('stream', userVideoStream => {
          addVideoStream(video, userVideoStream);
        });
      });

      socket.current.on('user-connected', userId => {
        connectToNewUser(userId, stream, myPeer);
      });

      socket.current.on('user-disconnected', userId => {
        if (peers.current[userId]) peers.current[userId].close();
      });
    });

    return () => {
      socket.current.disconnect();
    };
  }, [roomId]);
  • myPeer.on(‘call’, call => {…}): Handles incoming calls and streams video to a new video element.
  • socket.current.on(‘user-connected’, userId => {…}): Connects to new users when they join.
  • socket.current.on(‘user-disconnected’, userId => {…}): Closes connections when users leave.
 const connectToNewUser = (userId, stream, myPeer) => {
    const call = myPeer.call(userId, stream);
    const video = document.createElement('video');
    call.on('stream', userVideoStream => {
      addVideoStream(video, userVideoStream);
    });
    call.on('close', () => {
      video.remove();
    });

    peers.current[userId] = call;
  };

  const addVideoStream = (video, stream) => {
    video.srcObject = stream;
    video.addEventListener('loadedmetadata', () => {
      video.play();
    });
    document.getElementById('video-grid').append(video);
  };

  return (
    <div id="video-grid">
      <video ref={myVideo} muted />
    </div>
  );
};

export default VideoCall;
  • connectToNewUser(userId, stream, myPeer): Initiates a call to a new user and sets up their video stream.
  • addVideoStream(video, stream): Appends a new video element with the user’s stream to the video grid.

3. Update App.js

We configure our React Router to display the VideoCall component for specific room paths:

import React from 'react';
import VideoCall from './VideoCall';
import { BrowserRouter as Router, Route } from 'react-router-dom';

function App() {
  return (
    <Router>
      <Route path="/:roomId" component={({ match }) => <VideoCall roomId={match.params.roomId} />} />
    </Router>
  );
}

export default App;
  • Router: Wraps our application to enable routing.
  • Route: Defines a route that renders VideoCall for URLs with a room ID.

Step 3: Run Your Application

Finally, we run the server and React application to see everything in action.

Backend Server

node server.js

Starts the Node.js server on http://localhost:3000.

React Frontend

npm start

Runs the React app, opening it in your default browser at http://localhost:3000.

Challenges and Considerations

  • Network Configuration: Ensure proper configuration of STUN/TURN servers to handle peer connections across different networks.
  • Browser Compatibility: Test WebRTC functionality across various browsers and devices.
  • Security: Implement HTTPS and secure WebRTC connections.
  • Scalability: Consider integrating media servers for enhanced scalability and features.

Create A WebRTC Calling System From Scratch

 

Get Your React.js Developer

Conclusion

Building real-time communication features with WebRTC can transform how users interact with your application, adding a valuable layer of engagement and functionality. By following this guide, you’ve set up the essentials for video and audio calling using Node.js, Express.js, and React.js. 

Remember to consider factors like network configuration and security to ensure a smooth and reliable user experience. With this knowledge, you’re ready to further develop and refine your application, creating richer, more interactive experiences for your users. If you’re ready to dive deeper or need expert assistance, partnering with skilled developers can help you elevate your project even further.

Hire Remote Developers

Don’t Have Time To Read Now? Download It For Later.

The Global village that we live in is hugely connected. Here, each string leads to another. World is more connected than ever! Henceforth, having the ability to communicate in real-time can make a significant difference in how we work and interact online. 

WebRTC (Web Real-Time Communication) provides a powerful framework for building video and audio calling features right into your web applications. 

In order to save the day, this guide will walk you through setting up a webrtc-based calling system using node.js, express.js, and react.js. You can hire developers to get the job done on time, everytime. 

You’ll discover how to:

  • Build and integrate a WebRTC-based calling system from scratch.
  • Add real-time video and audio features to your web applications.
  • Follow clear, hands-on instructions to implement WebRTC technology.
  • Hire software developers that enhance your app with live video chat capabilities.
  • Gain essential skills for modern web applications and prepare for common development challenges

Even if you’re looking to boost your app with easy video chats or just exploring new technologies, this step-by-step tutorial will give you a solid foundation to get started and bring your real-time communication ideas to life. 

Prerequisites

Before we start, make sure you have the following installed:

  • Node.js (v14.x or higher)
  • npm (Node package manager)
  • React.js (create-react-app)
  • Basic knowledge of JavaScript, Node.js, Express.js, and React.js

Step 1: Setting Up the Backend with Node.js and Express.js

1. Initialize Your Node.js Project

We start by creating a new directory for our project and initializing it with npm. This creates a package.json file to manage our project’s dependencies.

mkdir webrtc-app
cd webrtc-app
npm init -y

2. Install Required Dependencies

Next, we install the necessary packages for building our server:

npm install express http socket.io uuid
  • express: A web framework for Node.js that helps us create a server.
  • http: Node.js module to create HTTP servers.
  • socket.io: Provides real-time, bidirectional communication between web clients and servers.
  • uuid: Generates unique identifiers, which we’ll use to create unique room IDs for video calls.

3. Create the Server

Here, we create a file named server.js and set up a basic server:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const { v4: uuidV4 } = require('uuid');

const app = express();
const server = http.createServer(app);
const io = new Server(server);
  • express(): Initializes an Express application.
  • http.createServer(app): Creates an HTTP server instance.
  • new Server(server): Creates a new Socket.io server instance attached to our HTTP server.

We then set up a route and socket event handlers:

app.use(express.static('public'));

app.get('/', (req, res) => {
  res.redirect(`/${uuidV4()}`);
});

app.get('/:room', (req, res) => {
  res.sendFile(__dirname + '/public/index.html');
});

io.on('connection', (socket) => {
  socket.on('join-room', (roomId, userId) => {
    socket.join(roomId);
    socket.to(roomId).emit('user-connected', userId);

    socket.on('disconnect', () => {
      socket.to(roomId).emit('user-disconnected', userId);
    });
  });
});

server.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});
  • app.use(express.static(‘public’)): Serves static files from the public directory.
  • app.get(‘/’, (req, res) => {…}): Redirects the root URL to a unique room URL using uuidV4().
  • app.get(‘/:room’, (req, res) => {…}): Serves an HTML file for a specific room.
  • io.on(‘connection’, (socket) => {…}): Listens for socket connections.
  • socket.join(roomId): Adds the socket to a specific room.
  • socket.to(roomId).emit(‘user-connected’, userId): Notifies other users in the room when a new user connects.
  • socket.on(‘disconnect’, …): Handles user disconnections.

Step 2: Setting Up the Frontend with React.js

1. Create a React App

We create a React application using create-react-app:

npx create-react-app client
cd client
npm install socket.io-client peer
 
  • socket.io-client: Allows the client to connect to the Socket.io server.

  • peer: Simplifies WebRTC peer-to-peer connections.

2. Create Video Call Component

In the src directory, we create VideoCall.js to handle video calls:

import React, { useEffect, useRef } from 'react';
import io from 'socket.io-client';
import Peer from 'peerjs';

const VideoCall = ({ roomId }) => {
  const myVideo = useRef();
  const peers = useRef({});
  const socket = useRef();
  • useRef(): React hook to create references for video elements, socket connections, and peer instances.
  • socket.current = io(‘http://localhost:3000’): Connects to the Socket.io server.
  • const myPeer = new Peer(…): Creates a new Peer instance for managing WebRTC connections.
useEffect(() => {
    socket.current = io('http://localhost:3000');
    const myPeer = new Peer(undefined, {
      host: '/',
      port: '3001'
    });

    myPeer.on('open', id => {
      socket.current.emit('join-room', roomId, id);
    });

    navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    }).then(stream => {
      myVideo.current.srcObject = stream;
      myVideo.current.play();
  • useEffect(() => {…}, [roomId]): Sets up connections and event listeners on component mount.
  • navigator.mediaDevices.getUserMedia(…): Requests access to the user’s webcam and microphone.
 myPeer.on('call', call => {
        call.answer(stream);
        const video = document.createElement('video');
        call.on('stream', userVideoStream => {
          addVideoStream(video, userVideoStream);
        });
      });

      socket.current.on('user-connected', userId => {
        connectToNewUser(userId, stream, myPeer);
      });

      socket.current.on('user-disconnected', userId => {
        if (peers.current[userId]) peers.current[userId].close();
      });
    });

    return () => {
      socket.current.disconnect();
    };
  }, [roomId]);
  • myPeer.on(‘call’, call => {…}): Handles incoming calls and streams video to a new video element.
  • socket.current.on(‘user-connected’, userId => {…}): Connects to new users when they join.
  • socket.current.on(‘user-disconnected’, userId => {…}): Closes connections when users leave.
 const connectToNewUser = (userId, stream, myPeer) => {
    const call = myPeer.call(userId, stream);
    const video = document.createElement('video');
    call.on('stream', userVideoStream => {
      addVideoStream(video, userVideoStream);
    });
    call.on('close', () => {
      video.remove();
    });

    peers.current[userId] = call;
  };

  const addVideoStream = (video, stream) => {
    video.srcObject = stream;
    video.addEventListener('loadedmetadata', () => {
      video.play();
    });
    document.getElementById('video-grid').append(video);
  };

  return (
    <div id="video-grid">
      <video ref={myVideo} muted />
    </div>
  );
};

export default VideoCall;
  • connectToNewUser(userId, stream, myPeer): Initiates a call to a new user and sets up their video stream.
  • addVideoStream(video, stream): Appends a new video element with the user’s stream to the video grid.

3. Update App.js

We configure our React Router to display the VideoCall component for specific room paths:

import React from 'react';
import VideoCall from './VideoCall';
import { BrowserRouter as Router, Route } from 'react-router-dom';

function App() {
  return (
    <Router>
      <Route path="/:roomId" component={({ match }) => <VideoCall roomId={match.params.roomId} />} />
    </Router>
  );
}

export default App;
  • Router: Wraps our application to enable routing.
  • Route: Defines a route that renders VideoCall for URLs with a room ID.

Step 3: Run Your Application

Finally, we run the server and React application to see everything in action.

Backend Server

node server.js

Starts the Node.js server on http://localhost:3000.

React Frontend

npm start

Runs the React app, opening it in your default browser at http://localhost:3000.

Challenges and Considerations

  • Network Configuration: Ensure proper configuration of STUN/TURN servers to handle peer connections across different networks.
  • Browser Compatibility: Test WebRTC functionality across various browsers and devices.
  • Security: Implement HTTPS and secure WebRTC connections.
  • Scalability: Consider integrating media servers for enhanced scalability and features.

Create A WebRTC Calling System From Scratch

 

Get Your React.js Developer

Conclusion

Building real-time communication features with WebRTC can transform how users interact with your application, adding a valuable layer of engagement and functionality. By following this guide, you’ve set up the essentials for video and audio calling using Node.js, Express.js, and React.js. 

Remember to consider factors like network configuration and security to ensure a smooth and reliable user experience. With this knowledge, you’re ready to further develop and refine your application, creating richer, more interactive experiences for your users. If you’re ready to dive deeper or need expert assistance, partnering with skilled developers can help you elevate your project even further.

Share to:

Furqan Aziz

Written By:

Furqan Aziz

Furqan Aziz is CEO & Founder of InvoZone. He is a tech enthusiast by heart with 10+ years ... Know more

Harram Shahid

Contributed By:

Harram Shahid

Senior Content Lead

Get Help From Experts At InvoZone In This Domain

Book A Free Consultation

Related Articles


left arrow
right arrow