Skip to main content
Chat SDK v4 2x

Swift, Kotlin, and TypeScript SDKs

Build in-app chat, calls, and live streaming

On This Page

How to build a chat moderation dashboard with Node.js

Harry t
Harry Theodoulou
Solutions Engineer
  • Tutorial Type: Advanced
  • Reading Time: 30 mins
  • Building Time: 1 hr
Chat SDK v4 2x

Swift, Kotlin, and TypeScript SDKs

Build in-app chat, calls, and live streaming

Chat SDK v4 2x

Swift, Kotlin, and TypeScript SDKs

Build in-app chat, calls, and live streaming

On This Page


In-app chat is a tool that fosters community building and human connections. It creates personal, authentic relationships among app users and serves a variety of use cases. From disseminating important news and brand updates to facilitating connections among friends, in-app chat has the potential to create a rich, convenient, and effective communication environment in which communities can thrive.

At the same time, it’s essential to maintain a safe space where all actors can contribute positively. To ensure user safety, Sendbird Chat offers moderation tools that users and content moderators can leverage to protect the community from toxic behaviors and provide a safe space for all.

In this tutorial, we will build a moderation dashboard for your chat app in Sendbird Chat. This dashboard will provide insights into participants’ behaviors and will allow you to take quick action to keep conversations healthy.

By the end of this tutorial, you will learn how to:

With the final dashboard, you will be able to:

  • List all reported items divided by users, messages, and channels
  • Filter reported items by date and type (‘suspicious’, ‘harassing’, ‘inappropriate’, or ‘spam’)
  • View profanity-filtered messages in a channel
  • Delete profanities or reported messages
  • Mute/unmute reported users
  • Ban/unban reported users
  • Freeze/unfreeze channels

Before we start building the moderation dashboard, let’s review some prerequisites.


To be able to follow this tutorial, you will need the following:

  • A Sendbird application along with your application ID and a secondary API token. You can get your application ID and a secondary API token from the Sendbird Dashboard.
Application ID
Application ID
Secondary API token
Secondary API token
  • Ensure you have profanity filtering enabled for your Sendbird organization (This is optional – please contact Sales to set this up.)
Enable profanity filter
Enable profanity filter
  • A free Heroku account
  • Node.js >= v16 installed on your machine

Please note that you will benefit most from this tutorial if you are familiar with JavaScript.

With that out of the way, let’s get started. 💻

Web server setup

For the backend server, we are going to use the Sendbird moderation API for actions like banning and muting users. We will use the reporting API for listing reported users, messages and channels.

To bootstrap your back-end Node server with express.js, use the following command from the command-line:

Once the previous commands have finished, make sure that you update your npm scripts inside the package.json file at the root of your project (inside the sb-moderation-server/ directory):

Install server dependencies

Before moving any further, let’s make sure that we have all dependencies needed for later in this tutorial. To install all dependencies needed for the back-end server, run the following inside the root of the project:

Install server dependencies

To add the credentials of your Sendbird application to our backend, we need to create a .env file that will be loaded before the server starts.

1. At the root of your project, create a file named .env that contains the following:

2. Add the following lines to the top of the app.js file:

Note: If you are using git for this tutorial, don’t forget to add the .env inside your .gitignore file! If you don’t already have a .gitignore file, make sure to create one and add **/.env inside it. Add it to git for tracking.

After you have applied the above changes, you should be able to access your app credentials within the server runtime, like process.env.APP_ID, without them being stored in code. The App ID and API token will come in handy later.

API routes

To run the server as an API for the frontend (web dashboard in next section), we will need to specify all routes with the express server.

Each API route will have a controller which will handle each route’s request and response. Let’s start by defining our controllers first; these will be the heart of the server.

First, create a new directory named “controllers” at the root of your project.

We will then create four new files inside this new directory, one for each type of controller: Authentication, Sendbird Reports, Sendbird Profanities, and Sendbird Moderation Actions (banning, muting).

Authentication controller

This controller will handle authentication requests (login and logout) from users from the frontend dashboard to the server.

The structure of our authentication process around our Moderation Dashboard and the Sendbird servers is based on using session tokens. If you would like to learn more about session tokens and how they differ from access tokens, please see the docs.

To start, let’s create a new file under controllers/auth.js that will hold our authentication logic. Then add the following code to the auth.js file:

The user ID and access token come from the front end, where dashboard users use their credentials to authenticate. We then use those credentials to connect the user to Sendbird servers to check that the credentials supplied are correct.

