Using Node to create a Twitch Chatbot

Last week I wrote a post here: https://www.richwerks.com/index.php/2019/twitch-bot-tutorial/. This post showed how to create a twitch chat bot using python. This week I wanted to take a stab at creating one using Node to create a Twitch chatbot. I’m using the same Ubuntu f1-micro setup on Google Cloud Platform. For this tutorial, I am using tmi.js (twitch messaging interface) to create the connection to the Twitch chatrooms. Again we will have our configuration for the connection located in a separate file from our main application code.

I also created a separate file to store the chat commands. I did this for a couple reasons. One was I wanted a configuration that could be iterated through, in the event that I wanted to add more commands without having to change my application logic. Then I started to think, what can I do with this file? Do I just store keywords and chat responses? That is useful enough if people wanted to get information about your social media or merchandising, but what about our previous tutorial that included a “!roll” command?

Well as it turns out using this external file is perfect. I just needed a standardized format. I chose to use an array of objects. These objects are commands the bot should react to. IN the object, I store a command name, “name”, a command type, and depending on the command type, I store either a chat message, “message” or a function. Currently the command type is limited to “message” or “function”. Because of this, I can have a rudimentary command/reply system, but also a system that executes some function.

Contents of the command.js file for our Node Twitch chatbot

Here is the contents of the commands.js file so that you can see what the object array looks like.

const commands = [
  {
    name : "merch",
    type : "message",
    message : "I don't currently have any merch at this time."
  },
  {
    name : "roll",
    type : "function",
    func : function (channel, userstate, message, client){
      let randNum = Math.floor(Math.random() * (100 - 0 + 1)) + 0;
      client.say(channel, `${userstate.username} rolled a ${randNum}!`);
    }
  },
  {
    name : "social",
    type : "message",
    message : "You can see me at http://www.twitch.tv/XerouzTV or you can go to http://www.youtube.com/cRichOffical"
  }
  ];
module.exports = commands

If you wanted to, you can just add additional objects to the array in the commands.js file. In addition to is, you could also add them directly from your main application code by creating a new object and appending it to the commands array like so. Iv

const newCommmand = {
    name: "newCommand".
    type: "message",
    message: "This is a new command message. It will send to the channel when !newCommand is used."
};

commands.push(newCommand)

Here is another example of adding a command that uses a function. The function commands take several arguments: channel, userState, message and client. These are objects that are part of the tmi client, so they should be available with every message. Just make sure your commands follow the same format.

const newFuncCommand = {
    name: "runFunction",
    type: "function",
    func: function(channel, userState, message, client){
        //Do some database stuff or maybe read from a text file here.
        //Really you can do whatever you want here. At the end, you can send
        //data back through client.say() to send a message to the chat channel
        client.say(channel, "Here I will send back some message after processing my function.");
    }
};

commands.push(newFuncCommand);

The configuration for the Twitch connection in config.js for our Node Twitch Chatbot

Great, we’ve defined some commands in an external commands.js file. Now we need to store connection information for the Twitch chat connection. This is a configuration object for tmi.js. It will store your OAuth token, so it is wise to keep it separate from your main application code, just in case you are storing your code in some sort of public repository. The options takes an options object that specifies debugging. debug: true will output your bot’s chat responses to the console. Connection.reconnect will tell the bot to attempt a reconnect if it gets disconnected.

The identity section takes the username of your bot and it’s OAuth token to authenticate it. If you do not have a username or OAuth token for your chatbot, you can follow the links in my article about creating a python chatbot. https://www.richwerks.com/index.php/2019/twitch-bot-tutorial/. The channels section is an array of channel names that your bot will join. Here is an example of a config.js file here.

const options = {
  options: {
    debug: true
  },
  connection: {
    reconnect: true
  },
  identity: {
    username: "OmegaDroid",
    password: "oauth:YOUR_OATH_TOKEN_HERE"
  },
  channels: ["XerouzTV"]
};

module.exports = options;

Chatbot.js. The meat and potatoes of our bot

Our next step in using Node to create a Twitch chatbot is to create the meat and potatoes of the whole thing, our chatbot.js file. This application will utilize tmi.js. tmi.js can be installed either by installing from the npm repository

npm install --save tmi.js

or it can be installed by downloading the files from the git repository at https://github.com/tmijs.

Now, first thing we need to do in our chatbot.js file is to import tmi.js, our config file and our commands file. We will also define our command prefix that we want to use to determine if a message is a command.

const tmi = require("tmi.js");
const options = require("./config.js");
const commands = require("./commands.js");
const CMD_PREFIX = "!";

