Build a Video Chat App with JavaScript, Vue.js and Programmable Video

August 30, 2018
Written by
Onwuka Gideon
Contributor
Opinions expressed by Twilio contributors are their own

WOjvA69uQixmylNTlqDapeWEHZeOiXq4JCtg7qoz9B5OygXpx-6M8syXDdyvrlDbLdCBSG-SFEyICyeGN56W8Vv1Ap8k3hPTu6jM5iwl1IxH6mqaKyvrwITKBqsrXVNgPtqSYEza

This article is for reference only. We're not onboarding new customers to Programmable Video. Existing customers can continue to use the product until December 5, 2024.


We recommend migrating your application to the API provided by our preferred video partner, Zoom. We've prepared this migration guide to assist you in minimizing any service disruption.

Vue.js is a powerful and approachable JavaScript framework that focuses on building user interfaces. One of the reasons why I like Vue is because it is easily adoptable. In this article, I will show you how to build a video chat application using Vue.js and Twilio Programmable Video. In the app, the participants will provide a username to get access to the chat app, then join a room (on the left of the screenshot below) to start chatting.

Here is a preview of what we'll be building:

Prerequisites

Basic knowledge of the following will be useful, but extensive knowledge is not required:

Before you continue, make sure you have Node.js installed on your system.

Getting Your Twilio API Keys

The first step to using Twilio Programmable Video chat is to get an access token. Twilio will generate a token using your API Keys. Twilio uses this token to make sure people using your app are authorised to do so.

To get your Twilio API Keys, login or sign up for a free account. Once you are logged in, take note of the ACCOUNT SID on your dashboard.

Next, go to All Products & Services by clicking the icon on the left as shown in the image below:

On the popup that appears, click on Programmable Video. The Programmable Video dashboard will be loaded for you.

Next, click on Tools, then click on API Keys, and then click on the + icon as seen in the image below:

Lastly, input a friendly name in the FRIENDLY NAME input field and then click on Create API Key.

The page that will be loaded contains your API Keys. Note down your API SID key, SECRET key, and also your ACCOUNT SID key. We'll make use of these keys in the next section.

Generating the Access Token

I have written a basic Node.js app for generating tokens. Go ahead and clone the repository on Github, then start it up. You’ll find instructions on how to get the app up and running on the Readme. You'll need your API Keys.

💡 You can make use of any programming language to generate the token, provided you have your Twilio API Keys.

After installation, make sure to keep the server running. We'll connect to the server to generate token later on.

Setting Up the Vue App

Vue provides an official CLI for scaffolding a new Vue.js project. First, you'll need to install the Vue CLI globally on your system (if you don't have it installed already). Then, you'll create a new Vue project with the CLI commands .

To create a new Vue project, run the following commands on your command prompt:

# Install vue cli globally on your system
$ npm install -g @vue/cli

# Create a new vue project (In the prompt that appears, press enter to select the default preset.)
$ vue create video-chat

# Change your directory to the project directory
$ cd video-chat

# Run the app!
$ npm run serve

If everything went well, your final command line output should be similar to this:

Now, visiting http://localhost:8080 will take you to a Vue default page which indicates that your setup is complete and successful. While the build is running, open a new terminal from where you can install dependencies. Also, make sure to change your directory to the project's root directory.

Install Dependencies

Twilio provides a JavaScript SDK that makes it easy to communicate with its Programmable Video API.

Add Twilio JavaScript SDK to the project by running the below command:

   $ npm install twilio-video

We'll use the axios module to make requests to our server for an access token. Add the axios module by running the below command:

 $ npm install axios

 Make sure you are in the root folder of the project before running the commands.

Twilio Programmable Video API Overview

Now that everything is set up, let's define some terms associated with the Twilio Programmable Video API:

  • Room: This represents a real-time audio, video, and/or screen-share session.
  • Peer-to-peer Room: This is a type of room in which media flows directly between participants. It supports up to 10 participants.
  • Group Room: This is a type of room in which media is routed through Twilio's Media Servers. Up to 50 participants can be accomodated in this room.
  • Participants: This represents client applications that are connected to a room and sharing audio and/or video media with one another.
  • Tracks: This represents the individual audio and video media streams that are shared within a Room.
  • LocalTracks: This represents the audio and video captured from the local microphone and camera.
  • RemoteVideoTracks: This represents the audio and video tracks from other participants connected to the room.

