Discord is a instant messaging and digital distribution platform designed for creating communities. With over 100 million users, the service allows you to communicate with voice calls, video calls, text messaging, media and files in private chats, or ,as part of communities called “servers”. With this extensive API, Discord allows developers to build bots that perform repetitive, mundane, or even fun tasks. With a Discord bot, users can moderating and send messages to communities, as well as send private messages to users.

In this tutorial, we will build a simple bot that sends random dad jokes to a community at a users request. Using Node.js and discord.js module, we can create, develop, and deploy this Discord bot in less than 60 minutes.

Before we begin…

We’ve listed all the things you need to set up before getting started with the tutorial:

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

Once you are set up, you can begin 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
Credit: Author Provided
Discord Dev Portal.
Discord Dev Portal

Click on “New Application.” , this will generate a popup requesting the new bot’s name.

Discord new application form
Credit: Author Provided
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. From here, go to the “Bot” tab and click “Add Bot” to add the bot to the application. Again, confirm the action in the pop-up.

Discord bot application
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.
Discord register bot

Now, we must 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
Credit: Author Provided
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
Credit: Author Provided
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
Credit: Author Provided
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.
Connect bot to Discord server

Now, if you go to the Discord server, you’ll be able to see the new bot listed 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, we will use Node.js and discord.js to do 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();
constDiscord=require("discord.js");
constclient=newDiscord.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);

There are a few important things 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.
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.
Test your basic bot

Reply to a user with a random Dad joke

Finally, we’ve come to the fun part of the project. Here, 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 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();
constaxios=require("axios");
constDiscord=require("discord.js");
constclient=newDiscord.Client(); constdadJokeURL="https://icanhazdadjoke.com";
constheaders= { "Accept":"application/json" }; asyncfunctiongetRandomDadJoke() { constresponse=awaitaxios.get(dadJokeURL, { headers:headers }); returnresponse.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
constresult=awaitgetRandomDadJoke(); 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.
Now the bot can reply information from the API

Search for a Dad joke with a user-provided search term

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

To do this, we must 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.

asyncfunctionsearchDadJokes(term) { constparams= { term:term, limit:1 } constresponse=awaitaxios.get(`${dadJokeURL}/search`, { params:params, headers:headers }); returnresponse.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; consttext=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; letresult; try { constterm=text.replace(/<@!\d+>/, "").trim(); //If there is a search term
if (term!=="") { //Search a joke containing the term
result=awaitsearchDadJokes(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=awaitgetRandomDadJoke(); } message.reply(result.joke); } catch (error) { message.reply("Sorry, an error occured") }
});

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 can detect IDs in text using the regex pattern <@!\d+> and replace it with an empty string. After trimming the modified text, the bot can retrieve the search term that was submitted. Then, the bot uses the searchDadJokes method to find a relevant joke.

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.
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.
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
constchannel=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.
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, we need to initialize the project as a git repository and push it to GitHub. We can connect the GitHub repo to Heroku which will deploy the bot. We recommend adding the node_modules folder and .env file to a .gitignore file before pushing the project to GitHub.

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.
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.
Heroku new app form

The new application will be listed on your Heroku dashboard. Select the application and go to the deploy tab, where you’ll find the option to connect your GitHub account. 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.
Connect Heroku app with git repository

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

Set up automatic deployments on Heroku
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. This adds the token to the env variables of the process. If you want, you can remove the dotenv configuration in the initial application code.

Add env variables
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.
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.

This article was originally published on Live Code Stream by Anjalee Sudasinghe.