Next, we need to create our tmi client object and connect it to the twitch IRC service.

const client = new tmi.client(options);
client.connect();

After we’ve established our connection, we need to create the functionality that tells the client what to do when we get a message. This is done by listening for a chat event on the client. We will output the chat message to the console, and call a command called handleCommands.

client.on("chat", function(channel, userstate, message, self){
  if(self) return;
  console.log(userstate, message);
  handleCommmand(channel, userstate, message);
});

Once we’ve got the client listening for a chat even, we need to define our handleCommand function. This function takes in the arguments from our chat event. The handleCommand function simply looks for the CMD_PREFIX and determines if it is the first character of our message. If it is, we have a chat command. We will then call the processCommand function, which will take the same arguments as the handleCommand function.

function handleCommmand(channel, userstate, message){
  if(message.charAt(0) == CMD_PREFIX){
    processCommand(channel, userstate, message)
  }
}

Now the processCommand function will iterate through our commands object and will perform an action based on the commands type (message or function). If it is a function, we can the “func()” function of the command object to process the function that is defined.

function processCommand(channel, userstate, message){
  console.log("processing commands...");
  message = message.replace(CMD_PREFIX, '').toLowerCase();
  command = message.split(' ');
  for(let i = 0; i < commands.length; i++){
    if(command[0] == commands[i].name){
      if(commands[i].type == "function"){
        commands[i].func(channel, userstate, message, client);
      }
      else if(commands[i].type == "message"){
        client.say(channel, commands[i].message);
      }
    }
  }
}

As you can see, we first strip the from the message. We then split the message into a command array. Then the commands array (confusing, maybe I should change the names) is iterated through and the name of our defined command is checked against the first item in the command array (our command minus the prefix). Once this is matched, the script then checks for the command type. If it is a “message” command type, we send the defined message to the chat channel, otherwise, if it is a “function” command type, we call command[i].func() with the arguments channel, userstate, message and client.

Our Twitch bot using Node is now ready to run

Great, we have all the pieces in place. Now we can run our bot by running:

node chatbot.js

Our chatbot will now connect to the channel defined and start listening to commands. As our chatbot is currently configured, it will listen for the “!merch” command and state we have no merchandise, “!roll” command and output a random number between 0 and 100 or the “!social” command and send links to our social media accounts. It is important to note that by default Twitch will mask URLs in chat channels. So if you want your bot to be able to properly display URLs, make your bot a moderator in your channel.

Making your bot a moderator will be a good idea as well, as you can use tmi.js’s client.ban(channel, user, reason) to ban users for, say, using words that you want banned from your channel or for spamming.

Here we go. Shown below will be the whole config.js, commands.js and chatbot.js files

config.js

const options = {
  options: {
    debug: true
  },
  connection: {
    reconnect: true
  },
  identity: {
    username: "OmegaDroid",
    password: "oauth:"
  },
  channels: ["XerouzTV"]
};

module.exports = options;

commands.js

const commands = [
  {
    name : "merch",
    type : "message",
    message : "I don't currently have any merch at this time."
  },
  {
    name : "roll",
    type : "function",
    func : function (channel, userstate, message, client){
      let randNum = Math.floor(Math.random() * (100 - 0 + 1)) + 0;
      client.say(channel, `${userstate.username} rolled a ${randNum}!`);
    }
  },
  {
    name : "social",
    type : "message",
    message : "You can see me at http://www.twitch.tv/XerouzTV or you can go to http://www.youtube.com/cRichOffical"
  }
  ];
module.exports = commands

chatbot.js

const tmi = require("tmi.js");
const options = require("./config.js");
const commands = require("./commands.js");
const CMD_PREFIX = "!";

const client = new tmi.client(options);
client.connect();



client.on("chat", function(channel, userstate, message, self){
  if(self) return;
  console.log(userstate, message);
  handleCommmand(channel, userstate, message);
});

function handleCommmand(channel, userstate, message){
  if(message.charAt(0) == CMD_PREFIX){
    processCommand(channel, userstate, message)
  }
}

function processCommand(channel, userstate, message){
  console.log("processing commands...");
  message = message.replace(CMD_PREFIX, '').toLowerCase();
  command = message.split(' ');
  for(let i = 0; i < commands.length; i++){
    if(command[0] == commands[i].name){
      if(commands[i].type == "function"){
        commands[i].func(channel, userstate, message, client);
      }
      else if(commands[i].type == "message"){
        client.say(channel, commands[i].message);
      }
    }
  }
}

