discord.py (Official Discord API Wrapper for Python)
discord.py is a modern, easy-to-use, feature-rich, and async-ready API wrapper for Discord written in Python. It simplifies interaction with the Discord API, enabling developers to create bots with various functionalities, from simple message responders to complex moderation tools. The library is actively maintained, with new releases typically following Discord API updates, and currently requires Python 3.8 or higher. [1, 2, 7]
Common errors
-
ModuleNotFoundError: No module named 'discord'
cause The `discord.py` library is not installed in the active Python environment, or the script is named `discord.py` causing a conflict. [24, 26, 29]fixEnsure you've installed the correct package: `pip install -U discord.py`. If using a virtual environment or IDE, ensure it's active and packages are installed within it. Check that your script is not named `discord.py`. [26, 29] -
Privileged message content intent is missing, commands may not work as expected.
cause The 'Message Content Intent' is not enabled in your bot's settings on the Discord Developer Portal, or `intents.message_content = True` is missing in your bot's code for `discord.py` v2.0+. [16, 17, 25]fixGo to the Discord Developer Portal, navigate to your bot's settings, and enable the 'Message Content Intent' under 'Privileged Gateway Intents'. Also, ensure your bot initialization includes `intents = discord.Intents.default(); intents.message_content = True`. [16, 17, 25] -
TypeError: __init__ missing 1 required keyword-only argument: 'intents'
cause You are using `discord.py` v2.0+ and have not provided the mandatory `intents` keyword argument when initializing `discord.Client` or `commands.Bot`. [14]fixAdd the `intents` argument to your bot's initialization: `intents = discord.Intents.default(); bot = commands.Bot(command_prefix='!', intents=intents)`. -
AttributeError: 'Member' object has no attribute 'avatar_url'
cause You are using `discord.py` v2.0+ but your code is trying to access an old attribute like `avatar_url`. In v2.0+, asset-related attributes return `Asset` objects. [7, 22]fixReplace `member.avatar_url` with `member.display_avatar.url` to get the user's avatar or default avatar, or `member.avatar.url` if you specifically want only their custom avatar and handle `None` cases. [7, 22]
Warnings
- breaking The `discord` package on PyPI is a mirror and not the official library. Installing `discord` instead of `discord.py` can lead to outdated versions, missing features, or even malicious code. [PyPI summary, 21]
- breaking Version 2.0+ of `discord.py` dropped support for Python versions below 3.8. Ensure your environment meets this requirement. [7, 14, 23]
- breaking Intents are now mandatory for `Client` and `Bot` initialization. The `message_content` intent became privileged in v2.0, meaning you must explicitly enable it in your code and on the Discord Developer Portal for your bot to receive message content and process text commands. User account automation is against Discord ToS, and support for user tokens was removed. [7, 14, 19, 23, 27]
- breaking Many methods like `edit()` no longer update objects in-place; they now return a new, modified instance. Old attributes like `User.avatar_url` or `Guild.icon_url` have been replaced or changed to `Asset` objects. [7, 14, 19, 22]
- gotcha Do not name your Python script `discord.py` or any name that conflicts with the library's internal modules. This can cause `ImportError` or `ModuleNotFoundError` due to Python's import system looking at your local file instead of the installed library. [3, 24]
Install
-
pip install -U discord.py -
pip install -U "discord.py[voice]"
Imports
- Client
from discord import Client
import discord client = discord.Client(...)
- Intents
from discord import Intents
import discord intents = discord.Intents.default()
- Bot
import discord bot = discord.Bot(...)
from discord.ext import commands bot = commands.Bot(...)
- View
from discord import View
from discord.ui import View
Quickstart
import discord
from discord.ext import commands
import os
# Configure intents: message_content is a privileged intent
intents = discord.Intents.default()
intents.message_content = True # Required for text commands that read message content [7]
# Initialize the bot with a command prefix and intents
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'Logged in as {bot.user} (ID: {bot.user.id})')
print('------')
@bot.command()
async def ping(ctx):
"""Responds with pong!"""
await ctx.send('pong!')
@bot.event
async def on_message(message):
# Ignore messages from the bot itself
if message.author == bot.user:
return
# Process commands (needed if you also have on_message event handler)
await bot.process_commands(message)
# Get the bot token from an environment variable for security
BOT_TOKEN = os.environ.get('DISCORD_BOT_TOKEN', 'YOUR_BOT_TOKEN_HERE')
if BOT_TOKEN == 'YOUR_BOT_TOKEN_HERE':
print("WARNING: Replace 'YOUR_BOT_TOKEN_HERE' with your actual bot token or set DISCORD_BOT_TOKEN env var.")
# Run the bot
bot.run(BOT_TOKEN)