Composing the Chat Interface

It's time to start creating the interface for our app. We'll use Bootstrap to help design the app. To add Bootstrap to the project, update the code in public/index.html with the following:

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
   <title>video-chat</title>
 </head>
 <body>
   <noscript>
     <strong>We're sorry but video-chat doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
   </noscript>
   <div id="app"></div>
   <!-- built files will be auto injected -->
 </body>
</html>

Here, we have added bootstrap css since we'll be using it to design our app.

In Vue, components are elements of the full app that encapsulate reusable code. The next thing we'll do is to divide our app into smaller components so we can build them separately:

In the above image, we have:

  • [1] - Our main component that will house other components. This is usually the App.vue file.
  • [2] - Video Component. The component that we'll use to list the Local of Remote tracks.
  • [3] - AddRoom Component. Component for adding new rooms.
  • [4] - Rooms Component. Component for listing rooms.
  • [5] - Logs Component. For displaying logs.

We will be creating this component in the next sections.

Triggering and Listening to Events

Before we start creating our components, let's talk about how our components will interact with each other.

At times, child components need to communicate with one another. For example, the AddRoom component will contain a form which will be used to create a new room and the Rooms component needs to know when a room form is submitted so it can list it.

When the user submits a new room to be created in the AddRoom component, our app will send a trigger to the Rooms component so it knows what has happen and take action.

This can be achieved using event bus, which is a Vue instance.

Create a new file called Event.js in the src folder and add the following code to it:

import Vue from 'vue'

export const EventBus = new Vue()

Here, we are exporting a vue instance.

When there is a need to trigger or listen to an event in a component, we'll import the Event.js file.

Putting all the Components together

Although we've not created any component yet, it will make sense to bring all the components that we'll create together now. So that when you build along, you'll be able to see the changes.

Now let's bring all the components we'll create together. We'll import all components to App.vue which is the main entry component file.

Update src/App.vue with the following code:

<template>
 <div class="container-fluid chat_container" id="app">
     <div class="row" v-if="authenticated">
       <Rooms />
       <Video :username="username"/>
       <Logs />
     </div>
     <div class="row" v-else>
       <div class="username">
           <form class="form-inline" @submit.prevent="submitUsername(username)">
             <div class="form-group mb-2">
                 <input type="text" class="form-control" v-model="username" >
             </div>
             <button type="submit" class="btn btn-primary mb-2 Botton">Submit</button>
         </form>
       </div>
     </div>
 </div>
</template>

Here, you will see that we've added - <Rooms />, <Video>, and the <Logs /> component.

Also, we used the v-if directive to determine which view to display to the user when they load up the app. Since we need a username to create an access token for each user, once they open the app, we'll display a form for them to supply their username.

Once the user enters a username we'll display the app view for chatting. The app uses the authenticated data to determine which view to display. We haven’t declared the authenticated data yet, we'll do this next.

Also, we passed down the username provided by the user to the Video component as property.

Next, add the following code to src/App.vue immediately after the closing </template> tag:

<script>
// import components
import Rooms from './components/Rooms'
import Video from './components/Video'
import Logs from './components/Logs'
import AddRoom from './components/AddRoom'

export default {
 name: 'App',
 data() {
   return {
     username: "",
     authenticated: false
   }
 },
 components: {
   Rooms,
   Video,
   Logs,
   AddRoom
 },
 methods: {
   submitUsername(username) {
      if(!username) {
        return alert('please provide a username');
      }

      this.authenticated = true;
   }
 }
 }
</script>

<style>
 #app {
   font-family: 'Avenir', Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
   text-align: center;
   color: #2c3e50;
   margin-top: 60px;
   background: #2c3e50;
 }
 .box {
   border: 1px solid gray;
 }

 .username {
   margin: 12px auto 7px auto;
   color: wheat;
 }

   .Botton {
   color: #fff;
   background-color: #4d555f;
   border-color: #303840;
   padding: 8px;
   font-weight: bolder;
 }
</style>

First, we imported all components that we'll create to this file.

In the data method, notice that username is empty and authenticated is false. When the user enters their username, we'll update the username data. Then, if the provided username is valid (not empty, in our case), we'll set authenticated to true.

When the authenticated data is set to true, the user can now start chatting.