173 thoughts on “Using Node to create a Twitch Chatbot”

  1. I’m not great in Python; what does the (100 - 0 + 1) part do in the expression Math.floor(Math.random() * (100 - 0 + 1))? I assume it has to do with casting the float from Math.random to an integer, but I’m confused why the +0 is needed?

    1. Jonathan, the 0 isn’t needed at all, it’s just there out of habit. You do Math.floor(Math.random(max -min)) to be exclusive of the max number, or Math.floor(Math.random(max – min + 1)) to be inclusive of tha max number.

  2. I’ve been surfing on-line more than three hours nowadays,
    yet I never discovered any fascinating article like yours.
    It is beautiful price enough for me. In my opinion,
    if all webmasters and bloggers made excellent content material as you
    probably did, the net shall be much more useful than ever before.

  3. Excellent goods from you, man. I’ve understand your stuff previous to and you’re just extremely fantastic.
    I actually like what you’ve acquired here, certainly
    like what you’re stating and the way in which you say
    it. You make it enjoyable and you still care for to keep it wise.
    I can not wait to read far more from you. This is actually a great site.

  4. Hey very cool site!! Guy .. Excellent .. Superb ..
    I will bookmark your blog and take the feeds additionally?
    I’m glad to find a lot of useful info right here in the submit, we
    want develop more strategies in this regard, thanks for
    sharing. . . . . .

  5. Hi there would you mind sharing which blog platform
    you’re using? I’m looking to start my own blog soon but I’m having a difficult time choosing between BlogEngine/Wordpress/B2evolution and Drupal.
    The reason I ask is because your layout seems different then most blogs and I’m looking for something completely unique.
    P.S Sorry for being off-topic but I had to ask!

  6. Reduce costs with our low cost composing program | Get ve ry high excellent quality papers of any problems stage but for your reasonable expense!

  7. Great weblog here! Additionally your web site loads up fast! What host are you the use of? Can I am getting your affiliate hyperlink to your host? I wish my web site loaded up as quickly as yours lol| а

  8. First off I want to say superb blog! I had a quick question in which I’d like to ask if you do not mind. I was interested to find out how you center yourself and clear your mind prior to writing. I have had a hard time clearing my thoughts in getting my thoughts out. I truly do enjoy writing however it just seems like the first 10 to 15 minutes tend to be lost simply just trying to figure out how to begin. Any ideas or tips? Thanks!| а

  9. Howdy would you mind sharing which blog platform you’re working with? I’m looking to start my own blog soon but I’m having a hard time selecting between BlogEngine/Wordpress/B2evolution and Drupal. The reason I ask is because your design seems different then most blogs and I’m looking for something unique. P.S My apologies for getting off-topic but I had to ask!| а

  10. I loved as much as you’ll receive carried out right here.
    The sketch is tasteful, your authored subject matter stylish.
    nonetheless, you command get got an shakiness over that you
    wish be delivering the following. unwell unquestionably come further formerly again as exactly the same nearly very often inside case you shield
    this hike.

  11. Just wish to say your article is as surprising. The clarity in your post is just great and i can assume you’re an expert on this subject. Fine with your permission let me to grab your feed to keep up to date with forthcoming post. Thanks a million and please keep up the rewarding work.| а

  12. It’s perfect time to make some plans for the future and it is time to be happy. I have read this post and if I could I want to suggest you some interesting things or advice. Perhaps you could write next articles referring to this article. I want to read even more things about it!| а

  13. An impressive share! I have just forwarded this onto a colleague who has been conducting a little homework on this. And he in fact bought me dinner due to the fact that I stumbled upon it for him… lol. So let me reword this…. Thanks for the meal!! But yeah, thanks for spending the time to discuss this topic here on your internet site.| а

  14. Greetings I am so delighted I found your webpage, I really found you by mistake, while I was researching on Bing for something else, Nonetheless I am here now and would just like to say many thanks for a tremendous post and a all round enjoyable blog (I also love the theme/design), I don’t have time to browse it all at the moment but I have bookmarked it and also added in your RSS feeds, so when I have time I will be back to read more, Please do keep up the great work.| а

  15. Magnificent goods from you, man. I’ve understand your stuff previous to and you are just too excellent. I actually like what you have acquired here, really like what you are saying and the way in which you say it. You make it enjoyable and you still take care of to keep it wise. I can’t wait to read much more from you. This is really a wonderful site.| а

  16. Long time supporter, and thought I’d drop a comment.

    Your wordpress site is very sleek – hope you don’t mind me asking what theme you’re using?
    (and don’t mind if I steal it? :P)

    I just launched my site –also built in wordpress
    like yours– but the theme slows (!) the site down quite a bit.

    In case you have a minute, you can find it by searching
    for “royal cbd” on Google (would appreciate any feedback) – it’s still in the works.

    Keep up the good work– and hope you all take care of yourself during the
    coronavirus scare!

  17. Здесь вы можете заказать копию любого сайта под ключ, недорого и качественно, при этом не тратя свое время на различные программы и фриланс-сервисы.

    Клонированию подлежат сайты как на конструкторах, так и на движках:
    – Tilda (Тильда)
    – Wix (Викс)
    – Joomla (Джумла)
    – WordPress (Вордпресс)
    – Bitrix (Битрикс)
    и т.д.
    телефон 8-996-725-20-75 звоните пишите viber watsapp
    Копируются не только одностраничные сайты на подобии Landing Page, но и многостраничные. Создается полная копия сайта и настраиваются формы для отправки заявок и сообщений. Кроме того, подключается админка (админ панель), позволяющая редактировать код сайта, изменять текст, загружать изображения и документы.

    Здесь вы получите весь комплекс услуг по копированию, разработке и продвижению сайта в Яндексе и Google.

    Хотите узнать сколько стоит сделать копию сайта?
    напишите нам
    8-996-725-20-75 звоните пишите viber watsapp

    Here you can order a copy of any site turnkey, inexpensive and high quality, while not wasting your time on various programs and freelance services.

    Cloning sites are subject to both designers and engines:
    – Tilda (Tilda)
    – Wix (Wicks)
    – Joomla (Joomla)
    – WordPress (WordPress)
    – Bitrix (Bitrix)
    etc.
    phone 8-996-725-20-75 call write viber watsapp
    Not only single-page sites like Landing Page are copied, but also multi-page sites. A full copy of the site is created and forms for sending requests and messages are set up. In addition, the admin panel is connected, which allows you to edit the site code, change the text, upload images and documents.

    Here you will get a full range of services for copying, development and promotion of the site in Yandex and Google.

    Do you want to know how much it costs to make a copy of the site?
    write to us
    8-996-725-20-75 call write viber watsapp

  18. Hi there, I do believe your website could be having internet browser compatibility issues. When I take a look at your blog in Safari, it looks fine however, if opening in Internet Explorer, it has some overlapping issues. I merely wanted to provide you with a quick heads up! Other than that, fantastic website!| а

  19. This design is wicked! You definitely know how to keep a reader amused. Between your wit and your videos, I was almost moved to start my own blog (well, almost…HaHa!) Fantastic job. I really loved what you had to say, and more than that, how you presented it. Too cool!| а

  20. Definitely believe that that you stated. Your favorite reason seemed to be at the internet the simplest factor to be aware of. I say to you, I definitely get irked whilst people think about concerns that they plainly don’t know about. You controlled to hit the nail upon the top as smartly as outlined out the entire thing without having side effect , people can take a signal. Will likely be back to get more. Thanks| а

  21. Very nice post. I just stumbled upon your blog and wanted to say that I have truly enjoyed browsing your blog posts. In any case I will be subscribing to your feed and I hope you write again very soon!|

  22. Hey very nice blog!! Guy .. Excellent .. Amazing .. I’ll
    bookmark your blog and take the feeds additionally?
    I’m glad to seek out a lot of useful info here in the put
    up, we’d like work out extra techniques on this regard, thank you for
    sharing. . . . . .

  23. I think this is one of the most important info for me. And i am glad reading your article. But wanna remark on some general things, The web site style is perfect, the articles is really great : D. Good job, cheers|

  24. Great goods from you, man. I’ve take note your stuff prior to and you are simply extremely great. I actually like what you’ve bought here, certainly like what you are saying and the way through which you assert it. You are making it enjoyable and you continue to care for to stay it wise. I can not wait to learn much more from you. This is really a terrific site.| а

  25. Excellent post. I used to be checking constantly this weblog and I’m inspired! Very helpful info specifically the remaining phase 🙂 I deal with such info a lot. I used to be seeking this certain information for a long time. Thank you and best of luck. |

  26. Hmm it seems like your website ate my first comment (it was extremely long) so I guess I’ll just sum it up what I wrote and say, I’m thoroughly enjoying your blog. I too am an aspiring blog writer but I’m still new to everything. Do you have any helpful hints for beginner blog writers? I’d really appreciate it.|

Leave a Reply

Your email address will not be published. Required fields are marked *