---
title: "Tutorial: How to Build a Video Conferencing Application with WebRTC – WebRTC.ventures"
description: Need a tutorial on building a video conference application using WebRTC? We'll show you how to create one with a custom signaling server.
image: https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/Tutorial_-How-to-Build-a-Video-Conference-App-with-WebRTC.png
---

[Skip to content](https://blog.webrtc.ventures/2019/11/tutorial-how-to-build-a-video-conferencing-application-with-webrtc#main-content)

![WebRTC.ventures](https://blog.webrtc.ventures/hubfs/logo-main-light.svg)

- [WebRTC Services](https://webrtc.ventures/webrtc-development-services/)
  
  Show submenu for WebRTC Services 
  
    - [Assess](https://webrtc.ventures/services/assess/)
    - [Build](https://webrtc.ventures/services/build/)
    - [Integrate](https://webrtc.ventures/services/integrate/)
    - [Test](https://webrtc.ventures/services/test/)
    - [Manage](https://webrtc.ventures/services/manage/)
    - [Migrating From Twilio Video](https://webrtc.ventures/twilio-video/)
- Our Partners
  
  Show submenu for Our Partners 
  
    - [Amazon Chime SDK](https://webrtc.ventures/partners/amazon-chime-sdk/)
- Stories of Success
  
  Show submenu for Stories of Success 
  
    - [Remote Video Interpreting Platform with Agent Routing](https://webrtc.ventures/successes/remote-video-translation-platform/)
    - [WebRTC to SIP Gateway for ASL Interpreters](https://webrtc.ventures/successes/webrtc-to-sip-gateway-for-asl-interpreters/)
    - [Audio Listening Device to Improve Surgical Outcomes](https://webrtc.ventures/successes/audio-listening-device-to-improve-surgical-outcomes/)
    - [Albania’s First Telemedicine Platform](https://webrtc.ventures/successes/albanias-first-telemedicine-platform/)
    - [Automated Video Storytelling with the Amazon Chime SDK](https://webrtc.ventures/successes/automated-video-storytelling-with-the-amazon-chime-sdk/)
    - [Large Scale Video Conferencing](https://webrtc.ventures/successes/large-scale-video-conferencing/)
    - [Broadcasting and Webcast Control Room](https://webrtc.ventures/successes/live-video-broadcasting-and-webcast-control-room/)
- WebRTC Resources
  
  Show submenu for WebRTC Resources 
  
    - [WebRTC Live](https://webrtc.ventures/webrtc-live/)
    - [WebRTC Tips](https://www.youtube.com/playlist?list=PLayYqdnyegt3QvxX-Rt6wbFIK8727Z5Oz)
    - [WebRTC.ventures Blog](https://webrtc.ventures/blog/)
    - [Migrating From Twilio Video](https://webrtc.ventures/twilio-video/)
    - [WebRTC.ventures Training Program](https://webrtc.ventures/webrtc-ventures-training-program/)
- [About Us](https://webrtc.ventures/our-team/)
  
  Show submenu for About Us 
  
    - [Blog](https://webrtc.ventures/blog/)
    - [Our Team](https://webrtc.ventures/our-team/)
    - [Jobs](https://webrtc.ventures/jobs/)

Open main navigation

Close main navigation

- [WebRTC Services](https://webrtc.ventures/webrtc-development-services/)
  
  Show submenu for WebRTC Services 
  
    - [Assess](https://webrtc.ventures/services/assess/)
    - [Build](https://webrtc.ventures/services/build/)
    - [Integrate](https://webrtc.ventures/services/integrate/)
    - [Test](https://webrtc.ventures/services/test/)
    - [Manage](https://webrtc.ventures/services/manage/)
    - [Migrating From Twilio Video](https://webrtc.ventures/twilio-video/)
- Our Partners
  
  Show submenu for Our Partners 
  
    - [Amazon Chime SDK](https://webrtc.ventures/partners/amazon-chime-sdk/)
- Stories of Success
  
  Show submenu for Stories of Success 
  
    - [Remote Video Interpreting Platform with Agent Routing](https://webrtc.ventures/successes/remote-video-translation-platform/)
    - [WebRTC to SIP Gateway for ASL Interpreters](https://webrtc.ventures/successes/webrtc-to-sip-gateway-for-asl-interpreters/)
    - [Audio Listening Device to Improve Surgical Outcomes](https://webrtc.ventures/successes/audio-listening-device-to-improve-surgical-outcomes/)
    - [Albania’s First Telemedicine Platform](https://webrtc.ventures/successes/albanias-first-telemedicine-platform/)
    - [Automated Video Storytelling with the Amazon Chime SDK](https://webrtc.ventures/successes/automated-video-storytelling-with-the-amazon-chime-sdk/)
    - [Large Scale Video Conferencing](https://webrtc.ventures/successes/large-scale-video-conferencing/)
    - [Broadcasting and Webcast Control Room](https://webrtc.ventures/successes/live-video-broadcasting-and-webcast-control-room/)
- WebRTC Resources
  
  Show submenu for WebRTC Resources 
  
    - [WebRTC Live](https://webrtc.ventures/webrtc-live/)
    - [WebRTC Tips](https://www.youtube.com/playlist?list=PLayYqdnyegt3QvxX-Rt6wbFIK8727Z5Oz)
    - [WebRTC.ventures Blog](https://webrtc.ventures/blog/)
    - [Migrating From Twilio Video](https://webrtc.ventures/twilio-video/)
    - [WebRTC.ventures Training Program](https://webrtc.ventures/webrtc-ventures-training-program/)
- [About Us](https://webrtc.ventures/our-team/)
  
  Show submenu for About Us 
  
    - [Blog](https://webrtc.ventures/blog/)
    - [Our Team](https://webrtc.ventures/our-team/)
    - [Jobs](https://webrtc.ventures/jobs/)
- [Contact us](https://webrtc.ventures/contact/)

[Contact us](https://webrtc.ventures/contact/)

 Nov 4, 2019 12:00:00 AM

# Tutorial: How to Build a Video Conferencing Application with WebRTC

[Hector Zelaya](https://blog.webrtc.ventures/author/hector-zelaya)

Share: [linkedin-in icon](http://www.linkedin.com/shareArticle?mini=true&url=https://blog.webrtc.ventures/2019/11/tutorial-how-to-build-a-video-conferencing-application-with-webrtc) [X Twitter icon](https://twitter.com/intent/tweet?url=https://blog.webrtc.ventures/2019/11/tutorial-how-to-build-a-video-conferencing-application-with-webrtc) [envelope icon](mailto:?body=https://blog.webrtc.ventures/2019/11/tutorial-how-to-build-a-video-conferencing-application-with-webrtc)

This blog post provides a tutorial on **building a video conferencing application using WebRTC**. Instead of complicating things, we’ll show you how to create a simple one-to-one video conferencing application using WebRTC APIs and a few other libraries to **build a custom signaling server**.

Before we get started, let’s look at the following diagram of the WebRTC communication process:

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/Screenshot-2018-07-19-11_53_08-1-1.png?width=607&height=326&name=Screenshot-2018-07-19-11_53_08-1-1.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/Screenshot-2018-07-19-11_53_08-1-1.png?width=607&height=326&name=Screenshot-2018-07-19-11_53_08-1-1.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/Screenshot-2018-07-19-11_53_08-1-1.png)

The process for enabling communication on WebRTC can be seen as a three-step flow:

1. The browser receives access to the media devices (the camera and the microphone).
2. Each peer exchanges information about itself with other peers through a signaling process.
3. After signaling, peers connect directly and communication begins.

To make all of this possible, a signaling server is necessary for information exchange. Additionally, a pair of STUN/TURN servers are required to achieve NAT traversal and relay media if direct communication is not possible.

Without further ado, let’s dive into the application!

## The application

**Now we will build a simple one-to-one video conference application. **It will have a “rooms” functionality, where each “room” will host a different call.

The first thing a user will see is a screen to type a room number. The room number can be anything the users wants it to be. When another user wants to join the first user, they need to enter that room number for the call to begin.

The code for this tutorial is available as a public repository on Github. You can either [clone it](https://github.com/agilityfeat/webrtc-video-conference-tutorial/) to your computer or follow along with us to build it from scratch. We’re using Javascript as programming language and Node.JS as a runtime engine, so you need to [install Node.JS](https://nodejs.org/en/download/) if you don’t have it yet.

**Let’s begin by creating a folder anywhere you want. This will be our project folder. **Then create another one inside called *public.* Using the command line, navigate to the project folder and paste the following commands to install the required dependencies. An internet connection is required to download the libraries.

npm init -y

npm install -S express@4.15.4 socket.io@2.0.3

**Now let’s create a simple HTML file.** It will contain two *div *elements, one for typing the room number and another for showing the video streams. The file will also contain *script *tags for the socket.io client library and another file that we will create later.

Using your favorite text editor, create a new file, paste the following code, and save it in your project folder, inside *public* as *index.html.*

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode1.png?width=627&height=88&name=ebookcode1.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode1.png?width=627&height=88&name=ebookcode1.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode1.png)

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode2.png?width=622&height=346&name=ebookcode2.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode2.png?width=622&height=346&name=ebookcode2.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode2.png)Great! **The next step is to create a client side JavaScript file.** In this file, we will get a reference of the webpage elements as the divs, the input text where the user types the room number, the button the user clicks, etc. Then we’ll declare some global variable to store things like the room number, the local and remote video and audio streams, the peer connection object, and the TURN/STUN servers used.

We’re also going to connect to *socket.io *server and add a click event to the button in which we’ll send a ‘create or join’ message to the server. Paste the following code in a new file and save it as *client.js. *in the *public *folder.

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode3-1.png?width=617&height=377&name=ebookcode3-1.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode3-1.png?width=617&height=377&name=ebookcode3-1.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode3-1.png)

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode4.png?width=624&height=240&name=ebookcode4.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode4.png?width=624&height=240&name=ebookcode4.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode4.png)

We need to wait for the responses after sending the initial message to the server, so we’re going to set up some event handlers in the same *client.js *file.

When the first participant joins the call, the server creates a new room and emits a ‘joined’ event to them. The same process is repeated on the second participant’s side: The browser receives access to the media devices, stores the stream on a variable and shows the video on the screen. Another action is taking place, too: A ‘ready’ message is sent to the server. Add the following code to the bottom of the *client.js *file.

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode5.png?width=615&height=377&name=ebookcode5.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode5.png?width=615&height=377&name=ebookcode5.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode5.png)

**Up until now, the first step is done.** The server receives the ‘ready’ message and notifies the first participant by sending him the same message. This begins the exchange of information process known as **Signaling**. We need to add the correspondent handlers to our *client.js* file.

When the first participant receives the ‘ready’ message, its callback creates an RTCPeerConnection object and sets the object’s onicecandidate and onaddstream listeners to the onIceCandidate and onAddStream functions, respectively. Se will review these functions later. Finally., it adds the local stream to the peer connection object. After that, it prepares an Offer, which will be stored locally and then sent to the server by the setLocalAndOffer function.

The server relays the offer to the second participant, which in turn completes the same process on the ‘offer’ callback: It creates its own peer connection object, sets its event listeners, stores the offer, and prepares an Answer that will be stored locally and then sent to the server by the setLocalAndAnswer function.

Similar to the offer, the server will relay the answer to the first participant who will store it. While all of this is happening, both peers are exchanging ice candidates by sending ‘candidate’ messages to the server, which in turn relays them to the other client. The ice candidates are added to each client’s peer connection object. Add the following code to the bottom of the *client.js* file.

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode6-1.png?width=621&height=397&name=ebookcode6-1.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode6-1.png?width=621&height=397&name=ebookcode6-1.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode6-1.png)

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode7-1.png?width=614&height=496&name=ebookcode7-1.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode7-1.png?width=614&height=496&name=ebookcode7-1.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode7-1.png)

**Now the second step is done.** When everything is ready, each peer receives the remote stream, then the *onAddStream *function shows it on the screen. Below are the remaining functions of our *client.js *file.

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode8.png?width=625&height=279&name=ebookcode8.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode8.png?width=625&height=279&name=ebookcode8.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode8.png)

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode9.png?width=622&height=392&name=ebookcode9.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode9.png?width=622&height=392&name=ebookcode9.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode9.png)

**Now our three-step flow is complete.** But we still haven’t completed our server. Begin by requiring the needed libraries and setting static hosting on the *public *folder to serve the client files.

**We will define the signaling handlers using socket.io.** First, we’ll have the ‘create or join’ event, which will count the number of clients in the room. If there are no users in the room, this means that the client is the first peer, so a ‘created’ event is sent to them. If there is already one participant in the room, then the client is added to the room and a ‘joined’ event is sent to them. If there are already two participants in the room, then the room is considered full and no more clients are added.

The subsequent events work as relays only, sending the same message received to the other client in the room. Create a new file, paste the following code, and save it on the project folders as *server.js.*

*[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode10.png?width=624&height=180&name=ebookcode10.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode10.png?width=624&height=180&name=ebookcode10.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode10.png)[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode11-1.png?width=503&height=575&name=ebookcode11-1.png) ![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/ebookcode11-1.png?width=503&height=575&name=ebookcode11-1.png)](https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/ebookcode11-1.png)*Now that we have all of the required files, we’re ready to test our application. On the command line, navigate to the project folder and type the following command:

node server.js

Using Google Chrome or Mozilla Firefox, [open this link](http://localhost:3000/) in two separate tabs. Be sure to enter the same room number in both, then click *Go. *

**We created our first video conference application! Cool, isn’t it?**

## Want to leave it to the experts?

#### **Ready to incorporate a video conference app into your business?** We have an experienced team ready and happy to help you. **[Contact us today!](https://webrtc.ventures/contact/)**

[CPaaS](https://blog.webrtc.ventures/tag/cpaas), [Managed Services](https://blog.webrtc.ventures/tag/managed-services), [Events](https://blog.webrtc.ventures/tag/events), [Video Conferencing](https://blog.webrtc.ventures/tag/video-conferencing), [Real Time Weekly](https://blog.webrtc.ventures/tag/real-time-weekly), [WebRTC Architecture](https://blog.webrtc.ventures/tag/webrtc-architecture), [Broadcasting](https://blog.webrtc.ventures/tag/broadcasting), [Medical](https://blog.webrtc.ventures/tag/medical), [WebRTC Live](https://blog.webrtc.ventures/tag/webrtc-live), [Showcase](https://blog.webrtc.ventures/tag/showcase), [Thoughts](https://blog.webrtc.ventures/tag/thoughts), [Vonage](https://blog.webrtc.ventures/tag/vonage), [Daily](https://blog.webrtc.ventures/tag/daily), [Jobs](https://blog.webrtc.ventures/tag/jobs), [Contact Centers](https://blog.webrtc.ventures/tag/contact-centers), [Telehealth](https://blog.webrtc.ventures/tag/telehealth), [Education](https://blog.webrtc.ventures/tag/education), [Technical](https://blog.webrtc.ventures/tag/technical), [General](https://blog.webrtc.ventures/tag/general), [Story of success](https://blog.webrtc.ventures/tag/story-of-success), [The WebRTC.ventures Blog](https://blog.webrtc.ventures/tag/the-webrtc-ventures-blog), [Testing](https://blog.webrtc.ventures/tag/testing), [Gaming](https://blog.webrtc.ventures/tag/gaming), [DevOps](https://blog.webrtc.ventures/tag/devops), [Symbl.ai](https://blog.webrtc.ventures/tag/symbl-ai)

## Related posts

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/WebRTC-Live-86.png?height=200&name=WebRTC-Live-86.png)](https://blog.webrtc.ventures/2023/12/watch-webrtc-live-86-webrtc-live-streaming-the-neverending-hack)

## [Watch WebRTC Live #86: WebRTC Live Streaming - The NeverEnding Hack](https://blog.webrtc.ventures/2023/12/watch-webrtc-live-86-webrtc-live-streaming-the-neverending-hack)

![Picture of Jen Oppenheimer](https://blog.webrtc.ventures/hs-fs/hubfs/Our-Team-Jen.jpg?width=50&name=Our-Team-Jen.jpg) [Jen Oppenheimer](https://blog.webrtc.ventures/author/jen-oppenheimer) 

 Dec 6, 2023 12:00:00 AM

On December 6, 2023, Arin Sime welcomed Ryan Jespersen back to the show to discuss live streaming...

[Read more](https://blog.webrtc.ventures/2023/12/watch-webrtc-live-86-webrtc-live-streaming-the-neverending-hack)

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/telehealth-ecourse-lp.png?height=200&name=telehealth-ecourse-lp.png)](https://blog.webrtc.ventures/2017/09/webrtc-ventures-announces-email-course-hipaa-telehealth-webrtc-video)

## [WebRTC Ventures Announces Email Course - HIPAA WebRTC Video in Telehealth](https://blog.webrtc.ventures/2017/09/webrtc-ventures-announces-email-course-hipaa-telehealth-webrtc-video)

[webrtc](https://blog.webrtc.ventures/author/webrtc) 

 Sep 12, 2017 12:00:00 AM

Webrtc.ventures offers free email course on the future of video in healthcare and telehealth,...

[Read more](https://blog.webrtc.ventures/2017/09/webrtc-ventures-announces-email-course-hipaa-telehealth-webrtc-video)

[![](https://blog.webrtc.ventures/hs-fs/hubfs/Imported_Blog_Media/How-Can-WebRTC_ventures-Help-You-4.png?height=200&name=How-Can-WebRTC_ventures-Help-You-4.png)](https://blog.webrtc.ventures/2019/08/how-can-webrtc-ventures-help-you)

## [How Can WebRTC.ventures Help You?](https://blog.webrtc.ventures/2019/08/how-can-webrtc-ventures-help-you)

[Paige Long](https://blog.webrtc.ventures/author/paige-long) 

 Aug 7, 2019 12:00:00 AM

WebRTC.ventures builds and licenses custom video and voice applications for all sorts of industries...

[Read more](https://blog.webrtc.ventures/2019/08/how-can-webrtc-ventures-help-you)

### WebRTC.Ventures Services

...

- Assess
- Build
- Integrate
- Test
- Deploy & Manage

### Contact Us

...

**Video should be an opportunity, not a headache.**   
 We’re here to build, integrate, assess and optimize, test, and even deploy and manage your live video application. 

[Contact us](https://blog.webrtc.ventures/2019/11/tutorial-how-to-build-a-video-conferencing-application-with-webrtc#contact)

### WebRTC Live

...

 View [past episodes](https://blog.webrtc.ventures/webrtc-live/) of our webinar interview series about the latest webRTC use cases and technical updates. Join our mailing list to learn about upcoming episodes! 

![WebRTC Live](https://blog.webrtc.ventures/hs-fs/hubfs/Template%20Images/widged-bannet.webp?height=90&name=widged-bannet.webp)

![logo-main-light](https://blog.webrtc.ventures/hubfs/logo-main-light.svg "logo-main-light")

We’re one of the few agencies in the world dedicated to WebRTC development. This dedication and experience is why so many people trust us to help bring live video application dreams to life.

 

### Let's get started!

###### **[Contact us today](https://webrtc.ventures/contact/)**

**[info@webrtc.ventures](mailto:info@webrtc.ventures)**

<https://www.linkedin.com/company/webrtc-ventures> <https://www.youtube.com/@WebrtcVentures>

### Join our mailing list

We don't e-mail often (a few times a month max), and it will be worth it when we do! Of course, we respect your privacy and will not share your contact information.

© 2023 WebRTC.ventures, an [AgilityFeat](https://agilityfeat.com/) company / [Privacy Policy](https://webrtc.ventures/privacy-policy//)

```json
{
  "@context" : "https://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Hector Zelaya",
    "url" : "https://blog.webrtc.ventures/author/hector-zelaya"
  },
  "dateModified" : "2024-04-03T18:39:16.565Z",
  "datePublished" : "2019-11-04T05:00:00.000Z",
  "headline" : "Tutorial: How to Build a Video Conferencing Application with WebRTC – WebRTC.ventures",
  "image" : [ "https://blog.webrtc.ventures/hubfs/Imported_Blog_Media/Tutorial_-How-to-Build-a-Video-Conference-App-with-WebRTC.png" ],
  "mainEntityOfPage" : {
    "@id" : "https://blog.webrtc.ventures/2019/11/tutorial-how-to-build-a-video-conferencing-application-with-webrtc",
    "@type" : "WebPage"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://blog.webrtc.ventures/hubfs/logo-main-light.svg"
    }
  }
}
```