Video calling with Zoom has skyrocketed in popularity since the start of the pandemic, for everything from work meetings to courses and lectures. This tutorial explains how to integrate Zoom with TalkJS so that you can schedule meetings directly from your chat. This drastically reduces the time taken to create meetings and saves users needing to move between applications.

Here’s what we’ll be doing in this tutorial:

  • Creating a frontend using HTML, CSS and JavaScript to run a TalkJS chatbox
  • Running a NodeJS server that exposes an API to create meetings
  • Using Zoom's APIs to create a meeting programmatically by clicking a button from your TalkJS chat

We’ll build up the feature step by step in the following sections. If you would rather see the complete example code, see the GitHub repo for this tutorial.

Prerequisites

There are a few prerequisites that you need to satisfy before going further in this tutorial:

  • A TalkJS account. TalkJS provides a ready-to-use chat client for your application. Your account gives you access to TalkJS's free development environment.
  • a Zoom account.
  • An installation of Node.js. We will use Node as the backend server to call our Zoom API.

If you satisfy all these requirements, jump ahead to the next section.

Creating a TalkJS application

With the help of our Getting Started guide, you can easily set up a TalkJS application within minutes. The sample project contains three files for the TalkJS app: an index.html file, a styles.css file, which we’ll look at later, and a script.js file that contains most of our TalkJS code.

Our script.js file looks like this:

const APP_ID = "YOUR_APP_ID";
const conversation = createTalkJSConversation();


async function createTalkJSConversation() {
  await Talk.ready;
  const me = new Talk.User({
    id: "00002",
    name: "Kirsten Doe",
    email: "kirsten.doe@example.com",
    photoUrl: "https://talkjs.com/images/avatar-1.jpg",
    role: "user",
  });
  window.talkSession = new Talk.Session({
    appId: APP_ID,
    me: me,
  });
  const other = new Talk.User({
    id: "00001",
    name: "Mikaela Ross",
    email: "mikaela.ross@example.com",
    photoUrl: "https://talkjs.com/images/avatar-7.jpg",
  });


  const conversation = talkSession.getOrCreateConversation(
    Talk.oneOnOneId(me, other)
  );
  conversation.setParticipant(me);
  conversation.setParticipant(other);


  const chatbox = talkSession.createChatbox();
  chatbox.select(conversation);
  chatbox.mount(document.getElementById("talkjs-container"));
  return conversation;
}

Our index.html file looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>TalkJS Zoom Integration</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
<script>
  (function(t,a,l,k,j,s){
  s=a.createElement('script');s.async=1;s.src="https://cdn.talkjs.com/talk.js";a.head.appendChild(s)
  ;k=t.Promise;t.Talk={v:3,ready:{then:function(f){if(k)return new k(function(r,e){l.push([f,r,e])});l
  .push([f])},catch:function(){return k&&new k()},c:l}};})(window,document,[]);
  </script>
  <script src="script.js"></script>
  <div id="talkjs-container" style="width: 90%; margin: 30px; height: 500px">
    <i>Loading chat...</i>
  </div>
</body>
</html>

The styles.css file is empty right now, but we’ll add to it later.

Adding a custom header

Next, we’re going to add a button to schedule Zoom meetings from within the chat. To do this, we create a custom header for the chat box. First, we’ll hide the existing header. Go back to the script.js file and update your createChatbox call to this:

const chatbox = talkSession.createChatbox({showChatHeader: false});

This hides the existing header completely. To add a custom header, wrap the existing talkjs-container <div> in our index.html file within another <div>. Then, create one more <div> inside this above the talkjs-container <div>. See the structure below:

  <div class="chatbox-container">
    <div class="chatbox-header">
    </div>
    <div id="talkjs-container" style="height: 400px"><i>Loading chat...</i></div>
  </div>

Inside the chatbox-header <div>, add an <a> tag with the class chatbox-header-button. We’re going to use this to make a button with a link to schedule Zoom meetings. Copy the code below to add the button along with an SVG icon for Zoom:

<a class="chatbox-header-button" onclick="createZoomMeeting()">
  <svg class="chatbox-header-button-icon" xmlns="http://www.w3.org/2000/svg" width="36" height="36"
    viewBox="0 0 24 24" fill="currentColor" stroke-width="2" class="ai ai-ZoomFill">          
    <g clip-path="url(#clip0_822_311)">            
      <path fill-rule="evenodd" clip-rule="evenodd"
        d="M24 12c0 6.627-5.373 12-12 12S0 18.627 0 12 5.373 0 12 0s12 5.373 12 12zM6 16.2h9V9.6a1.8 1.8 0 0 0-1.8-1.8h-9v6.6A1.8 1.8 0 0 0 6 16.2zm10.2-2.4l3.6 2.4V7.8l-3.6 2.4v3.6z" />
    </g>
    <defs>
      <clipPath id="clip0_822_311">
        <rect width="24" height="24" />
      </clipPath>
    </defs>
  </svg>        
</a>

Inside the styles.css file, add the following styles:

.chatbox-container {
    width: 420px;
    max-width: 100%;
    margin: auto;
    position: relative;
}


.chatbox-header {
    height: 80px;
    background-color: #E7ECEE;
    border-radius: 10px 10px 0 0;
    border: 1px solid #D0D8DC;
    border-bottom: 0px;
}


.chatbox-header-button-icon {
    color: #fff;
    border-radius: 50%;
    background-color: #2D8CFF;
    position: absolute;
    top: 25px;
    right: 10px;
    border: 1px solid #9b9b9b;
}


.chatbox-header-button-icon:hover {
    color: #2D8CFF;
    background-color: white;
}

