Build your first Discord bot in less than an hour

Feature image

Build Your First Discord Bot With NodeJS in Less Than 60 Minutes

Discord is a chat application over 100 million users rely on to build online communities through text, voice, and video conversations. With the extensive API Discord offers to developers, we can build bots that perform repetitive, mundane, or even fun tasks on Discord. Moderating communities, sending messages to communities, and private messaging users are only a few jobs we can automate using Discord bots.

In today’s tutorial, we will build a simple (and fun) bot that sends random dad jokes to a community at user request. Using Node.js and discord.js module, we can create, develop, and deploy this Discord bot in less than 60 minutes with zero hassle. And the countdown starts now.


Before We Begin…

Here, we’ve listed all the things you need to set up before getting started with the tutorial.

  • Install Node.js on your machine.
  • Create an account on Discord. You can either download the desktop app or access it using the browser.
  • Create a new community (or a new “server” in Discord language) to test the app.

Once all these are set up, you’re ready to continue with the tutorial.

One last thing, you can find the code for the project on GitHub


Creating a New Discord Bot

In this first step, you should create and configure a new bot on Discord. Here’s how you can do it.

Log in to your Discord account and go to the application page on its developer portal.

Discord Dev Portal

Discord Dev Portal

Click on “New Application.” It generates a popup to provide the new bot’s name.

Discord new application form

Discord new application form

After adding the name, click on the create button, and you’ll be navigated to a new page with application information. Go to the “Bot” tab and click on the “Add Bot” button to add the bot to the application. Again, confirm the action in the popup.

Discord bot application

Discord bot application

This adds the new bot to Discord. Now, we can start configuring it.

Discord register bot

Discord register bot

As the first step, copy the bot token and store it somewhere private. Remember: this token is for your eyes only; never share it with anyone else.

Keep the default selections under the “Authorization Flow” section.

Discord authorization flow

Discord authorization flow

Next, you should turn on the“Server Members Intent” option under the “Privileged Gateway Intents.” Our bot needs permission for this intent to detect when a new member joins the server.

Discord set up bot intents

Discord set up bot intents


Adding the Bot to a Discord Server

We should generate an invite link that reflects the level of permissions the bot should have to add it to a Discord server. To do this, go to the “OAuth2” tab on the same page and select “bot” as the application’s scope. Then, choose the set of permissions the bot should have when interacting with the server. Our bot only needs permission to read and send messages in server channels.

Discord set bot permissions

Discord set bot permissions

After selecting all the necessary permissions, copy the URL generated under the scope section and open it in a new browser tab. Then, choose the server that the bot should join and authorize the action when prompted.

Connect bot to Discord server

Connect bot to Discord server

Now, if you go to the Discord server, you’d be able to see the new bot listed as a member on the right side panel.


Implementing the Bot’s Behavior

We can now start adding code to define how the bot should behave inside the server. As we mentioned at the beginning of the post, we will use Node.js and discord.js to accomplish this.

As the first step of implementation, set up a new Node.js project and initialize it with npm. Then, we should install discord.js, axios, and dotenv modules using npm.

npm install discord.js axios dotenv

Next, we create a .env file and add the token we previously copied as an environment variable.

//.env

TOKEN=<your token>

Log In and Start Listening to Events

Now we can import discord.js and set up the bot to listen to server events and respond accordingly. Create a new file named index.js and add the following code to it.

//index.js

require("dotenv").config();
const Discord = require("discord.js");
const client = new Discord.Client();

//Listen to the event that signals the bot is ready to start working
client.on("ready", () => {
  console.log(`logged in as ${client.user.tag}`);
});

//Listen to new messages on the server
client.on("message", async (message) => {
  if (message.content === "ping") {
    message.reply("pong");
  }
});

//Login to the server using bot token
client.login(process.env.TOKEN);

Few important things are happening in this code. First, we import the discord.js module and create a new Client object, which represents the Discord bot in this scenario. The client.login method then allows the bot to log in to Discord using the token we added to the .env file. The dotenv module takes care of adding it as an environment variable to the process.