NOTE: You'll get an error on the page when you visit http://localhost:8080/. It's okay to get the errors for now because we've not created the components we imported yet.

AddRoom Component

Next, let's create the AddRoom component which will contain a form for adding a new room.

Create a new file called AddRoom.vue in the src/components folder and add the following code to it:

<template>
   <div class="row roomForm">
       <form class="form-inline" @submit.prevent="createNewRoom(room_name)">
           <div class="form-group mb-2">
               <input type="text" class="form-control" v-model="room_name" >
           </div>
           <button type="submit" class="btn btn-primary mb-2 createRoomBotton">Create Room</button>
       </form>
   </div>
</template>

<script>
import { EventBus } from '../Event'

export default {
 name: "AddRoom", // Component name
 data() {
   return {
    room_name: "",
   }
 },
 methods: {
   createNewRoom(name) {
       if(!name) {
         alert("please provide a room name");
         return
       }

       this.room_name = '';
       EventBus.$emit('new_room', name);
   }
 }
}
</script>

<style>
 .roomForm {
     margin-left: auto;
     margin-right: auto;
     margin-top: 30px;
     width: 100%;
 }
 .createRoomBotton {
   color: #fff;
   background-color: #4d555f;
   border-color: #303840;
   padding: 8px;
   font-weight: bolder;
 }
</style>

If you are familiar with Vue, you should have an idea of what is going on here. This is one of the ways of creating a Vue component known as the single file component.

Here, we have three sections: <template>, <script>, and <style>. All HTML elements goes to the <template> tag, all JavaScript code goes to the <script> tag, and the styling for the component goes to the <style> tag.

Also, we'll use the v-model directive to create a two-way data bindings for the form input. The @submit.prevent directive will prevent the form from submitting normally, and thereby call the createNewRoom() method.

We'll also use the createNewRoom() method to trigger an event named new_room using  EventBus.$emit('new_room', name);.

The first parameter passed to the $emit() method is the name of the event while the second parameter is the value we want to pass along, which in our case is the room name. We'll listen to this event in the Rooms component which we'll create next.

 

Rooms Component

We'll use the Rooms component to list rooms. To add the Rooms component, create a new file named Rooms.vue in the src/components folder. Then add the following code to it:

<template>
   <div class="col-md-3 rooms">
       <div class="room" v-for="room in rooms" v-bind:key="room.id" @click="showRoom(room.name)">
           {{room.name}}
       </div>
   <AddRoom /> <!-- Imported AddRoom component -->
   </div>
</template>

<script>
import { EventBus } from '../Event'
import AddRoom from '../components/AddRoom'

export default {
 name: "Rooms", // Name of the component
 data() {
   return {
       rooms: [
           {id: 1, name: 'PHP Room'},
           {id: 2, name: 'Python Room'},
           {id: 3, name: 'Daily standup'}
       ],
       roomCount: 3, // used to keep track of the number of rooms present
       loading: false, // indicate when tracks in a room is being loaded
   }
 },
 components: {
   AddRoom // imported AddRoom component
 },
 created() {
 },
 methods: {
   showRoom(room) {
       EventBus.$emit('show_room', room);
   }
 }

}
</script>

<style scoped> /* scoped attribute is used here so the styling applies to this component alone */
   .rooms > .room {
       border: 1px solid rgb(124, 129, 124);
       padding: 13px;
       margin: 3px 0px;
       color: ghostwhite;
   }

   .rooms {
     border: 1px solid rgb(64, 68, 64);
     cursor: pointer;
   }
</style>

The v-for directive in the <template> tag will render the rooms. Also, we'll use the @click directive to listen to click events from the user. When a room is clicked, we'll load up the chat for that particular room by calling showRoom() method.

Next, we'll use the showRoom() method to trigger an event - 'show_room'. When a room is clicked, we'll call the showRoom() method, which will be responsible for listing tracks for the particular room.

We also have some default rooms as seen in the data() method which we have hard-coded to the app. We'll list these rooms once the app is loaded.

Let's listen to new_room event. In the AddRoom component, there is a form for adding a new room. Once the room form is submitted, a new_room event will be triggered. We need to know when this happens in this component (Rooms component) so we can append the newly created room to the list of rooms. To achieve this, update the created method in src/components/Rooms.vue, which is empty with the following code :

 created() {
   EventBus.$on('new_room', (data) => {
       this.roomCount++;
       this.rooms.push({id: this.roomCount, name: data});
   });
 },