You should have a chat box that looks like this:

Adding a handler for creating a Zoom meeting

Next, we need to create a handler that calls our backend server when we click the button, which in turn calls the Zoom API. We’ll set up the backend server in the next section.

Add the following function to your script.js file:

async function createZoomMeeting() {
  const conversationObject = await conversation;
  const serverURL = `http://127.0.0.1:3000/meeting`;
  try {
    const response = await fetch(serverURL, {
      method: "GET",
    });
    const data = await response.json();
    conversationObject.sendMessage("Please join the Zoom meeting " + data.join_url)
  } catch (error) {
    console.log(error);
  }
}

We have the conversation object available globally in the file. We’ll be using this to send the meeting link to our conversation. When you click on the button, this handler gets activated and it calls the backend server’s ‘createZoomMeeting’ endpoint. Once we retrieve the response from the server, we send a message to the conversation with the meeting URL.

Accessing the Zoom APIs

To access the Zoom APIs, you first need a Zoom account. After signing up, visit their App Marketplace to build an application. On the top right hand corner, next to the profile icon, is a dropdown menu labeled Develop. Click on it, and select Build App. In the next page, click Create for the Server-to-Server OAuth application. Enter a name for the app and click Create.

In the next few steps you’ll need to enter some basic information and select the scopes for your app.

Click Continue from the above screen and enter your Company Name, Developer Name and Email Address. WIthout this, you cannot activate the app. Leave the defaults for the Feature section and in the Scopes section, select the following three scopes:

  • View and manage sub account's user meetings
  • View all user meetings
  • View and manage all user meetings

Once you’ve set the scope, you can click on Activate your app. With that you’re all set to call the Zoom APIs from the backend server.

Creating a backend server to call the Zoom API

Zoom doesn’t support CORS, so you’ll need to have a backend server to call the APIs. We’ll create a NodeJS Express server to do this.

First of all, create a .env file to store all your credentials. Retrieve your credentials from the Zoom dashboard and paste it in their respective fields.

ACCOUNT_ID=<YOUR_ACCOUNT_ID>
CLIENT_ID=<YOUR_CLIENT_ID>
CLIENT_SECRET=<YOUR_CLIENT_SECRET>

Now create an npm project from within a folder using the command npm init -y and then install the following dependencies:

npm install cors dotenv express

We’ll use cors to handle cross origin resource sharing, express as the middleware and dotenv to use the environment variables from our .env file in our server code. Create a file called server.js and add the following:

import dotenv from 'dotenv';
import express from 'express';
import cors from 'cors';


dotenv.config();


const app = express();
app.use(cors())


app.listen(3000, () => console.log("Server is up"));

Next, add a single endpoint that generates an access token for Zoom and then creates a meeting using that access token:

app.get('/meeting', async function (req, res) {
   try {
     // Generate Access Token
     const tokenResponse = await fetch(`https://zoom.us/oauth/token?grant_type=account_credentials&account_id=${process.env.ACCOUNT_ID}&client_id=${process.env.CLIENT_ID}&client_secret=${process.env.CLIENT_SECRET}`, {
       method: 'POST'
     });


     const tokenData = await tokenResponse.json();
 
     // Zoom Meeting Data
     const meetingData = JSON.stringify({
       "topic": "Zoom Meeting Created from TalkJS",
       "type": 2,
       "start_time": new Date().toString(),
       "agenda": "Zoom Meeting Created from TalkJS",
       "settings": {
         "join_before_host": true
       }
     });
 
     const createMeetingResponse = await fetch('https://api.zoom.us/v2/users/me/meetings', {
       method: 'POST',
       headers: {
         'Authorization': 'Bearer ' + tokenData.access_token,
         'Content-Type': 'application/json'
       },
       body: meetingData
     });
     const createMeetingData = await createMeetingResponse.json();


     res.send(createMeetingData);
   } catch (error) {
     console.log(error);
   }
 });

We are nesting two API calls within this function. The first API call retrieves the access token using our account ID, client ID and client secret. Once we receive that, we create a data object with the necessary information to create a meeting. Next, we make the second API call to create the meeting, using our access token for authorization. Finally, we send our response back to the frontend.

To start the server, add "start": "node server.js" to the scripts section of your package.json file, and then run npm start.

Styling the header

Finally, the moment has come to see everything in action. Just before we move forward, let’s make some minor UI changes to the header so that it looks like the actual TalkJS header. To do that, add these two tags right under the <div> with the class chatbox-header:

<div id="avatar"></div>
<p id="header-alt"><span id="header-username">Username</span></p>

Then, in the script.js file, just before you return the conversation object in the main function, add these lines:

const headerUsername = document.getElementById('header-username');
headerUsername.textContent = other.name;
document.getElementById('avatar').style.backgroundImage = "url(" + other.photoUrl + ")";

Finally, add these styles:

#avatar {
    position: absolute;
    height: 50px;
    width: 50px;
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
    border-radius: 50%;
    border: 2px solid #eee;
    left: 10px;
    top: 15px;
}


#header-alt {
    position: absolute;
    left: 70px;
    top: 18px;
    font-size: 16px;
    font-family: 'Roboto', sans-serif;
}

Conclusion

You should now have a working Zoom link button integrated with your chat app! Clicking the button creates a Zoom meeting and returns its link. Anyone on the chat at that point can click on the link to join the meeting:

For the full example code for this tutorial, see our GitHub repo.

If you want to learn more about TalkJS, here are some good places to start:

You’ve successfully subscribed to TalkJS
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Your link has expired
Success! Check your email for magic link to sign-in.