Our bot listens to two Discord events: ready and message. The ready event is triggered when the bot is ready to be used. And the message event is triggered every time a user sends a message to a channel. Here, we set up the bot to reply to every message that sends “ping” with a “pong.”

When we run this Node script using the node index command, the bot, which has stayed offline so far, goes online and starts working.

See your bot online

See your bot online

You can send a ping message to a channel and test if it’s working correctly.

Test your basic bot

Test your basic bot


Reply to a User with a Random Dad Joke at User Request

Finally, we’ve come to the fun part of the project. In this step, we will set our bot to reply to any user who directly mentions it with a random dad joke. For this, we are using this awesome API: icanhazdadjoke.com . It has a great collection of funny (and awkward) dad jokes we can retrieve for free.

The basic logic of this implementation goes like this. When a user mentions our bot, it sends a request to the dad joke API using axios and retrieves a random dad joke. Then it replies to the user with the joke. Quite simple.

One thing to note here is that we need to set up the Accept headers of the GET request to application/json to retrieve the results from the API in JSON format.

require("dotenv").config();
const axios = require("axios");
const Discord = require("discord.js");
const client = new Discord.Client();

const dadJokeURL = "https://icanhazdadjoke.com";
const headers = { "Accept": "application/json" };

async function getRandomDadJoke() {
  const response = await axios.get(dadJokeURL, { headers: headers });
  return response.data;
}

//Listen to the event that signals bot is ready to start working
client.on("ready", () => {
  console.log(`logged in as ${client.user.tag}`);
});

//Listen to new messages on the server
client.on("message", async (message) => {
    //"Ignore the message if the bot authored it"
    if (message.author.bot) return;

    //If the doesn't specifically mention the bot, return
    if (text.includes("@here") || text.includes("@everyone")) return;

    //Return if the message doesn't mention the bot
    if (!message.mentions.has(client.user.id)) return;

    try {  
        //Reply with a random joke
        const result = await getRandomDadJoke();
        message.reply(result.joke);
    }
    catch (error) {
      message.reply("Sorry, an error occured");
    }
});

//Login to the server using bot token
client.login(process.env.TOKEN);

The getRandomDadJoke method sends the axios request and returns the retrieved data with the random joke. In the message handler, the bot listens to the message events and determines which messages it should reply to. It eliminates three types of messages.

  • Messages authored by the bot itself.
  • Messages that mention everyone on the server, not just the bot.
  • Messages that don’t mention the bot.

If a user directly mentions the bot, it replies with a random joke retrieved using the getRandomDadJoke method.

You can stop and start the Node script to get the modified bot running on the server.

Now the bot can reply information from the API

Now the bot can reply information from the API


Search for a Dad Joke with a User-Provided Search Term

This implementation is not much different from the last one. But here, users can submit a search term to get a dad joke on a specific topic.

To implement this, we add a new function called searchDadJokes which sends the request to the /search API endpoint with the search term as a query parameter. We also set the limit=1 to retrieve only one joke on a given subject.

async function searchDadJokes(term) {
    const params = { term: term, limit: 1 }
    const response = await axios.get(`${dadJokeURL}/search`, { params: params, headers: headers });
    return response.data.results[0];
}

Then, we have to modify the message event handler to consider the case the user submits a search term. Here’s how we do it.

//Listen to new messages on the server
client.on("message", async (message) => {

    //"Ignore the message if the bot authored it"
    if (message.author.bot) return;

    const text = message.content.toLowerCase();

    //If the doesn't specifically mention, bot return
    if (text.includes("@here") || text.includes("@everyone")) return;

    //Return if the message doesn't mention the bot
    if (!message.mentions.has(client.user.id)) return;

    let result;
    try {
        const term = text.replace(/<@!\d+>/, "").trim();

        //If there is a search term
        if (term !== "") {
            //Search a joke containing the term
            result = await searchDadJokes(term);
            if (!result) {
                message.reply(`Sorry, got no dad jokes about ${term}. But how about a random dad joke?`);
            }
        }

        //Reply with a random joke
        if (!result) {
            result = await getRandomDadJoke();
        }

        message.reply(result.joke);
    }
    catch (error) {
        message.reply("Sorry, an error occured")
    }
});