The created() method is a Vue method for executing statements as soon as Vue is loaded.

 

Log Component

It feels good to see things as they happen. We'll add logs of all the action taking place in a room, such as when a user joins a room or leave a room.

Create a new file named Logs.vue in src/components/ folder and add the following code to it:

<template>
    <div class="col-md-3 box">
        <div class="log"  v-for="log in logs" v-bind:key="log.id">
            {{log.message}}
        </div>
    </div>
</template>

<script>

import { EventBus } from '../Event'
import axios from 'axios'

export default {
  name: "Logs",
  data() {
    return {
        logs: [],
        logCount: 0
    }
  },
  created() {
    EventBus.$on('new_log', (message) => {
        this.logs.push( {id: this.logCount, message: message} );

        this.logCount += 1; 
    })
  },
}
</script>

<style scoped>
    .log {
        border: 1px solid rgb(124, 129, 124);
        padding: 13px;
        margin: 3px 0px;
        color: ghostwhite;
    }
</style>

Here, in the data() method, we've have defined an array for holding logs. When there is a new log, we'll append the log to the array.

Then with v-for directive, we'll loop through the log array and display the logs to the view.

In the created() method, we are actively listening for a new_log event. When there is a new log, we'll append the log to the logs array.

 

Video Component

We'll use this component to display local and remote tracks. When a user clicks on a room, we will initiate a chat for that room and display the tacks to the respective DOMs.

Create a Video.vue file in src/components and add the following code to it:

<template>
   <div class="col-md-6 box">
       <div class="roomTitle">
           <span v-if="loading"> Loading... {{roomName}}</span>
           <span v-else-if="!loading && roomName"> Connected to {{roomName}}</span>
           <span v-else>Select a room to get started</span>
       </div>
       <div class="row remote_video_container">
           <div id="remoteTrack"></div>
       </div>
       <div class="spacing"></div>
       <div class="row">
           <div id="localTrack"></div>
       </div>
   </div>
</template>

<script>
import { EventBus } from '../Event'
import Twilio, { connect, createLocalTracks, createLocalVideoTrack } from 'twilio-video'
import axios from 'axios'

export default {
 name: "Video",
 data() {
   return {
     loading: false,
     data: {},
     localTrack: false,
     remoteTrack: '',
     activeRoom: '',
     previewTracks: '',
     identity: '',
     roomName: null,
   }
 },
 props: ['username'], // props that will be passed to this component
 created() {},
 methods: {
   // Generate access token
   async getAccessToken() {},

   // Trigger log events 
   dispatchLog(message) {},

   // Attach the Tracks to the DOM.
   attachTracks(tracks, container) {},

    // Attach the Participant's Tracks to the DOM.
   attachParticipantTracks(participant, container) {},

   // Detach the Tracks from the DOM.
   detachTracks(tracks) {},

   // Detach the Participant's Tracks from the DOM.
   detachParticipantTracks(participant) {},

   // Leave Room.
   leaveRoomIfJoined() {},

   // Create a new chat
   createChat(room_name) {},
   }
}
</script>

<style >
   .remote_video_container {
     left: 0;
     margin: 0;
     border: 1px solid rgb(124, 129, 124);
   }
   #localTrack video {
       border: 3px solid rgb(124, 129, 124);
       margin: 0px;
       max-width: 50% !important;
       background-repeat: no-repeat;
   }
   .spacing {
     padding: 20px;
     width: 100%;
   }
   .roomTitle {
       border: 1px solid rgb(124, 129, 124);
       padding: 4px;
       color: dodgerblue;
   }
</style>

In the <template> tag, we have a couple of conditions that check if we are loading up a chat. So if we are initiating a chat, we'll display  Loading... {{roomName}}. If we are not loading a chat and the roomName has been set, we'll display Connected to {{roomName}}. Otherwise, we'll display Select a room to get started.

In the data() method, we have initiated some variables which we are going to use soon.

We also imported the Twilio JavaScript package to this component, which will make it easy to interact with Twilio.

Also, in the methods block, there are a couple of empty functions we have defined in there. We'll be adding their respective code step by step as we proceed in this tutorial.

Now that we have all the components. The page should now look like below:

