What is a Twitch Bot?

Twitch Bots can be used by a streamer on the Twitch platform for a variety of reasons. One of the more common use cases for a bot is to moderate the chat in real-time; a bot is not always as accurate as a moderator, but, they are excellent at identifying specific keywords and taking swift action.  In addition, bots can be used to react with a streamer’s chat in order to engage the viewers – often through timed reminders and minigames.

Other types of bots:

  • Moderation
  • Games
  • Playing Music
  • Posting timed messages to chat

What will our Bot Do?

Despite what you may have heard, implementing your first chatbot for Twitch can be very simple! The goal of this guide is to show you how to make a very simple Twitch bot in only a few minutes.

Starting off as just a little baby-bot our joyous bot will gleefully greet users that we instruct it to or when a user says “Hi” in our stream chat. To test it, we’ll use the StreamLabs chat simulator.

!greet CodeTober in the Twitch chat will cause a message to appear for CodeTober.
CodeTober: Hi – in the chat will cause a message to appear in the chat aimed at CodeTober

The Twitch platform treats a bot just like a normal user. That means the very first step is to simply create a new Twitch account, which can be done using a new or an existing email address. I chose to use the same email address as my normal account when setting up the bot.

When our bot is completed, it will do three main things:

  1. Authenticate & Join a Stream
  2. Consume the Stream Chat
  3. Take some action based on the chat messages

Development Prerequisites

In this guide, we’ll be using NodeJS v14.16.1 and NPM. If you need help getting started with those, check out the  NodeJS installation guide, NPM can be automatically installed while configuring NodeJS.

Make sure that your PATH is updated when installing NodeJS so that you can use the node command in your terminal.

Note: The bot we’re going to make should not be used for commercial purposes as it’s not optimized for production architecture and security.

Building your NodeJS Twitch Bot

Step #1: Create a blank NodeJS App

Navigate to a new directory, and open your command line / terminal to the same directory. I like to Shift+Right-Click and select “Open Powershell window here”. Then initialize a new NPM project with the command npm init,it will walk you through the necessary steps to set up the Node application.

Now you should notice that a file named “package.json” is located in the directory. This file is how NPM keeps track of any external packages we end up adding to the project.

Open the package.json file and add the highlighted line in the code below to your “scripts” object. This just makes it so that you can type “npm start” in the CMD/Termnial to run your app.

Once completed, your package.json file should look something like this:

{
  "name": "twitch-bot",
  "version": "1.0.0",
  "description": "My First Twitch Bot",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "CodeTober",
  "license": "MIT"
}

In the same folder as your package.json file, create a file called index.js. This file is where our Node app will be created. Next, just copy the following code into your index file to get your node app bootstrapped.

function sayHello(){
  console.log("Hello World");
}

sayHello();

RUN IT! By going to your CMD/Termnial inside your project directory (same spot as your index.js and package.json) just enter npm start and you will see the output message Hello World printed to the terminal where you ran the project. Similar to the image below.

Quick review

This code is simply creating a function that can be called, which, when called will cause a String to be printed to the console. Pretty easy, yea? As you’ll soon see, the bot is not much more complicated.

Step #2: Adding the TMI.js Twitch Library

The TMI.js library is a wrapper around the logic that allows our bot to authenticate with the Twitch servers, enter a stream, and access the chat contents. We’ll walk through the setup of the TMI code and then register our new Twitch Bot account with TMI to receive an auth token.

Install TMI.js

npm install tmi.js

Configuring our Bot

There are a ton of ways to configure the bot, but, we’re going to stick to the bare minimum so we can get up and running lickity-split. 

The two required pieces of the TMI configuration are identity and channels. Between those two pieces of configuration, we can get our bot authenticated and join the chat for a Twitch channel.

// add reference to the TMI library
const TMI = require('tmi.js');

// Bot Name and Password
const BOT_NAME = "HelloBot";
const TMI_OAUTH = "paste your TMI token here";
const TMI_OPTIONS = {
  identity: {
    username: BOT_NAME,
    password: TMI_OAUTH
  },
  channels: [
    "codetober"
  ]
}

// Connect bot to channels and get client instance
const client = new TMI.client(TMI_OPTIONS);
client.on('connected', onConnectedHandler);
client.connect();

// Called every time the bot connects to Twitch chat
function onConnectedHandler (addr, port) {
  console.log(`Successfully Connected to ${addr}:${port}`);
}

If you run this code you’ll see a message Successfully Connected to irc-ws.chat.twitch.tv:443 if the configuration is correct. Make sure to use the username and password from your newly created twitch account (for the bot) when getting your OAuth token from TMI.

After setting up our TMI_OPTIONS we just created a new instance of the TMI client and then we set up a callback function that is triggered whenever our client becomes connected. This console.log will run each time our bot is connected to Twitch successfully. If you’re not seeing this message, make sure your username and oauth token are correct.

