Create a multi-tab chat popup

Estimated reading time: 9 minutes

This article will describe the implementation of a web-based chat popup app, having real-time messaging, voice, and video calls that can be opened and viewed simultaneously on multiple-tabs.

Many developers and teams have built chatbots, custome support services, etc using mesibo. Mesibo Messenger is a simple web app, that demonstrates using mesibo APIs to build such applications which supports popups running on a single tab with a single mesibo connection. But, what if you want to build apps where the app runs on multiples tabs?

For example, let’s say you are building a customer support chat app - that will be used by support agents to answer incoming queries from customers. Support teams are generally very busy and may be chatting with multiple customers at any instant. So, a support agent using your chat popup app, needs to open seperate tabs for each customer simulataneously and reply to each of the customers questions.

You can build a chat support app for the above scenario by using Mesibo Chat Popup as a starting point. But, you need to open multiple tabs for the same user. The first approach that you might think of to implement this, would be to open the same page on multiple tabs and initialize mesibo on each tab. But, when you initialize mesibo in one tab, you open a single connection to mesibo servers. This means, when you try to initialize mesibo on another tab, you are attempting to connect to mesibo with the same user. But at any instant, there can be only one mesibo connection per user. So, your earlier connection will be closed by mesibo and you will be logged out on the other tab. You need a way to retain messages while switching between multiple tabs, and this plain approach, clearly will not work.

One way to overcome this problem would be to create new users with every tab. But, this is not recommended. Logically, you only have one user at your end and so, it would be inefficient to have duplicate users. You will also have more latency and bandwidth needs, as you have more connections. Every message sent from each tab on a seperate connection, will have to go to mesibo servers and receive the delivery/read status. Instead you can maintain a single connection to mesibo with

Chat Popup Features

The chat popup app has fully functional real-time messaging, voice, and video calling. Some of the key features are

  • Multi-tab support
  • One-to-One Messaging, Voice and Video Call
  • Group Messaging
  • Read receipts
  • Send Files
  • Record and Send live audio from microphone
  • Send photos captured live using Webcam
  • Chat history
  • Link Preview

You can download and modify the complete source code of the chat popup app from Github

Prerequisites

Before we dive into building a multi-tab chat popup, ensure that you’ve read the following.

It is expected that you are already familiar with the mesibo Javascript API and you have created basic apps using mesibo API. If you have not, ensure that you read the get-started and first-app tutorial mentioned above and try simple apps before proceeding with this tutorial.

Let’s get started.

Download the source code

Download the chat popup app source from Github

git clone https://github.com/mesibo/messenger-javscript.git

Configure Mesibo

Edit mesibo/config.js and provide the AUTH TOKEN & APP ID.

Obtain the AUTH TOKEN and APP ID for a user from Mesibo Console. You can also generate the token for the Web app from Mesibo Demo App Token Geneartor. Provide APP ID as console.

See the Preparation Guide to learn about creating users

const MESIBO_ACCESS_TOKEN = "xxxxxxx";
const MESIBO_APP_ID = "xxxx";
const MESIBO_API_URL = "https://app.mesibo.com/api.php"

If you are hosting mesibo-backend on your server, you need to change the API URL to point to your server.

Configure Popup

Configure the following for setting the displayed user avatar and destination user(to which all messages will be sent to) in mesibo/config.js.

const POPUP_DISPLAY_NAME = "xxxx"
const POPUP_DISPLAY_PICTURE = "images/profile/default-profile-icon.jpg"
const POPUP_DESTINATION_USER = 'xxxx';

Initialize Mesibo

As discussed here the initialization of mesibo API functions and callbacks will be handled by a Web Worker defined in mesibo-worker.js.

So, in your app script initialize mesibo as follows:

// Instead of directly accessing Mesibo APIs like so,
// $scope.mesibo = new Mesibo();
// use a wrapper API that uses a shared worker                          
$scope.mesibo = new MesiboWorker($scope);
$scope.mesiboNotify = $scope;

//Initialize Mesibo
$scope.mesibo.setAppName(MESIBO_APP_ID);
$scope.mesibo.setCredentials(MESIBO_ACCESS_TOKEN);
$scope.mesibo.setListener($scope);
$scope.mesibo.setDatabase("mesibo");
$scope.mesibo.start(); 

When you call MesiboWorker.start, a start message is sent to the shared worker

//mesibo-worker.js
MesiboWorker.prototype.start = function(){
        var post = {op: "start"};
        this.mesibo_worker.port.postMessage(post);
}

On the shared worker end, we will then initialize mesibo

//mesibo-shared.js
if(op == "start"){
                send_mesibo_init(port);
        }

send_mesibo_init = function(port) {
        if(mesibo_api_init) {
                mesibo_api_init = false;

                //initialize mesibo
                send_to_port(port, "init", null);
                active_port = port;
        }
}

In our shared worker, We will only initialize and connect to mesibo once — when a tab connects for the first time. After that, the tab that connected via that port is set to be active. This active mesibo port is used to connect to mesibo, send messages, make calls, etc directly through Mesibo APIs.

//mesibo-worker.js

case "init":
	console.log("Received init message from shared worker");
	this._mesibo_init();
	break;

Sending Messages

For example, to send a message you call the sendMessage function and a message is posted to the shared worker for a sendMessage operation.

//mesibo-worker.js
MesiboWorker.prototype.sendMessage = function(p, id, m){
        var post = {op: "sendMessage", id: id, message: m, params: p};
        this.mesibo_worker.port.postMessage(post);
}

The shared worker receives this message and forwards the message parameters to the active port. Also, all the other connected tabs will be notified of the message sent through a Mesibo_OnMessage callback.

//mesibo-shared.js

if(op == "sendMessage") {
        // send it to active port to send message
        send_to_port(active_port, null, data);

        //Inform all the tabs about new message
        var p = {};
        p.m = data.params;
        p.data = new TextEncoder().encode(data.message);

        console.log("inform everyone..", p);
        send_to_all("Mesibo_OnMessage", p);
}

Now, only the active port will get the sendMessage call and will inturn call Mesibo API function sendMessage to the required destination.

//mesibo-worker.js

case "sendMessage":
        // send message for this and other tab
        if(this.mesibo_api)
                this.mesibo_api.sendMessage(o.params, o.id, o.message);
        break;

Receiving Messages

Similar to sending messages being handled by the active port, only the active port will receive the messages from Mesibo through the Mesibo_OnMessage callback. The active port must forward this to all other connected ports. The active port connected to mesibo, forwards all such data(like Mesibo_OnConnectionStatus, Mesibo_OnMessageStatus, etc) received through callbacks.

//mesibo-worker.js
MesiboNotifyForward.prototype.Mesibo_OnMessage = function(m, data) {
        console.log("Forwarding Mesibo_OnMessage: from "  + m.peer + " id: " + m.id);
        var p = {op: "Mesibo_OnMessage", data:{'m':m, 'data': data} };
        this.worker.port.postMessage(p);
        this.client_notify.Mesibo_OnMessage(m, data);
}

Once the shared worker gets this it sends it to all connected ports.

//mesibo-shared.js
if(op.startsWith("Mesibo_On")) {
        send_to_all(null, data);
}

Similarly, you can define worker functions for sending files, making calls, etc. You also need to switch the active tab when a currently active tab is closed.

Launch the Popup

Open the page index.html in your browser. Click on the floating circle in the bottom-right corner to launch the popup window. You can open index.html simultaneously in as many tabs as you like

chat popup, web, messenger, javascript