In this code, to check if a user has submitted a search term, we need to remove the bot’s ID from the text. It’s added to the text when the user mentions the bot. A mentioned ID appears in the text in the following format.

<@!1223344342859688930>

We detect IDs in text using the regex pattern <@!\d+> and replaces it with an empty string. After trimming the modified text, the bot can retrieve the search term user submitted. Then, the bot uses the searchDadJokes method to find a relevant joke.

But if the API database doesn’t have a joke on a particular topic, the bot replies to the user explaining the situation along with a random joke. If the user doesn’t submit a search term, it responds with a random joke by default.

The rest of the code stays similar to the last scenario. So, we can now run and test this new feature of our bot.

When there’s is a joke related to the search term:

Send jokes related to a query

Send jokes related to a query

When there’s no joke on the submitted term:

Use a fallback random joke when nothing was found

Use a fallback random joke when nothing was found


Welcome New Members

We can set up our bot to welcome every new user who joins the Discord server. When the bot detects a new “guildMemberAdd” event, which signals a new user has joined, it sends a message to the “general” channel welcoming the new user.

//Listen to new member joining event
client.on("guildMemberAdd", member => {
//Find the general channel in the user's channel list to send the welcome message
const channel = member.guild.channels.cache.find(ch => ch.name === "general");

    //If the channel is not in the server, exit
    if (!channel) return;

    channel.send(`Welcome, ${member}! I'm at your service if you want to hear dad jokes`);
});

Here’s how this feature works on the server when a new user joins.

Bot welcomes user

Bot welcomes user

With that, we have completed the development of our Discord bot. You can now add the bot to any server where you have “Manage Server” permission and have fun reading random dad jokes.


Deploying the Bot to Heroku

Running the bot locally on your machine is not ideal if you want to keep it working 24/7. So, to make it continuously available, we will deploy the bot to the Heroku cloud.

First, we should create a Procfile in our project folder specifying the commands that Heroku should execute at the application start. We add a new worker process with npm node index.js as starting command to the Procfile.

//Procfile

worker: node index.js

Next, you should initialize the project as a git repository and push it to GitHub. We can directly connect the GitHub repo to Heroku to deploy the bot. We recommend adding the node_modules folder and .env file to a .gitignore file before pushing the project to GitHub.

Then, once you log in to Heroku (create an account if you don’t have one), you’ll be redirected to the Heroku dashboard. Here you can create a new application by clicking on the “New” button.

Heroku new app menu

Heroku new app menu

Choose the “Create new app” option, give your application a name, and confirm the app creation.

Heroku new app form

Heroku new app form

The new application must now be listed on your Heroku dashboard. Select the application and go to its deploy tab, where you’ll find the option to connect your GitHub account to Heroku. After connecting the account, search for the app repository and click on “Connect.”

Connect Heroku app with git repository

Connect Heroku app with git repository

Heroku will now automatically deploy your app via the GitHub repository. You can enable automatic deployment to automatically deploy the repo every time you push new changes.

Set up automatic deployments on Heroku

Set up automatic deployments on Heroku

Next, go to the Settings tab and add the bot token to the “config vars” section. It adds the token to the env variables of the process. If you want, now you can remove the dotenv configuration in the initial application code.

Add env variables

Add env variables

We have to make one more change to complete the deployment. For this, go to the Resources tab of the application. Currently, the “web” option is turned on in the free dynos section while the “worker” is turned off. Instead, you should turn on “worker” and turn off “web” to prevent the app from crashing due to a 60-second timeout error .

Set up app as worker

Set up app as worker

With that, the app deployment is complete. Now, our Discord bot can run 24/7 on a server and provide an endless supply of dad jokes.


Summary

Discord API is a powerful tool that allows developers to build various applications for Discord, including bots. The Node-based discord.js package makes it even easier for us to take advantage of this tool.

Today, we created a simple bot that could do several automated tasks, including messaging channels, welcoming new members, and retrieving content from a remote API. It’s a fun experience anyone can try that would prepare you for building more serious, complex bots. I hope you’ll enjoy experimenting with the Discord API with what we learned today.