Build a group chat app in JavaScript and Pusher
Tags: vue, pusher
Published: 2018-01-09 23:38:07

---
title: Build a group chat app in JavaScript and Pusher
published: true
description: 
tags: vue.js, pusher
---

The ability to group chat with friends and colleagues through group chat applications like WhatsApp, Facebook Messenger etc has improved interactions among friends and colleagues who can all chat from wherever they might be and still get the feeling of being all physically present.

In this tutorial, we’re going to build a group chat app in JavaScript and Pusher. Though the app will be basic, it will have some of the features a typical group chat app would have, such as the number of users in the group, notifications when a new user joins the group and finally, display chat messages to all users in the group in real-time. We’ll be using Node.js (Express) as the application server, Vue.js on the front-end and Pusher for realtime communication between our server and front-end.

This tutorial assumes you already have Node.js and NPM installed on your computer.

Let’s take a quick look at what we’ll be building:

![](https://blog.pusher.com/wp-content/uploads/2017/04/how-to-build-a-group-chat-app-in-javascript-and-pusher_demo.gif)


The complete source code is available on [Github](https://github.com/ammezie/pusher-group-chat) for reference.

Let’s get started!

## Create A Pusher App

If you don’t have one already, create a free Pusher account [here](https://pusher.com/signup) then log in to your dashboard and create an app. Take note of your app credentials as we’ll be using them shortly. You can find your app credentials under the Keys section on the Overview tab.

## Create Node.js Server

Having created our Pusher app and gotten our app credentials, we can move on to creating the Node.js server. As stated above, we’ll be using Express as our Node.js framework. Initialize a new Node.js project by using the following command:


    mkdir pusher-group-chat
    cd pusher-group-chat
    npm init -y

Next, we’ll install Express, Pusher’s Node.js package and some other dependencies that our app will need:


    npm install express body-parser express-session dotenv pusher --save

You will noticed we installed the `dotenv` package which will allow us to pull details from an environment variable from a `.env` file.

The rest of this tutorial assumes you’re already `cd` to the `pusher-group-chat` directory as subsequent commands will be run from within that directory.

Now let’s start fleshing the server, run command to create a new file name `server.js`:


    touch server.js

Open the newly created file and paste the code below into it:


    // server.js
    require('dotenv').config();
    const express    = require('express');
    const path       = require('path');
    const bodyParser = require('body-parser');
    const session    = require('express-session');
    const Pusher     = require('pusher');
    
    const app = express();
    
    // Session middleware
    app.use(session({
        secret: 'somesuperdupersecret',
        resave: true,
        saveUninitialized: true
    }))
    
    // Body parser middleware
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    
    // Serving static files
    app.use(express.static(path.join(__dirname, 'public')));
    
    // Create an instance of Pusher
    const pusher = new Pusher({
        appId:     process.env.PUSHER_APP_ID,
        key:       process.env.PUSHER_APP_KEY,
        secret:    process.env.PUSHER_APP_SECRET,
        cluster:   process.env.PUSHER_APP_CLUSTER,
        encrypted: true
    });
    
    app.listen(3000, () => {
        console.log('Server is up on 3000')
    });

First, we create a basic Express server and enable some middleware that the server will use. The `session` middleware will allow us to save a user’s details in session for later use. The `body-parser` middleware will allow us get form data. Then we serve static files from `public` directory.

Next, we create an instance of Pusher. As you can see, we’re loading our Pusher app credentials from environment variables from a `.env` (which we’re yet to create) file. Lastly, we start the server on port `3000`.

Before we move to the other part of the server, let’s create the `.env` file we talked above:


    touch .env

And paste the lines below into it:


    // .env
    PUSHER_APP_ID=xxxxxx
    PUSHER_APP_KEY=xxxxxxxxxxxxxxxxxxxx
    PUSHER_APP_SECRET=xxxxxxxxxxxxxxxxxxxx
    PUSHER_APP_CLUSTER=xxxx

Remember to replace the xs with your Pusher app credentials.


## Adding Routes

Now let’s add the necessary routes our server will need. Open `server.js` and add the following code to it just after where we created an instance of Pusher:


    // server.js
    
    ...
    
    app.get('/', (req, res) => {
        res.sendFile('index.html');
    });
    
    app.post('/join-chat', (req, res) => {
        // store username in session
        req.session.username = req.body.username;
        res.json('Joined');
    });
    
    app.post('/pusher/auth', (req, res) => {
        const socketId = req.body.socket_id;
        const channel = req.body.channel_name;
        // Retrieve username from session and use as presence channel user_id
        const presenceData = {
            user_id: req.session.username
        };
        const auth = pusher.authenticate(socketId, channel, presenceData);
        res.send(auth);
    });
    
    app.post('/send-message', (req, res) => {
        pusher.trigger('presence-groupChat', 'message_sent', {
            username: req.body.username,
            message:  req.body.message
        });
        res.send('Message sent');
    });
    
    ...

In the snippet above, the first route will render the `index.html` which is the main entry point of our app when we hit the `/` endpoint. Next, we define the `/join-chat` endpoint which will be called when a user fills the input field to join the chat. We get the username entered by the user and save it in the session. Because we’ll be using a presence channel for our group chat app, we need to implement an auth API which will authenticate the user request on the server side. So the `/pusher/auth` endpoint will be called automatically when a user subscribes to our chat. We pass along the user’s username retrieved from the session to Pusher’s `authenticate` method so it will be available on the client side when a user has subscribed to the channel. Lastly, we create the `/send-message` route that uses Pusher to broadcast a `message_sent` event to the channel `presence-groupChat`. Typically, within the `/send-message` route is where you will persist the message into a database, but for the purpose of this tutorial and to keep things simple, we won’t be persisting messages to the database.

That’s all on the server side.

## Setup Chat App Frontend

Let’s move on to building our app front-end. We talked about `index.html` which will be the main entry point of our app and recall that we set up our server to render static files from within the `public` directory. Now we’ll create the directory and the file.


    mkdir public
    cd public
    touch index.html

And paste the following code into it:


    <!-- public/index.html -->
    
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>Group Chat App with Vue.js and Pusher</title>
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
        <style>
          body {
            padding-top: 100px;
          }
          .chat {
                list-style: none;
                margin: 0;
                padding: 0;
            }
            .chat li {
                margin-bottom: 10px;
                padding-bottom: 5px;
                border-bottom: 1px dotted #B3A9A9;
            }
            .chat li .chat-body p {
                margin: 0;
                color: #777777;
            }
            .panel-body {
                overflow-y: scroll;
                height: 350px;
            }
            ::-webkit-scrollbar-track {
                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
                background-color: #F5F5F5;
            }
            ::-webkit-scrollbar {
                width: 12px;
                background-color: #F5F5F5;
            }
            ::-webkit-scrollbar-thumb {
                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
                background-color: #555;
            }
        </style>
      </head>
      <body>
        <div class="container" id="app">
          <div class="row">
            <div class="col-md-6 col-md-offset-3">
              <div class="panel panel-info">
              </div>
            </div>
          </div>
        </div>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <script src="https://unpkg.com/vue"></script>
        <script src="//js.pusher.com/4.0/pusher.min.js"></script>
        <script src="./app.js"></script>
      </body>
    </html>

Basic Bootstrap webpage with some few stylings. As started in the introductory section of this tutorial, we’ll be using Vue.js. So we pull in Vue, Axios (will be used to make AJAX request to our server) and of course the Pusher JavaScript library. We also reference our own JavaScript file which will contain all our Vue.js specific code.

Now let’s add the main section of the chat app. Open `index.html` and add the following code immediately after the div with class `panel panel-info`:


    <!-- public/index.html -->
    
    <div class="panel-heading">
      Group Chats <span class="badge">{{ members.count }}</span>
    </div>
    <div class="panel-body">
      <div v-if="joined">
        <em><span v-text="status"></span></em>
        <ul class="chat">
          <li class="left clearfix" v-for="message in messages">
            <div class="chat-body clearfix">
              <div class="header">
                <strong class="primary-font">
                  {{ message.username }}
                </strong>
              </div>
              <p>
                {{ message.message }}
              </p>
            </div>
          </li>
        </ul>
        <div class="panel-footer">
          <div class="input-group">
            <input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Type your message here..." v-model="newMessage" @keyup.enter="sendMessage">
            <span class="input-group-btn">
              <button class="btn btn-primary btn-sm" id="btn-chat" @click="sendMessage">Send</button>
            </span>
          </div>
        </div>
      </div>
      <div v-else>
        <div class="form-group">
          <input type="text" class="form-control" placeholder="enter your username to join chat" v-model="username" @keyup.enter="joinChat">
        </div>
        <button class="btn btn-primary" @click="joinChat">JOIN</button>
      </div>
    </div>

We have added Vue.js to the webpage, so we can start using it. We are displaying the number of users that have joined the group chat next to the Group Chat heading. Using Vue.js conditional rendering, we will only show the chat form when the user has joined (that is, entered his/her username) the group chat, else the user will be shown a form to enter a username to join chat. When the user clicks the JOIN button or presses ENTER while within the username input field, the `joinChat` method will be triggered. We also bind the username input field with the `username` data so we can easily pass whatever the user entered to Vue.js.

Once a user has joined the chat, we loop through (using `v-for`) the messages (if there are any) and display them, then show the user an input field to type their chat message. When the user clicks the Send button or presses ENTER while within the message input field, the `sendMessage` method will be triggered. We also bind the message input field with the `newMessage` data so we can easily pass whatever the user entered to Vue.js.

When a user has not joined the chat:

![](https://blog.pusher.com/wp-content/uploads/2017/04/how-to-build-a-group-chat-app-in-javascript-and-pusher_join-1.png)


When the user has joined the chat:

![](https://blog.pusher.com/wp-content/uploads/2017/04/how-to-build-a-group-chat-app-in-javascript-and-pusher_chat-1.png)

## Create App.js

Now let’s create the file that will contain all our Vue.js specific code. Use the command below to do just that:


    cd public
    touch app.js

And paste the following code into it:


    // public/app.js
    
    const pusher = new Pusher('xxxxxxxxxxxxxxxxxxxx', {
        cluster: 'APP_CLUSTER',
        encrypted: true,
        authEndpoint: 'pusher/auth'
    });
    const app = new Vue({
        el: '#app',
        data: {
            joined: false,
            username: '',
            members: '',
            newMessage: '',
            messages: [],
            status: ''
        },
        methods: {
            joinChat() {
                axios.post('join-chat', {username: this.username})
                    .then(response => {
                        // User has joined the chat
                        this.joined = true;
                        const channel = pusher.subscribe('presence-groupChat');
                        channel.bind('pusher:subscription_succeeded', (members) => {
                            this.members = channel.members;
                        });
                        // User joins chat
                        channel.bind('pusher:member_added', (member) => {
                            this.status = `${member.id} joined the chat`;
                        });
                        // Listen for chat messages
                        this.listen();
                    });
            },
            sendMessage() {
                let message = {
                    username: this.username,
                    message: this.newMessage
                }
                // Clear input field
                this.newMessage = '';
                axios.post('/send-message', message);
            },
            listen() {
                const channel = pusher.subscribe('presence-groupChat');
                channel.bind('message_sent', (data) => {
                    this.messages.push({
                        username: data.username,
                        message: data.message
                    });
                });
            }
        }
    });

Remember to replace the xs with your Pusher app key and also specify your app cluster.

First, we create an instance of Pusher, passing to it our app key and other options. We pass in the auth endpoint `/pusher/auth` we set up in our Express server. Next, we create an instance of Vue.js. Then we specify the element (`#app`) we want to mount Vue.js on. We define some data that will be used by our app. The `joined` data which is `false` by default indicates whether a user has joined the chat or not. The `username` will be the username a user enters from the join chat form. The `members` will hold the number of users in the group chat. The `newMessage` will be the message a user enters from the chat form. The `messages` will hold an array of chat messages. The `status` will simply display notification of newly joined users.

When a user enters a username to join chat, the `joinChat` method is called which in turn make an HTTP POST request to the `/join-chat` endpoint on our server passing along the username. Once the request is successful, we set `joined` to `true` and subscribe the user to the `presence-groupChat` channel. Because we’re using a presence channel, Pusher provides us with additional functionality like getting the members in the channel. With that, we can listen for when the subscription is successful and get all the users subscribed to the channel and assign it to our `members` data. We also listen for when a new user joins the chat using the `pusher:member_added` event and notify other users that a new user has joined the chat. Lastly, we call a `listen` method (which we’ll create shortly) which listens for new chat messages and broadcast to users.

The `sendMessage` method is pretty simple, it makes an HTTP POST request to the `/send-message` endpoint on our server passing along the chat message. We also clear the input field of the previous message so the user can start typing new messages without having to manually clear the input field first.

Lastly, the `listen` method which we called from within the `joinChat` method will listen for `message_sent` event that was triggered from our server and add the new message to the messages array and finally broadcast it to users.

Note: By default, Pusher will try to use `/pusher/auth` as `authEndpoint`. If you setup yours different from that, you’ll have to specify while instantiating the Pusher JavaScript library.

Note: Pusher presence channels are to be prefixed with `presence-`.

Testing The App

So we’re done with building our group chat app. It’s time test out what we’ve built. To test the app, we need to start up our Express server by executing the command below:


    node server.js

The app should be running now and can be accessed through [http://localhost:3000](http://localhost:3000). Go on and try the app out. You should get something similar to the demo below:


![](https://blog.pusher.com/wp-content/uploads/2017/04/how-to-build-a-group-chat-app-in-javascript-and-pusher_demo.gif)

## Conclusion

So that’s it for this tutorial. In this tutorial, we saw how to build a group chat app with JavaScript and Pusher. Using Pusher’s presence channel, we saw how easy it is to get all the members subscribed to a channel. You can do more exciting things with [Pusher’s presence](https://pusher.com/docs/client_api_guide/client_presence_channels) channel like building chat rooms, collaborators on a document, people viewing the same web page, competitors in a game etc.
Did I mention you can signup for a forever free Pusher account which includes 100 connections, unlimited channels, 200k daily messages, SSL protection, and there are more features than just Pub/Sub Messaging? Yeah, you can. [Sign up here](https://pusher.com/signup).

This post was originally posted by the author on the [Pusher blog](https://blog.pusher.com/build-group-chat-app-javascript-pusher).