Создание видеочата с помощью Node.js + Socket.io + WebRTC
Сегодня, специально к старту нового потока по веб-разработке, поделимся с вами туториалом, из которого вы узнаете, как создать видеочат с помощью JavaScript и NodeJS. Также вы научитесь использовать PeerJS, WebRTC и Socket.io.
Здесь вы можете увидеть живой пример приложения, которое вы будете создавать.
Подготовка к проекту
Вот что вам понадобится:
- NodeJS: посетите официальный веб-сайт Node.js, чтобы загрузить и установить Node;
- NPM: программа NPM устанавливается на ваш компьютер при установке Node.js.
Настройка проекта
Весь код этого проекта можно найти в репозитории GitHub.
- Создайте пустой каталог с именем video-chat-app.
- Откройте консоль, перейдите в наш новый каталог и запустите npm init.
- Заполните необходимую информацию для инициализации нашего проекта.
- Запустите npm install express ejs socket.io uuid peer. Команда установит все зависимости, необходимые для создания этого приложения.
- А также в качестве dev-зависимости установите Nodemon. Нужно выполнить npm install-dev nodemon. Это установит nodemon как dev-зависимость.
- Создайте файл server.js — в этом файле будет храниться вся ваша серверная логика.
Теперь, когда у вас настроен наш проект, вы можете приступить к созданию приложения!
Создание сервера (с Express JS)
Первое, что вам нужно сделать, — это запустить ваш сервер. Мы собираемся использовать для этого Express. Express — это минималистичный веб-фреймворк для Node.js. Express позволяет очень легко создавать и запускать веб-сервер с помощью Node.
Давайте создадим шаблонный файл начального приложения Express.
// server.js const express = require("express"); const app = express(); const server = require(“http”).Server(app); app.get("/", (req, res) => < res.status(200).send("Hello World"); >); server.listen(3030);
Теперь ваш сервер запущен, вы можете протестировать его, запустив:
> nodemon server.js
Теперь откройте свой браузер и перейдите по адресу: localhost:3000, вы должны увидеть Hello World.

