Quickstart Guide
This guide will walk you through creating your first Discord bot with Pycord using modern slash commands.
Prerequisites
Install Pycord
Make sure you have Pycord installed. See the installation guide if you haven’t done this yet. Create a Discord Application
- Go to the Discord Developer Portal
- Click “New Application” and give it a name
- Navigate to the “Bot” section and click “Add Bot”
- Under the bot’s username, click “Reset Token” to get your bot token
Invite Your Bot
- Go to the “OAuth2” → “URL Generator” section
- Select scopes:
bot and applications.commands
- Select permissions your bot needs (e.g., “Send Messages”, “Read Messages/View Channels”)
- Copy the generated URL and open it in your browser to invite the bot to your server
Never share your bot token! Anyone with your token can control your bot. If you accidentally expose it, reset it immediately in the Developer Portal.
Your First Bot
Create a new file called bot.py and add the following code:
import discord
bot = discord.Bot()
@bot.slash_command()
async def hello(ctx, name: str = None):
"""Say hello to someone"""
name = name or ctx.author.name
await ctx.respond(f"Hello {name}!")
@bot.event
async def on_ready():
print(f"{bot.user} is ready and online!")
bot.run("YOUR_BOT_TOKEN")
Replace YOUR_BOT_TOKEN with the token you copied from the Discord Developer Portal.
Run Your Bot
If everything is set up correctly, you should see “[Your Bot Name] is ready and online!” in your terminal.
Test Your Bot
In your Discord server, type /hello and press Enter. Your bot should respond with “Hello [your name]!” Try typing /hello name:Friend to greet someone else!
Understanding the Code
Let’s break down what each part does:
Imports the Pycord library.
Creates a bot instance. This is the main object that represents your Discord bot.
@bot.slash_command()
async def hello(ctx, name: str = None):
"""Say hello to someone"""
Defines a slash command. The function name becomes the command name, and the docstring becomes its description.
name = name or ctx.author.name
await ctx.respond(f"Hello {name}!")
Uses the provided name or defaults to the command user’s name, then responds to the interaction.
@bot.event
async def on_ready():
print(f"{bot.user} is ready and online!")
An event listener that triggers when the bot successfully connects to Discord.
bot.run("YOUR_BOT_TOKEN")
Starts the bot and connects to Discord.
Adding More Commands
Let’s add a few more commands to make your bot more useful:
import discord
import random
bot = discord.Bot()
@bot.slash_command()
async def hello(ctx, name: str = None):
"""Say hello to someone"""
name = name or ctx.author.name
await ctx.respond(f"Hello {name}!")
@bot.slash_command()
async def roll(ctx, sides: int = 6):
"""Roll a dice"""
result = random.randint(1, sides)
await ctx.respond(f"🎲 You rolled a {result}!")
@bot.slash_command()
async def userinfo(ctx, member: discord.Member = None):
"""Get information about a user"""
member = member or ctx.author
embed = discord.Embed(
title=f"{member.name}'s Info",
color=member.color
)
embed.add_field(name="ID", value=member.id)
embed.add_field(name="Joined", value=discord.utils.format_dt(member.joined_at))
embed.set_thumbnail(url=member.display_avatar.url)
await ctx.respond(embed=embed)
@bot.event
async def on_ready():
print(f"{bot.user} is ready and online!")
bot.run("YOUR_BOT_TOKEN")
Working with Command Options
You can add detailed options to your commands with descriptions, choices, and constraints:
import discord
from discord import option
bot = discord.Bot()
@bot.slash_command()
@option("name", description="Enter your name")
@option(
"pokemon",
description="Choose your starter Pokémon",
choices=["Bulbasaur", "Squirtle", "Charmander", "Pikachu"]
)
@option(
"age",
description="Enter your age",
min_value=1,
max_value=99,
default=18
)
async def introduce(ctx, name: str, pokemon: str, age: int):
"""Introduce yourself"""
await ctx.respond(
f"Hello {name}! Your starter Pokémon is {pokemon} and you are {age} years old."
)
bot.run("YOUR_BOT_TOKEN")
The @option decorator allows you to add descriptions, set choices, define min/max values, and set default values for command parameters.
Pycord also supports context menu commands (right-click commands):
import discord
bot = discord.Bot()
@bot.user_command(name="Say Hello")
async def say_hello(ctx, user: discord.User):
await ctx.respond(f"{ctx.author.mention} says hello to {user.name}!")
@bot.message_command(name="Count Words")
async def count_words(ctx, message: discord.Message):
word_count = len(message.content.split())
await ctx.respond(f"This message has {word_count} words.")
bot.run("YOUR_BOT_TOKEN")
Context menu commands appear when you right-click on a user or message. They provide quick actions without typing commands.
Best Practices
Store Your Token Securely
Never hardcode your token. Use environment variables instead:import os
from dotenv import load_dotenv
load_dotenv()
bot.run(os.getenv("DISCORD_TOKEN"))
Handle Errors Gracefully
Add error handling to improve user experience:@bot.event
async def on_application_command_error(ctx, error):
if isinstance(error, discord.errors.ApplicationCommandInvokeError):
await ctx.respond("An error occurred while running the command.", ephemeral=True)
Use Intents Appropriately
Only request the intents your bot needs:intents = discord.Intents.default()
intents.message_content = True # Only if you need to read message content
intents.members = True # Only if you need member information
bot = discord.Bot(intents=intents)
Responding to Interactions
Understanding how to respond to interactions is crucial:
@bot.slash_command()
async def example(ctx):
# Basic response
await ctx.respond("Hello!")
# Ephemeral response (only visible to the user)
await ctx.respond("This is private!", ephemeral=True)
# Deferred response (for long-running operations)
await ctx.defer()
# ... do something that takes time ...
await ctx.followup.send("Done!")
Important: Discord interactions must be responded to within 3 seconds. If your command takes longer, use await ctx.defer() to acknowledge the interaction, then use ctx.followup.send() to send the actual response.
Debug Mode for Testing
When developing, use debug guilds to make your commands appear instantly in specific servers:
bot = discord.Bot(debug_guilds=[123456789, 987654321]) # Your server IDs
# Or per-command:
@bot.slash_command(guild_ids=[123456789])
async def test_command(ctx):
await ctx.respond("This is a test!")
Without debug_guilds, commands can take up to an hour to appear globally. Use debug guilds during development for instant updates.
Next Steps
Congratulations! You’ve created your first Discord bot with Pycord. Here’s what to explore next:
- Interactive Components - Learn about buttons, select menus, and modals
- Cogs - Organize your bot code into modular extensions
- Voice Features - Add music and audio capabilities
- Database Integration - Store persistent data for your bot
- Advanced Patterns - Explore error handling, checks, and middleware