Reading the Stream Chat

Now that our bot can connect, it’s time to read the chat. Just like we did for the connected event, this time we’ll register a function to handle the message event. When a message comes through, we have access to the following parameters:

  • target – the channel name that the message came from. This is important because your bot can monitor multiple channels at once
  • tags – a set of key value pairs related to the user that sent the message
  • message – the String sent in chat
  • self – boolean that is true when the message is from our bot and false when the message is from another user

Using these parameters, we can handle the incoming messages and decide how/when to reply back into the chat (next step). For now, let’s create the function to listen to the chat and handle messages.

client.on('message', onMessageHandler);

function onMessageHandler(target, tags, message, self){
  // Just leave this function if the message is from self
  if(self){ return;}

  let trimmedMessage = message.trim();
  let splitMessage = trimmedMessage.split(" ");
  
  // log every message, remove this eventually, for debugging only
  console.log(target, tags.username, trimmedMessage);

  if(splitMessage[0] === "Hi"){
    // log when a user says "Hi" in chat
    console.log(tags.username + " said: " + splitMessage[0]);
  }

 // TODO: Add command to greet specific users by name
}

The point of this function is to do a little bit of cleaning up on messages in a Twitch chat and then log all of the chats to the terminal/CMD. This is one place where we will eventually be responding to the user. But, we don’t only want to respond to viewers in chat that are kind enough to drop a “Hi” in the chat. A good bot will always allow you to tell it what to do – if we want it to greet someone who is being rude by not saying “Hi”, we want to send a command to our bot like !greet <username> and have our bot send a message to them in the chat.

Responding to a message and contributing to the chat

function onMessageHandler(target, tags, message, self){
    // Just leave this function if the message is from self
    if(self){ return;}
  
    let trimmedMessage = message.trim();
    let splitMessage = trimmedMessage.split(" ");
    let targetUser = "";
    if(splitMessage.length > 1){
        targetUser = splitMessage[1];
    }
    let greetingMessage = `Hey there @${targetUser}! I'm super excited you are here today! Tell the class how you're doin'`;
    let hiResponse = `What's up @${tags.username}?! Thanks for joining, it's always a good time :D`;
    
    // log every message, remove this eventually, for debugging only
    console.log(target, tags.username, trimmedMessage);
  
    if(splitMessage[0] === "Hi"){
      client.say(target, hiResponse);
    } else if(splitMessage[0] === "!greet"){
      client.say(target, greetMessage);
    }
  }

On the highlighted lines, you notice that we added two different types of greetings for our bot and we also replaced our logging with client.say(target, string). The target is the channel that we want to put the message into and the string is the message we’d like to send. 

Notice that in the greetingMessage we are using splitMessage[1] which would be a specific username mentioned by someone else in the chat. Whereas the hiResponse uses tags.username because our bot is responding directly to the viewer that sent the message.

Note: It’s a good idea to add a second condition before saying the greetMessage that will check if the person that issued the command is one of the moderators or the channel owner. That will stop the viewers from spamming the bot and causing an issue in chat.

Full Code for the Bot

// add reference to the TMI library
const TMI = require('tmi.js');

// Bot Name and Password
const BOT_NAME = "HelloBot";
const TMI_OAUTH = "<tmi oauth token here>";
const TMI_OPTIONS = {
  identity: {
    username: BOT_NAME,
    password: TMI_OAUTH
  },
  channels: [
    "<some channel name>"
  ]
}

// Connect bot to channels and get client instance
const client = new TMI.client(TMI_OPTIONS);
client.on('connected', onConnectedHandler);
client.on('message', onMessageHandler);
client.connect();

// Called every time the bot connects to Twitch chat
function onConnectedHandler (addr, port) {
  console.log(`* Connected to ${addr}:${port}`);
}

// Called every time a message is typed in a chat that the bot is connected to
function onMessageHandler(target, tags, message, self){
    // Just leave this function if the message is from self
    if(self){ return;}
  
    let trimmedMessage = message.trim();
    let splitMessage = trimmedMessage.split(" ");
    let targetUser = "";
    if(splitMessage.length > 1){
        targetUser = splitMessage[1];
    }
    let greetingMessage = `Hey there @${targetUser}! I'm super excited you are here today! Tell the class how you're doin'`;
    let hiResponse = `What's up @${tags.username}?! Thanks for joining, it's always a good time :D`;
    
    // log every message, remove this eventually, for debugging only
    console.log(target, tags.username, trimmedMessage);
  
    if(splitMessage[0] === "Hi"){
      client.say(target, hiResponse);
    } else if(splitMessage[0] === "!greet"){
      client.say(target, greetMessage);
    }
  }