Создание первой страницы
Вместо того чтобы выводить текст, когда кто-то посещает ваш корневой маршрут, вы хотели бы присылать HTML. Для этого нужно использовать EJS (встроенный JavaScript). EJS — это язык шаблонов.
Чтобы использовать EJS в Express, вам нужно настроить ваш шаблонизатор. Для настройки добавьте эту строку кода в файл server.js.
app.set('view engine', 'ejs')
Доступ к EJS по умолчанию осуществляется в каталоге views. Теперь создайте новую папку views в каталоге. В этой папке добавьте файл с именем room.ejs. Пока что думайте о нашем файле room.ejs как о HTML-файле.
Вот как выглядит ваша файловая структура:
|-- video-chat-app |-- views |-- room.ejs |-- package.json |-- server.js
Теперь добавьте HTML-код в файл room.ejs.
Как только вы скопируете приведённый выше код, нужно немного поменять app.js:
app.get(‘/’, function (req, res) < // OLD CODE res.status(200).send("Hello World"); >)
Выше приведён старый код, в котором вы отправляете клиенту текст «Hello World!». Вместо этого вы хотите отправить файл room.ejs:
app.get(‘/’, function (req, res) < // NEW CODE res.render(‘room’); >)
Теперь откройте браузер и перейдите по адресу: localhost:3030, и вы увидите, что отображается файл room.ejs!

Добавление CSS
Выглядит не очень хорошо, правда? Это потому, что в вашем проекте нет стилей. Итак, добавьте немного CSS.
Нам нужно будет добавить новую папку в проект под названием public. В этой папке создайте файлы style.css и script.js. Вот ваша новая файловая структура:
|-- weather-app |-- views |-- index.ejs |-- public |-- style.css |-- script.js |-- package.json |-- server.js
Express не даёт доступа к этому файлу по умолчанию, поэтому вам нужно открыть его с помощью следующей строки кода:
app.use(express.static(‘public’));
Этот код позволяет вам получить доступ ко всем статическим файлам в папке “public”. Наконец, вам нужен CSS. Поскольку это не курс по CSS, я не буду вдаваться в подробности, но если вы хотите использовать мои стили, вы можете скопировать их отсюда.
После того как вы добавили CSS, вы можете посетить: localhost:3030. Вы заметите, что приложение выглядит немного лучше.
Настройка комнат
К настоящему моменту ваш файл server.js должен выглядеть так:
У вас есть один GET-роут и запуск сервера. Однако, чтобы ваше приложение работало, нужно всякий раз, когда новый пользователь посещает ваш роут по умолчанию, перенаправлять его на уникальный URL-адрес. Следует использовать библиотеку uuid для создания случайного уникального URL-адреса для каждой комнаты.
UUID — это библиотека javascript, которая позволяет вам создавать уникальные идентификаторы. В вашем приложении вы будете использовать uuid версии 4 для создания уникального URL. Но сначала импортируйте uuid в server.js.
const < v4: uuidv4 >= require("uuid");
Теперь нужно использовать uuid для создания случайного уникального идентификатора для каждой комнаты и перенаправлять пользователя в эту комнату.
app.get(“/”, (req, res) => < res.redirect(`/$`); >);
И, прежде чем вы протестируете это, я также хотел добавить страницу для каждой уникальной комнаты, и вы передадите текущий URL этой странице.
app.get(“/:room”, (req, res) => < res.render(“room”, < roomId: req.param.room >); >);
Вы передали roomId в room.ejs на этом закончили настройку ваших комнат. А теперь, если вы посетите localhost:3030, вы будете перенаправлены на уникальный URL.

Добавление видео пользователя
Вы будете работать с файлом script.js, который вы создали ранее. script.js будет содержать весь клиентский код приложения.
Итак, вот что необходимо сделать: нужно получить видеопоток, а затем добавить этот поток в элемент видео.
let myVideoStream; const videoGrid = document.getElementById("video-grid"); const myVideo = document.createElement("video"); myVideo.muted = true; navigator.mediaDevices.getUserMedia(< audio: true, video: true, >) .then((stream) => < myVideoStream = stream; addVideoStream(myVideo, stream); >);
Теперь создайтем функцию addVideoStream, которая добавит поток к видеоэлементу.
const addVideoStream = (video, stream) => < video.srcObject = stream; video.addEventListener("loadedmetadata", () =>< video.play(); videoGrid.append(video); >); >;
Этот код добавит пользовательский поток к видеоэлементу. Вы можете проверить это, посетив localhost:3030, и вы увидите всплывающее окно с видео

Добавление возможности разрешить другим пользователям транслировать свои видео в потоковом режиме.
Пришло время использовать Socket.io и PeerJS. Для тех, кто не знает, Socket.io позволяет взаимодействовать серверу и клиенту в режиме реального времени. PeerJS позволяют реализовать WebRTC.
Сначала импортируйте socket.io и peerjs в server.js и прослушайте событие соединения.
// server.js const express = require(“express”); const app = express(); const server = require(“http”).Server(app); const < v4: uuidv4 >= require(“uuid”); app.set(“view engine”, “ejs”); const io = require(“socket.io”)(server); const < ExpressPeerServer >= require(“peer”); const peerServer = ExpressPeerServer(server, < debug: true, >); app.use(“/peerjs”, peerServer); app.use(express.static(“public”)); app.get(“/”, (req, res) => < res.redirect(`/$`); >); app.get(“/:room”, (req, res) => < res.render(“room”, < roomId: req.param.room >); >); io.on(“connection”, (socket) => < socket.on(“join-room”, (roomId, userId) =>< socket.join(roomId); socket.to(roomId).broadcast.emit(“user-connected”, userId); >); >); server.listen(3030);
Теперь ваш сервер прослушивает событие присоединения к комнате. Далее настройте ваш script.js.
// public/script.js const socket = io(“/”); const videoGrid = document.getElementById(“video-grid”); const myVideo = document.createElement(“video”); myVideo.muted = true; var peer = new Peer(undefined, < path: “/peerjs”, host: “/”, port: “3030”, >); let myVideoStream; navigator.mediaDevices .getUserMedia(< audio: true, video: true, >) .then((stream) => < myVideoStream = stream; addVideoStream(myVideo, stream); peer.on(“call”, (call) => < call.answer(stream); const video = document.createElement(“video”); call.on(“stream”, (userVideoStream) =>< addVideoStream(video, userVideoStream); >); >); socket.on(“user-connected”, (userId) => < connectToNewUser(userId, stream); >); >); const connectToNewUser = (userId, stream) => < const call = peer.call(userId, stream); const video = document.createElement(“video”); call.on(“stream”, (userVideoStream) =>< addVideoStream(video, userVideoStream); >); >; peer.on(“open”, (id) => < socket.emit(“join-room”, ROOM_ID, id); >); const addVideoStream = (video, stream) => < video.srcObject = stream; video.addEventListener(“loadedmetadata”, () =>< video.play(); videoGrid.append(video); >); >;
Теперь, если в комнату войдёт новый пользователь, вы увидите его видео.
Создание пользовательского интерфейса
С видеочастью закончили. А теперь займитесь стилизацией. Но сначала добавьте контент в файл room.ejs. (Добавьте CDN font-awesome внутри тега head.)
// views/room.ejs Video Chat
Затем откройте файл style.css и добавьте немного CSS.
@import url(“https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap"); :root < — main-darklg: #1d2635; — main-dark: #161d29; — primary-color: #2f80ec; — main-light: #eeeeee; font-family: “Poppins”, sans-serif; >* < margin: 0; padding: 0; >.header < display: flex; justify-content: center; align-items: center; height: 8vh; width: 100%; background-color: var( — main-darklg); >.logo > h3 < color: var( — main-light); >.main < overflow: hidden; height: 92vh; display: flex; >.main__left < flex: 0.7; display: flex; flex-direction: column; >.videos__group < flex-grow: 1; display: flex; justify-content: center; align-items: center; padding: 1rem; background-color: var( — main-dark); >video < height: 300px; border-radius: 1rem; margin: 0.5rem; width: 400px; object-fit: cover; transform: rotateY(180deg); -webkit-transform: rotateY(180deg); -moz-transform: rotateY(180deg); >.options < padding: 1rem; display: flex; background-color: var( — main-darklg); >.options__left < display: flex; >.options__right < margin-left: auto; >.options__button < display: flex; justify-content: center; align-items: center; background-color: var( — primary-color); height: 50px; border-radius: 5px; color: var( — main-light); font-size: 1.2rem; width: 50px; margin: 0 0.5rem; >.background__red < background-color: #f6484a; >.main__right < flex: 0.3; background-color: #242f41; >.main__chat_window < flex-grow: 1; >.main__message_container < padding: 1rem; display: flex; align-items: center; justify-content: center; >.main__message_container > input < height: 50px; flex: 1; border-radius: 5px; padding-left: 20px; border: none; >#video-grid
Вот и всё! Поздравляем, вы успешно создали видеочат! Теперь вы можете развернуть его на Heroku и показать его всему миру. Демо и исходный код.
Это лишь небольшой пример того, какие вещи может делать веб-разработчик, причем в одиночку. Сделать just for fun экспорт музыки в Spotify и получить известность, пока огромная компания долго думает над решением задачи — без проблем. За один вечер набросать и выкатить расширение для браузера, которое упростит жизнь миллионам пользователей — тоже по силам. На что еще способна веб-разработка — зависит только от фантазии программиста. Приходите учиться, чтобы освоить дзюцу веб-разработки и стать настоящим самураем интернета.

Узнайте, как прокачаться в других специальностях или освоить их с нуля:
- Профессия Fullstack-разработчик на Python
- Профессия C++ разработчик
- Профессия Java-разработчик
- Курс «Python для веб-разработки»
ПРОФЕССИИ
- Профессия Data Scientist
- Профессия Data Analyst
- Профессия QA-инженер на JAVA
- Профессия Frontend-разработчик
- Профессия Этичный хакер
- Профессия C++ разработчик
- Профессия Разработчик игр на Unity
- Профессия Веб-разработчик
- Профессия iOS-разработчик с нуля
- Профессия Android-разработчик с нуля
КУРСЫ
- Курс по Data Engineering
- Курс по Machine Learning
- Курс «Machine Learning и Deep Learning»
- Курс «Математика для Data Science»
- Курс «Математика и Machine Learning для Data Science»
- Курс «Python для веб-разработки»
- Курс «Алгоритмы и структуры данных»
- Курс по аналитике данных
- Курс по DevOps
WebRTC Node.js tutorial: Development of a real-time video chat app

A server that handles real-time communication is a must if you want to make remote connections between multiple devices. This happens to be a fairly common requirement in modern app development (and increasingly so!). The WebRTC specification makes it possible for browsers to communicate directly without any third-party support, making peer-to-peer audio and video communication much easier. If you want to see how it works, complete with a practical example of a video chat app based on it, check out this WebRTC overview!
What you’ll learn
Real-time is money, so I’m gonna get to the point. In this article, I’ll show you how to write a video chat application that allows for sharing both video and audio between two connected users. It’s quite simple, nothing fancy but good for training in the JavaScript language and – to be more precise – the WebRTC technology and Node.js.
More specifically, you’re going to find out more about:
- what WebRTC is and why this HTML5 specification means so much for the modern web development,
- the JavaScript API for WebRTC and its place in the Node.js ecosystem,
- why Node.js’s non-blocking approach to serving requests makes it a great choice for WebRTC,
- how to make a simple video chat app, including an app overview, code, as well as the handling of socket connections.
What is WebRTC?
Web Real-Time Communications – WebRTC in short – is an HTML5 specification that allows you to communicate in real-time directly between browsers without any third-party plugins. WebRTC can be used for multiple tasks (even file sharing) but real-time peer-to-peer audio and video communication is obviously the primary feature and we will focus on those in this article.
What WebRTC does is to allow access to devices – you can use a microphone, a camera and share your screen with help from WebRTC and do all of that in real-time!So, in the simplest way:WebRTC enables audio and video communication to work inside web pages.
WebRTC is already supported by major players such as Apple, Microsoft (WinRTC), Google, or Opera. The specification itself is available through the World Wide Web Consortium (W3C) and the Internet Engineering Task Force.
And what about using WebRTC in tandem with JavaScript and Node.js?
WebRTC JavaScript API
WebRTC is a complex topic where many technologies are involved. However, establishing connections, communication and transmitting data are implemented through a set of JS APIs. The primary APIs include:
- RTCPeerConnection – creates and navigates peer-to-peer connections,
- RTCSessionDescription – describes one end of a connection (or a potential connection) and how it’s configured,
- navigator.getUserMedia – captures audio and video.
And Node.js may be one of the very best ways to use the WebRTC JavaScript API.
Why Node.js for WebRTC?
To make a remote connection between two or more devices you need a backend server. In this case, you need a server that handles real-time communication. You know that Node.js is built for real-time scalable applications. To develop two-way connection apps with free data exchange, you would probably use WebSockets that allows opening a communication session between a client and a server.
Requests from the client are processed as a loop, more precisely – the event loop, which makes Node.js a good option because it takes a “non-blocking” approach to serving requests and thus, achieves low latency and high throughput along the way.
That’s about it for the theory. Let’s make an app! But what kind of app?
Read more:
Demo Idea: what are we going to create here?
We are going to create a very simple application that allows us to stream audio and video to the connected device – a basic video chat app. We will use:
- express – JavaScript library to serve static files like our HTML code file which stands for our UI,
- socket.io – JavaScript library to establish a connection between two devices with WebSockets,
- WebRTC – to allow media devices (camera and microphone) to stream audio and video between connected devices.
It looks like we’ve got some code to write!
Video Chat implementation
The first thing we’re gonna do in order to create the video stream app is to serve an HTML file that will work as a UI for our application. Let’s initialize a new node.js project by running: npm init . After that we need to install a few dev dependencies by running: npm i -D typescript ts-node nodemon @types/express @types/socket.io and production dependencies by running: npm i express socket.io .
Now we can define scripts to run our project in package.json file:
When we run npm run dev command, then nodemon will be looking at any changes in src folder for every file which ends with the .ts extension. Now we are going to create an src folder and inside this folder, we will create two typescript files: index.ts and server.ts .
Inside server.ts we will create server class and we will make it work with express and socket.io:
To run our web server, before we make a js file, we need to make a new instance of Server class and invoke the listen method, we will make it inside the index.ts file:
Now, when we run: npm run dev , we should see:

And when we open the browser and enter on http://localhost:5000 we should notice our “Hello World” message:

Now we are going to create a new HTML file inside public/index.html :
In this file, we declared two video elements: one for remote video connection and another for local video. As you’ve probably noticed, we are also importing local script, so let’s create a new folder – called scripts and create index.js file inside this directory. As for styles, you can download them from the GitHub repository .
Now, you need to serve index.html to the browser. First, you need to tell express, which static files you want to serve. In order to do it, we will implement a new method inside the Server class:
Don’t forget to invoke configureApp method inside initialize method:
Now, when you enter http://localhost:5000 , you should see your index.html file in action:

The next thing you want to implement is the camera and video access, and stream it to the local-video element. To do it, you need to open public/scripts/index.js file and implement it with:
When you go back to the browser, you should notice a prompt that asks you to access your user media devices, and after accepting this prompt, you should see your camera in action!

Read more expert JavaScript content:
- A simple guide to JavaScript concurrency in Node.js and a few traps that come with it
- Cypress vs Playwright — which JavaScript testing framework is better?
- A case study from writing TypeRunner.js – a Svelte example app
How to handle socket connections?
Now we will focus on handling socket connections – we need to connect our client with the server and for that, we will use socket.io. Inside public/scripts/index.js , add:
After page refresh, you should notice a message: “Socket connected” in our terminal.

Now we will go back to server.ts and store connected sockets in memory, just to keep only unique connections. So, add a new private field in the Server class:
And on the socket connection check if the socket already exists. If it doesn’t, push a new socket to memory and emit data to connected users:
You also need to respond on socket disconnect, so inside socket connection, you need to add:
On the client-side (meaning public/scripts/index.js ), you need to implement proper behaviour on those messages:
Here is the updateUserList function:
And createUserItemContainer function:
Please notice that we add a click listener to a user container element, which invokes callUser function – for now, it can be an empty function. Now when you run two browser windows (one as a private window), you should notice two connected sockets in your web app:

After clicking the active user from the list, we want to invoke callUser function. But before you implement it, you need to declare two classes from the window object.
We will use them in callUser function:
Here we create a local offer and send to the selected user. The server listens to an event called call-user , intercepts the offer and forwards it to the selected user. Let’s implement it in server.ts:
Now on the client side, you need to react on call-made event:
Then set a remote description on the offer you’ve got from the server and create an answer for this offer. On the server-side, you need to just pass proper data to the selected user. Inside server.ts , let’s add another listener:
On the client’s side we need to handle answer-made event:
We use the helpful flag – isAlreadyCalling – just to make sure we call only the user only once.
The last thing you need to do is to add local tracks – audio and video to your peer connection, Thanks to this, we will be able to share video and audio with connected users. To do this, in the navigator.getMediaDevice callback we need to call the addTrack function on the peerConnection object.
And we need to add a proper handler for ontrack event:
As you can see, we’ve taken stream from the passed object and changed srcObject in remote-video to use received stream. So now after you click on the active user, you should make a video and audio connection, just like below:

Read more expert Node.js content:
- JavaScript dependency injection in Node – friend or foe?
- Build scalable Node.js apps faster with this boilerplate
- Elasticsearch tutorial for beginners. Take your first steps and learn practical tips with Node.js specialist
That’s it for the WebRTC Node.js tutorial – now you know how to write a video chat app with WebRTC!
WebRTC is a vast topic – especially if you want to know how it works under the hood. However, by this time you should know:
- how useful WebRTC can be and how popular this technology is becoming in 2023,
- why Node.js makes such a good combination with WebRTC,
- how to make simple WebRTC-based Node.js apps in practice.
Fortunately, we have access to easy-in-use JavaScript API, where we can create pretty neat apps, e.g. video-sharing, chat applications and much more!
If you want to deep dive into WebRTC, here’s a link to the WebRTC official documentation . My recommendation is to use docs from MDN .
Would you like to work with Node.js developers skilled in implementing real-time solutions?
In the Node.js- and AWS-based project for Reservix, we were able to develop a custom Amazon Chime implementation, which improved a CMS experience in a platform that processes hundred of thousands of events in real time.
With over three years of software development experience, he switched his allegiance from Java and fell in love with Node.js — both the dynamics of development and the community gathered around this technology. He’s mostly focused on good practices in code writing and design patterns. He spends his free time in the gym, in the mountains or in Azeroth.
How to Build a Video Chat Application with Node.js, Socket.io and TypeScript
Hey awesome people, it’s real good to see you back here. Alright so, in this tutorial we are going to be building a video chat application, yup you heard it right. We will explore how websites like Skype and Slack works. All right so let’s dive in.
Our Stack
- Node.js
- Express.js
- TypeScript
- Socket.io
Why Node.js ?
That is an excellent question. Usually REST apis are written in a client/server model, in which the client would demand certain resources from the server, and get those resources in response. This architecture is common in traditional web applications. The server reacts when the client made a request, and then closed the connection right after each response. However, in 2009, Ryan Dahl introduced a new approach to server-side runtime written in JavaScript. It enables requesting in and out of the web server (I/O) to be processed concurrently and asynchronously using a concept called non-blocking, or asynchronous I/O. The original idea behind this was to build websites with real-time push capability. Thus Node.js was born.
Unlike the previous client/server model, it became possible to develop two-way connection websites with free data exchange. It’s mostly due to WebSockets, which allow opening an interactive communications session between a user’s browser and a server. Requests to a server are then processed as a loop (event loop, to be more precise), which makes Node.js a JavaScript runtime environment that takes a “non-blocking” approach to serving requests and thus, achieves low latency and high throughput along the way.
On another note a Node.js app is run in a single process, without creating a new thread for every request. Node.js handles concurrency through an event loop which makes it extremely scalable and able to serve millions of requests.
In a nutshell Node.js is built for real time scalable applications. I will provide links to further readings that will give you some further information on why Nodejs is ideal for real time applications.
