discord.py on Grumble
Python. Your discord.py bot runs on Grumble with two lines changed: where it sends requests and where it connects. Tested with discord.py 2.7.1.
Install
pip install discord.py
Point it at Grumble
Make a bot in the Developer Portal and copy its token. Then change two lines (marked):
import os, discord, yarl
discord.http.Route.BASE = "https://grumble.gg/api/v10"discord.gateway.DiscordWebSocket.DEFAULT_GATEWAY = yarl.URL("wss://grumble.gg/gateway/")
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
@client.event
async def on_message(message):
if message.content == "!ping":
await message.reply("pong")
client.run(os.environ["GRUMBLE_TOKEN"])
Set both. discord.py doesn't ask the server where its gateway is, so without the second line your bot logs in to Grumble and then hands its token to Discord's gateway, which turns it away.
For your own Grumble server, use its address instead of grumble.gg.
In encrypted servers: through the bridge
Grumble's servers are end-to-end encrypted, and our servers never hold the keys. Talking to Grumble directly, your bot gets their messages, names and what people type in its commands still sealed. The Grumble bridge is a small program you run next to your bot. It holds your bot's keys on your machine and serves your bot this same API on your own computer, with everything opened, and seals what your bot sends: messages, files, embeds, buttons and menus.
npx grumble-bridge --token $GRUMBLE_TOKEN
Then point discord.py at the bridge instead of Grumble: Route.BASE = "http://127.0.0.1:3170/api/v10", and the gateway the bridge gives at GET /gateway/bot (ws://127.0.0.1:3170/). Nothing else changes. The bridge can also stand in for Discord's own addresses (its transparent mode), for a bot you'd rather not change at all.
What we test
Our bot sweep runs a discord.py bot through the everyday things bots do, then plays a person in the app: reading its messages, using its command and pressing its button. It runs talking to Grumble directly, and through the bridge in an encrypted server. Last run 13 November 2026, with discord.py 2.7.1: 57 of 57 directly, and 59 of 59 through the bridge.
| What it does | Directly | Bridge |
|---|---|---|
| Connecting | ||
| Logs in and connects to the gateway | ✓ | ✓ |
| Reads its own account | ✓ | ✓ |
| Sees its server and channels | ✓ | ✓ |
| Messages | ||
| Sends a message | ✓ | ✓ |
| Sends an embed | ✓ | ✓ |
| Sends a file | ✓ | ✓ |
| Edits its message | ✓ | ✓ |
| Fetches a message | ✓ | ✓ |
| Reads a channel's history | ✓ | ✓ |
| Shows it's typing | ✓ | ✓ |
| Reads a person's message | ✓ | ✓ |
| Replies to it | ✓ | ✓ |
| Hears the person edit it | ✓ | ✓ |
| Hears the person delete it | ✓ | ✓ |
| Sends several in a row | ✓ | ✓ |
| Deletes several at once | ✓ | ✓ |
| Deletes its message | ✓ | ✓ |
| Reactions and pins | ||
| Reacts | ✓ | ✓ |
| Lists who reacted | ✓ | ✓ |
| Takes its reaction back | ✓ | ✓ |
| Hears the person react | ✓ | ✓ |
| Pins a message | ✓ | ✓ |
| Lists pins | ✓ | ✓ |
| Unpins | ✓ | ✓ |
| Threads | ||
| Starts a thread from a message | ✓ | ✓ |
| Posts in it | ✓ | ✓ |
| Archives it | ✓ | ✓ |
| Starts a thread on its own | ✓ | ✓ |
| Channels | ||
| Makes a channel | ✓ | ✓ |
| Renames it | ✓ | ✓ |
| Sets a permission on it | ✓ | ✓ |
| Deletes it | ✓ | ✓ |
| Roles and members | ||
| Makes a role | ✓ | ✓ |
| Edits it | ✓ | ✓ |
| Gives it to someone | ✓ | ✓ |
| Takes it back | ✓ | ✓ |
| Deletes it | ✓ | ✓ |
| Fetches a member | ✓ | ✓ |
| Lists members | ✓ | ✓ |
| Asks the gateway for members | ✓ | ✓ |
| Sets its nickname | ✓ | ✓ |
| Fetches a user | ✓ | ✓ |
| Direct messages | ||
| Messages someone directly | – | ✓ |
| Webhooks | ||
| Makes a webhook | ✓ | ✓ |
| Posts through it | ✓ | ✓ |
| Deletes it | ✓ | ✓ |
| Commands and buttons | ||
| Registers its slash commands | ✓ | ✓ |
| Gets a slash command | ✓ | ✓ |
| Answers it | ✓ | ✓ |
| Sends a button | ✓ | ✓ |
| Hears it pressed and answers | ✓ | ✓ |
| What a person sees in the app | ||
| Its reply | ✓ | ✓ |
| Its slash command, offered | ✓ | ✓ |
| Its answer to the command | ✓ | ✓ |
| Its answer to the button | ✓ | ✓ |
| Its embed | ✓ | ✓ |
| Its file | ✓ | ✓ |
| Its webhook's message | ✓ | ✓ |
| Its direct message | – | ✓ |
✓ works. – not possible that way: Grumble's direct messages are end-to-end encrypted, so a bot can only send one through the bridge, which seals it.
Something not working? Tell us on the feedback page, with your library's version. discord.py belongs to its authors; Grumble isn't affiliated with Discord Inc.