Create A Support Chat Admin Dashboard

·Published Aug 21, 2020

Taylor G.

In this tutorial, we'll build a chat app with a dashboard that allows an admin user to switch between one-on-one customer chat channels in the same window.

As a busy customer support representative, you don’t want to be stuck with a chat app that opens each chat in a new window, forcing you to cycle through multiple browser tabs and potentially resulting in losing track of an open ticket. The app we’ll build in this post displays all customer chats in a compact dashboard that bolds new messages as they come in (much like iMessage), and allows support reps to navigate between chats quickly and easily. What's more: this will take a matter of minutes, not hours.



Stream Chat provides the chat infrastructure for this app, as well as some basic out-of-the-box styling. Topics will be covered using Express JS and React, but the methodologies can be ported to most languages and frameworks.

This post will guide you through the Git Repository here.

Stream Configuration

A free Stream Trial account will be needed; grab yours here. Once you've signed up, create a new app on your Stream dashboard.

  1. Here's the navbar link for the dashboard
Stream Dashboard Button
  1. From the dashboard, create a new app with the 'Create App' button
Stream App Button
  1. Give your app a name and select 'Development' mode
Create New App
  1. This will generate an API key and Secret which we'll add to a .env file in a moment.
Stream Key Secret

Disable Stream Auth Checks and Permissions

Stream offers Auth Checks and Permissions Checks by default. These will be useful for any production environment, but we'll disable them for this case. Here's how:

  1. In your Stream dashboard, select your app. Click the 'CHAT' navbar dropdown and select 'Overview'
Stream Chat App
  1. Scroll down and activate the 'Disable Auth Checks' and 'Disable Permissions Checks' toggles.
Stream Auth

.env Configuration

The Git Repo contains a file in backend titled .env.example. Add your Stream API Key and Stream Secret here, then rename the file to .env.

// backend/.env.example:1

STREAM_API_KEY= your Stream API key here
STREAM_API_SECRET= your Stream API secret here

Spin 'Er Up

Your app should now be ready to run. The app is split into a frontend folder created using stream-chat-react and a backend folder created using npm express-generator.

To start the app on your machine run npm install and npm run start on both the frontend and backend folder. Once running, navigate to http://localhost:3000 to see the frontend. Now, we can dive into how this app works.


The frontend is split between an Admin component and Customer component. Each has their own login page and chat window. Here's the Router to distinguish the two.

To view the customer login, navigate to localhost:3000/. To view the admin login, go to localhost:3000/admin.

Customer Login (Frontend)

Let's investigate the login portion of the Customer component.

The snippet above returns the following:

Customer Login

This simple login form takes in firstName, lastName, and email. These are state variables that will be sent to the backend in the register function. Let's peek at the first half of the register function, the POST to the backend

I chose to write this request without any libraries, to clearly show what is being transmitted. I recommend the axios library if you're looking to simplify.

Next, let's see how the backend and how it handles the registration.

Customer Login (Backend)

First, the backend must establish its validity with Stream by configuring a serverSideClient, which is authenticated with your unique Stream API Key and Secret.

Next, the /customer-login endpoint accepts the customer inputs and registers a chat. Here's the process flow:

  • Normalize customer input from frontend
  • Generate a token for the customer
  • Open a chat channel
  • Add members to the channel
  • Return this data to the frontend

Note how the Stream library is the workhorse for this process, offering methods like .createToken, .updateUser, .channel, and .addMembers.

Some useful notes on the Stream methods used above:

  • .createToken takes in the username for the argument and generates a unique token for each participant in a chat.
  • .updateUser takes in an object, wherein the user id must be sent, and a name can be applied. The method requires a token for the user.
  • .channel accepts ( channel-type, channel-id, options-object). By specifying an array of members, we restrict channel access to those with the user id's specified.

Next, we'll check out how the frontend receives the backend response.

Chat Initialization (Frontend)

Let's explore the second half of the frontend registration function in Customer.js:

The backend's response is destructured. The following steps mirror the chat setup from the backend:

  • Set the user
  • Configure the channel for the frontend to join
  • Watch the channel, so that the user's browser receives all events occurring in the channel
  • setChannel(channel) is called so we can use the channel state later in rendering the chat

Render Customer Chat

Now that the channel is established, the customer chat is returned with the following block of code:

Here, again, Stream provides all the components we need to build the chat. The header is an optional inclusion, but it gives us a chance to play around with some of the built-in data Stream offers.

Customer Chat

⭐️Good to know: Stream offers loads of convenient channel data we can use anywhere in our apps. We can replace the Second National Bank header with something like: Welcome, {}, to render:

Custom Header

The <Chat /> component has several handsome out-of-the-box themes. For this instance, we'll use commerce light. Here's a list of the available themes.

The channel we just created is specified in the <Channel /> component. The <MessageList /> and <MessageInput /> an also be easily customized. That's all we need for the customer side; let's check out the Admin component.

Admin Login

The Admin Login page mimics the same steps as for the customer, but only accepts an Admin Id in the form input. Here's the form:

And here's the registration function, which only POST's an adminId, but follows the same channel setup.

This is nearly identical to the /customer-login endpoint. It creates a token, initializes the client, sets a user, and opens a generic channel. As new customers start chats, the channel list will be automatically populated.

Render Admin Dashboard

Here's how the Admin Dashboard looks:

Admin Dashboard

The main difference between the customer and admin registration is in the rendered Stream components.

Notice the <ChannelList /> component. This is another Stream built-in that handles the side pane with all channels hosted by our app. Stream's API will keep a history for each channel. The ChannelList component comes with loads of listeners to update the view when new chats are started, messages are sent, etc.

The sort option will show the chat with the most recent message at the top of the list. The Preview shows a snippet of the most recent message. The onSelect uses the setChannel state method to show the selected channel.


There you have it! A fully functional chat app with a powerful admin dashboard. Hopefully this tutorial provides some extra insight into working with Stream. Check out the Stream Chat Docs and Stream Chat React Docs for more inspiration and guidance for your projects.