When you enter a username and submits:

Starting up the chat

To start up a chat, we need a token. Let's add a function for generating these access tokens. Add the below code to the getAccessToken() block in src/components/Video.vue:


async getAccessToken() {
  return await axios.get(`http://localhost:3000/token?identity=${this.username}`);
},

💡 http://localhost:3000/ is the address of the Node.js server we created earlier.

Here, we are connecting to our Node.js server to generate a token.

this.username is passed as a props to the Video component. We'll ask a user to provide a username before they can access the chat. Then, we'll use this username to uniquely identify each user using our application. We'll implement this soon.

Next, add a function for triggering a log events. Add the below code to the dispatchLog(message) function in src/components/Video.vue:

// Trigger log events 
   dispatchLog(message) {
       EventBus.$emit('new_log', message);
   },

Next, add a function for attaching track to the DOM. Add the below code to the attachTracks(tracks, container) function in src/components/Video.vue:

 // Attach the Tracks to the DOM.
   attachTracks(tracks, container) {
       tracks.forEach(function(track) {
           container.appendChild(track.attach());
       });
   },

Next, add a function for attaching the participant's tracks to the DOM. Add the below code to the attachParticipantTracks(participant, container) function block in src/components/Video.vue:

   // Attach the Participant's Tracks to the DOM.
   attachParticipantTracks(participant, container) {
       let tracks = Array.from(participant.tracks.values());
       this.attachTracks(tracks, container);
   },

Next, add a function for removing attached tracks from the DOM. Add the below code to the methods: { } block in src/components/Video.vue:

// ...

<script>
import { EventBus } from '../Event'
import Twilio, { connect, createLocalTracks, createLocalVideoTrack } from 'twilio-video'
import axios from 'axios'

export default {
name: "Video",
data() {
  return {
    loading: false,
    data: {},
    localTrack: false,
    remoteTrack: '',
    activeRoom: '',
    previewTracks: '',
    identity: '',
    roomName: null,
  }
},
props: ['username'], // props that will be passed to this component
created() {},
 methods: {
     async getAccessToken() {
       return await axios.get(`http://localhost:3000/token?identity=${this.username}`);
     },
     // Trigger log events
   dispatchLog(message) {
       EventBus.$emit('new_log', message);
   },
    // Attach the Tracks to the DOM.
  attachTracks(tracks, container) {
      tracks.forEach(function(track) {
          container.appendChild(track.attach());
      });
  },
     // Attach the Participant's Tracks to the DOM.
  attachParticipantTracks(participant, container) {
      let tracks = Array.from(participant.tracks.values());
      this.attachTracks(tracks, container);
  },
     // Detach the Tracks from the DOM.
  detachTracks(tracks) {
      tracks.forEach( (track) => {
          track.detach().forEach((detachedElement) => {
             detachedElement.remove();
          });
      });
  },
 }
}
</script>

Next, add a function for removing the attached participant's tracks from the DOM. Add the below code to the detachParticipantTracks(participant) function block in src/components/Video.vue:

   // Detach the Participant's Tracks from the DOM.
   detachParticipantTracks(participant) {
       let tracks = Array.from(participant.tracks.values());
       this.detachTracks(tracks);
   },

Finally, add a function for leaving a room a user joined. Add the below code to the leaveRoomIfJoined() function block in src/components/Video.vue:

   // Leave Room.
   leaveRoomIfJoined() {
       if (this.activeRoom) {
           this.activeRoom.disconnect();
       }
   },

Let's create a  function for creating a chat room. Add the following to the createChat(room_name) function block of src/components/Video.vue:

 


  createChat(room_name) {
      this.loading = true;
      const VueThis = this;

      this.getAccessToken().then( (data) => {
          VueThis.roomName = null;
          const token = data.data.token;
          let connectOptions = {
              name: room_name,
              // logLevel: 'debug',
              audio: true,
              video: { width: 400 }
          };
          // before a user enters a new room,
          // disconnect the user from they joined already
          this.leaveRoomIfJoined();
        
          // remove any remote track when joining a new room
          document.getElementById('remoteTrack').innerHTML = "";

          Twilio.connect(token, connectOptions).then(function(room) {
              // console.log('Successfully joined a Room: ', room);
              VueThis.dispatchLog('Successfully joined a Room: '+ room_name);

              // set active toom
              VueThis.activeRoom = room;
              VueThis.roomName = room_name;
              VueThis.loading = false;

              // Attach the Tracks of all the remote Participants.

              // When a Participant joins the Room, log the event.

              // When a Participant adds a Track, attach it to the DOM.

              // When a Participant removes a Track, detach it from the DOM.

              // When a Participant leaves the Room, detach its Tracks.

              // if local preview is not active, create it

         });
      })
   },