Once we have successfully connected the user to Sendbird servers, we then add a check, isModerator(user) above, to make sure that the current user that is trying to authenticate is a content moderator.

One way to distinguish between chat moderators and normal chat users is by adding metadata for each moderator. You can do this either by using the Platform API or from the Sendbird Dashboard under Users > (Select a user) > User information > Custom fields as shown below:

Screenshot: Add metadata for each moderator
Add metadata for each moderator

If you followed the example in the screenshot above, make sure that you include the helper function isModerator anywhere inside your controllers/auth.js file:

Once the user passes all authentication checks, we go ahead and generate a new session token for that user, which we will send as a stateless token to the front end. This session token will then be saved in the local storage at the frontend and will be used in subsequent API requests to our server to verify a valid authentication.

For logging the user out, we simply need to delete any session tokens that the user currently has. So, inside your controllers/auth.js file, append the following:

If you would like to read more about deleting user’s session tokens, please see the docs.

Sendbird reports

This controller will handle requests for reported content (users, messages and channels) from the frontend dashboard to the server. If you would like to learn more about querying Sendbird for reports, please visit our docs.

To start, let’s create a new file under controllers/reports.js that will hold our querying logic. Then add the following code to the reports.js file:

Note: We are calling the Sendbird API recursively to retrieve all reports and send them to the frontend at once. If you experience scalability issues, you might want to handle pagination here as well as the Sendbird API does with the next field in the response json.

Sendbird profanities (optional)

This controller will handle requests for Sendbird profanity-filtered messages from the frontend dashboard to the server. If you would like to learn more about querying Sendbird for profanity filtered messages, please see the docs.

To start, let’s create a new file under controllers/profanities.js that will hold our querying logic. Then add the following code to the profanities.js file:

Links to Sendbird dashboard

In order to safely provide links to the Sendbird dashboard in the frontend of our custom moderation dashboard, we need to specify an API route that builds and returns the link to either a Group Channel, Open Channel, or a user.

To do this, let’s create a new file under controllers/links.js that will hold the link-generating logic. Then add the following code to the links.js file:

Sendbird moderation

This controller will handle requests for moderation actions (e.g. viewing a banned user, banning a user, deleting a message, freezing a channel, etc.) from the frontend dashboard to the server. If you would like to learn more about moderation actions offered by Sendbird, please check out the docs.

To start, let’s create a new file under controllers/moderation.js that will hold our moderation actions logic. Then add the following code to the moderation.js file for each section.

Authentication middleware

Now, it is critical to add an authentication check for all the above routes as we wouldn’t want anyone outside the organization to be able to take powerful actions such as banning a user from a channel.

We will do this by checking the dashboard user’s session token that we generated during login above, which was during our first steps of creating an authentication controller.

To do that, we need to create a new directory and file under middleware/index.js and add the following code:

The code above will check for a bearer token inside the authorization headers. That token (session token) will then be used to connect to the Sendbird websocket servers to validate a successful connection. If the connection has been successful, we disconnect the websocket and we then let the user complete the original request by calling next(). Otherwise, we stop the original request and return a response with 403 (Forbidden) status.

For the above to work successfully throughout our final application, we need to handle the session token at the frontend during login, and for each subsequent request that requires authentication. We will see how to do this in the following sections.

Connect controllers to API routes

Tying it all together, we will connect the authentication middleware and the controllers we just created to the API routes following the express.js way of defining them. To do this, we need a new file in which we define all routes and methods:

  1. Create a new directory at the root of your project named routes.
  2. Create a new file under the routes/index.js.
  3. After importing all controllers and defining the routes and methods you would like to use, your routes/index.js file should look something like this:

To apply the above routes to our app, add the following lines inside your app.js file at the root of your project.

Finally, to handle static files requests for the index.html file at the various URL paths in our frontend, add the following lines of code inside the app.js file:

Your app.js file should now look like this:

Your project structure should look like the one below:

Web dashboard setup

Before moving on to include our frontend code inside this project, make sure you delete the public directory if there is one in the root directory of your project. (It is generated if you used express-generator at the beginning of this tutorial).

Note: If you haven’t already initialized git inside your project, it is a good idea to do this before proceeding. You can do this by running git init inside the root project directory.

Then we will create a new directory called web, which will hold our frontend app. For the sake of making this tutorial simpler, you can add this branch into your project as a git submodule with the following command at the root of your project:

