Discord bots are AI-driven tools that can help you automate tasks on your Discord server. They make it a lot easier to build a community that is truly engaged and can be used to moderate your server, welcome new members, or even ban people who are creating a bad environment for everyone else. Aside from moderation features, Discord bots let you and users add games, music, memes, and other fun, engaging, and entertaining content. Popular bots are a few like Mee6, Carl-Bot, Hydra, Dank Memer and more!
Before you start coding discord bots with python, there are some requirements that are necessary to get a full-fledged understanding about the working of the bots!
Few requirements are as follows:
- Basic knowledge of variables, data types, keywords and some commonly used in-built functions in python
- String methods, List methods, Dictionary methods, Set methods
- Familiar with asynchronous programming within python. [Use case of keywords such as
async
andawait
and the libraryasyncio
] - Have familiarity with Object Oriented Programming within python
- An understanding about indentation
- Have knowledge about scopes of variables, et cetera
- Importing of libraries and local files into each other
- Type Hinting of variables and parameters!
Prior to starting to code a discord bot, there's some steps to follow to create a bot and invite it to a discord server! You can follow the steps below to get started!
-
Visit the discord developer portal and sign up/login.
-
Now click on the
New Application
button from the top-right corner. -
A prompt will appear to enter the name of your application AKA your bot. Type in your desired name and hit
Create
. This will take you to your bot's control panel webpage! -
(Optional) In the
General
tab (selected by default), you can upload an avatar for your bot by clicking on your bot's current shown avatar or remove the avatar as desired! -
Click on the
Bot
tab from the left pane and hitAdd Bot
and clickYes, do it!
. If a messages withA wild bot has appeared!
is flashed on your screen, this means that you have successfully added your first bot to an app on discord! Note: If you get an error such asToo many users have this username, please try another.
. Head over to theGeneral Information
tab and change your application's name from the text box and hitSave Changes
, now follow the same step again. -
Now scroll down in the
Bot
tab and enable the Message Content intent and Members intent. -
Go to the
Oauth2
tab from the left pane and click on theURL Generator
tab from the drop down and selectbot
from the list of scopes. This will show the same list of permissions as from theBot
page! Select theView Channels/Read Messages
,Send Messages
permissions (or others if required) and while this generates a URL at the bottom of the webpage, copy the URL and paste it in a new tab of your web browser and invite the bot to your test server! -
With this you have now created your first bot and added it your server!
Discord bots work with a gateway connection from a piece of code sending requests to the API to perform certain functions. This seems a bit hectic to code by yourself and so to make life easier, API wrappers for python for the discord API such as discord.py
, hikari
, etc. were created! In this tutorial, we will use the discord.py
library to code our first discord bot! A discord bot uses a token to connect your bot app with the gateway, you can find the token in the Bot
page of your application! You may have to reset the token to copy it. We will need the token shortly!
The latest and up-to-date usable discord.py version can be installed using pip install discord.py
Intents is a feature of Discord that tells the gateway exactly which events to send your bot. By default discord.py has all intents enabled except for Members, Message Content, and Presences. These are needed for features such as on_member events, to get access to message content, and to get members' statuses.
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
bot.run("token that you copied")
The above code will basically do nothing other than getting your bot online for the first time!
EXPLANATION
import discord
imports the discord.py package that we just installed.from discord.ext import commands
imports thecommands
extension from the discord.py package!intents = discord.Intents.default()
enables all the unprivileged intents, in essence, all the intents excludingMembers
,Presences
,Message Content
intents are enabled. Now the bot will receive all the events except the privileged intents!intents.members = True
enables theMembers
intent in our code which tells discord.py to receive all Member events from the gateway!intents.message_content = True
enables theMessage Content
intent in our code which tells discord.py to connect with the discord gateway so as your bot is able to read the content of the messages sent by other users. Message content is required to detect invocation of message commands such as!ping
, et cetera.bot = commands.Bot(command_prefix="!", intents=intents)
basically creates aBot
object which acts as a multi-purpose container which holds your message commands and slash commands, user commands et cetera. ABot
object is also capable of fetching guilds (servers) and users from the discord API itself to receive information about the same!bot.run("token")
connects your current bot application with the corresponding token passed to therun
method and creates an active websocket connection with the discord gateway which frequently sends heartbeats to the discord API to keep the websocket connection with the discord API from dying. This is how the bot gets online! Note that this method creates an infinite loop and no code below this method will ever run!
Message commands in discord.py are held by the Bot
itself and created through the Bot.command
method of the Bot class. An asynchronous function is decorated with this method which indicates to discord.py that the decorated function is to be a message command! The function takes a default argument which is an instance of a Context
object and is to be the first parameter of the function. This parameter is internally handled by discord.py whenever a command invocation occurs! The Context
argument holds useful information about the invoked command and invoker of the command! The Context
argument is also named as ctx
by convention! If no name of the command is specified in the decorator for the command, then the name of the function is used for the command name instead!
A simple message command in action!
bot = commands.Bot(command_prefix="!", intents=...)
@bot.command(name="hello")
async def hello(ctx: commands.Context) -> None:
await ctx.send("Hello There!")
The hello
command can be invoked by !hello
. Make sure to enable the message content intent too!
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
@bot.command()
async def hello(ctx: commands.Context) -> None:
await ctx.send("Hello There!")
bot.run("token that you copied")
The following command will return a quote from an API!
import discord
from discord.ext import commands
import aiohttp
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
@bot.command()
async def quote(ctx: commands.Context) -> None:
resp = await bot.http.get("https://zenquotes.io/api/random")
if resp.status != 200:
return await ctx.reply("Could not get a quote!")
data = await resp.json()[0]
await ctx.send(f"**{data['q']}** - *{data['a']}*")
async def main() -> None:
async with bot:
async with aiohttp.ClientSession() as session:
bot.http = session
await bot.start("token")
NOTE: start
is another method which is the same as run
.
- Here a single
ClientSession
has been created to save resources rather than creating a ClientSession on every command invocation which would have been unnecessary and a bad practice. bot.http
basically acts a container for theClientSession
object which can be used anywhere in the code and the value of the variable can be set from anywhere and any command! Such variables are known as bot variables and helpful for if facing any variable scope issues! Before naming your bot variables, it is important to check what you name them as you are likely to overwrite a property or method of the Bot class such ascommand
,cogs
, et cetera. NOTE: Use theaiohttp
library instead ofrequests
as discord bots are asynchronous and requests is not an asynchronous library which if used will block all the other functions and the internal heartbeat sending requests to the discord API, eventually disconnecting your bot from the gateway and terminating the connection.
import discord
from discord.ext import commands
import asyncio
import aiohttp
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
#getting the information about the author of the command invocation
@bot.command()
async def username(ctx: commands.Context) -> None:
await ctx.send(ctx.author.name)
bot.run("token")
The above command when run using !username
will send back the name of the author of the command invocation!
import discord
from discord.ext import commands
import asyncio
import aiohttp
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
@bot.command()
async def embed(ctx: commands.Context, *, text: str) -> None:
embed = discord.Embed(title=ctx.author.name, description=text, colour=discord.Colour.random()).set_thumbnail(url=ctx.author.display_avatar.url)
await ctx.send(embed=embed)
bot.run("token")
- In the
embed
command, we can see a new parameter definition named astext
here. This will simply allow us to accept another argument passed during command invocation. For example!embed this is my text
will capture the content fromthis
totext
in the parameter named astext
. The presence of*
which makes thetext
argument a keyword-argument captures the whole argument sent after a space (*
was absent, then the argument content which would have been captured would just have beenthis
instead ofthis is my text
. embed = discord.Embed(...)
initiates an Embed object to which the arguments are passed..set_thumbnail
sets an image of the avatar of the author on the top-right corner of the embed andawait ctx.send(embed=embed)
sends an embed back as a response. Note thatembed=
is a keyword-argument.