In the preceding code:

  • this.getAccessToken() will fetch access token for a user from the Node.js server we created earlier.
  • connectOptions is a variable that holds the option for creating a new chat in Twilio. Here we passed in the room name, video frame width, etc.
  • Next, we call the Twilio.connect method which will create the room which requires a token.

Next, let's attach all tracks of all participants already in the room before a user joins.

Add the following code to the Twilio.connect method block in src/components/Video.vue file just after the // Attach the Tracks of all the remote Participants. comment. 


              room.participants.forEach(function(participant) {
                  let previewContainer = document.getElementById('remoteTrack');
                  VueThis.attachParticipantTracks(participant, previewContainer);
              });

Next, log an event when a user joins a room. Add the following code to the Twilio.connect method block in src/components/Video.vue file just below the // When a Participant joins the Room, log the event. comment:

                        room.on('participantConnected', function(participant) {
                              VueThis.dispatchLog("Joining: '" + participant.identity + "'");
                       });

Next, add tracks to the DOM as soon as a user attaches a new track. Add the following code to the Twilio.connect method block in src/components/Video.vue file just below the // When a Participant adds a Track, attach it to the DOM. comment:

               room.on('trackAdded', function(track, participant) {
                   VueThis.dispatchLog(participant.identity + " added track: " + track.kind);
                   let previewContainer = document.getElementById('remoteTrack');
                   VueThis.attachTracks([track], previewContainer);
               });

When a participant removes a track, we need to remove the track from the DOM. Add the following code to the Twilio.connect method block in src/components/Video.vue file just below the // When a Participant removes a Track, detach it from the DOM. comment:

               room.on('trackRemoved', function(track, participant) {
                   VueThis.dispatchLog(participant.identity + " removed track: " + track.kind);
                   VueThis.detachTracks([track]);
               });

Next, let's remove the tracks of a participant from the DOM as soon as they exit the chat. Add the following code to the Twilio.connect method block in src/components/Video.vue file just below the // When a Participant leaves the Room, detach its Tracks.:

               room.on('participantDisconnected', function(participant) {
                   VueThis.dispatchLog("Participant '" + participant.identity + "' left the room");
                   VueThis.detachParticipantTracks(participant);
               });

At times, before joining a room, you want to see how you look. Let's display a local track to the DOM.

Finally, add the following code to the Twilio.connect method block in src/components/Video.vue file below the // if local preview is not active, create it comment:

              if(!VueThis.localTrack) {

                  createLocalVideoTrack().then(track => {
                    let localMediaContainer = document.getElementById('localTrack');

                    localMediaContainer.appendChild(track.attach());
                    VueThis.localTrack = true;
                  });
              }

If you've followed closely, your Video.vue file should look like this.

Once Vue is initiated, we'll start listening to events for when a user wants to enter a new room.
To do that, add the following code to the the created() method block of src/components/Video.vue component:

// ...
     EventBus.$on('show_room', (room_name) => {
         this.createChat(room_name);
     })

   // When a user is about to transition away from this page, 
   // disconnect from the room, if joined.
   window.addEventListener('beforeunload', this.leaveRoomIfJoined);

// ...

Now, when there is a show_room event, we'll call the function we just created above - createChat,  to create a chat for that room.

Wrapping it Up

Well done! To test what you have built, load up the application in different tabs on your browser, fill in your username, and then click on any room to start communicating. 

In this tutorial, you have seen how to add video chat to your Vue.js application using Twilio Programmable Video chat technology.

One more thing. We used a simple means to get a username for those using the application, but this method isn’t quite secure. If what you are building is not meant to be publicly accessible, you should consider a means of authenticating your users, so that only users you trust can use the app. You can check out https://www.twilio.com/docs/authy for authenticating users. You can also get the full app on Github.

If you have any questions or contributions, I'll love to hear from you. You can reach me on Twitter: @onwuka_gideon.