If you prefer to create your own frontend project from scratch, you can generate a new React.js project with create-react-app inside the root directory of your project. Just remember that to test this locally, you would probably need to specify the “proxy” field inside your package.json file:

Regardless of the way you chose to add your frontend code, your file structure should now look something like this:

We will then be looking at how the frontend code works when a user logs in and requests data, like reported content and Sendbird channels, from our back-end API.

If you followed the whole tutorial until now and cloned the dash-frontend branch from this repository, then you should have everything in place now and be ready to run the project. If you wish to understand in detail how the frontend code works, you can continue reading. Otherwise, you can skip to the Deployment section below.

Login page

Whether you have used your own frontend code or followed the tutorial above (the login page is at web/src/pages/login.js), you should be able to handle login requests from the frontend to the back-end API that we set up earlier:

The POST login request above goes to the /api/auth API route that is handled by this line‘/api/auth’, authController.login) that we specified earlier. This is where all the authentication checks happen and once the user has been successfully authenticated, we save the session token, returned from the API, to Local Storage as it will be used later in subsequent API calls:

Reports page

In the main page of our dashboard, we want to retrieve and show all reported content about users, messages and channels.

To do this, we use the session token that was retrieved earlier (during login) with the help of the getLoginDetails utility function detailed above. We then make a request to the back-end API after attaching the token to the authorization headers with the getAuthHeaders function like below:

Note: If you followed the whole tutorial so far, you should find the above code inside the web/src/pages/home.js file.

Here is the getAuthHeaders utility function used above to generate the authorization headers:

Moderation actions UI

Although handling UI changes and filtering at the frontend is not in context for this tutorial, you are already covered if you used this branch for setting up your frontend for this project.

For more information on moderation actions like banning or muting a user, you can see examples of how to handle these at the frontend within the banButton.js and muteButton.js components.

Profanity filtering (optional)

For more information on how to handle responses for profanities and displaying them to the UI, check out the /src/pages/profanity.js file.



To run the production version of your dashboard locally, follow these steps:

  1. From inside the web/ directory run npm run build.
  2. Once the above has finished, start your API server first by running npm start from the root of your project.
  3. Open a new tab in your browser and navigate to https://localhost:3000.
  4. If you are using an .env file for loading your App ID and API token like in this tutorial, make sure you update the dotenv configuration in the first lines of the app.js file and restart your server:


  1. Start your API server first by running npm run dev from the root of your project.
  2. Start your frontend server by running npm start from inside the web/ directory.
    1. You might be asked to run this on another port as the API server is already running on port 3000. In that case, accept by typing ‘y’.
  3. A new tab should open in your browser. If not, open your browser at https://localhost:3001 or to whichever port that your frontend development server has set up for you.

Deploy to Heroku


  1. A free Heroku account
  2. The Heroku CLI installed on your machine

If you haven’t already, initialize a git repository inside the root of your project:

Then authenticate with the Heroku CLI, create a new app, and push your local git repository to Heroku:

Finally, we need to specify the Sendbird application credentials like the App ID and API token inside our new Heroku app.

To do this, head over to your Heroku app dashboard and select your new app. Then, from the top app menu, select “Settings” and then “Reveal Config Vars”:

Screenshot: Reveal config vars in Heroku
Reveal config vars in Heroku

Now add your Sendbird App ID as APP_ID and the API token for that app as API_TOKEN:

Screenshot: Add Sendbird App ID and API token
Add Sendbird App ID and API token

If necessary, rebuild your app after setting the Heroku config vars, although they should be applied to your app already.

Logging into the live dashboard

If you have followed the above steps for deploying your app, you should now have a public URL for your dashboard where it can be accessed at all times.

Screenshot: Dashboard login screen
Dashboard login screen

To log into your dashboard, you need to make sure you have a Sendbird user whose metadata include the {moderator: true} field and you have that user’s ID and access token at hand.

Screenshot: Edit a moderator
Edit a moderator

Drive trust and safety with advanced chat moderation software

And that’s it! In this tutorial, we discussed the server and dashboard implementation of setting up a custom Sendbird moderation dashboard and deploying it live so we can use it anytime. With this, you can moderate conversations to ensure your users' safe, secure, and positive chat experience. Now, if you just want something off-the-shelf moderation software, check our Sendbird moderation dashboard and the auto-moderation capabilities of Sendbird's advanced chat moderation.

Please visit our community site or contact us if you have any questions. We’re always eager to help!

Happy content moderation dashboard building! 🖥