JDA on Grumble
Java and Kotlin. Your JDA bot runs on Grumble with two settings changed: where it sends requests and where it connects. Tested with JDA 6.7.0.
Install
implementation("net.dv8tion:JDA:6.+")
Point it at Grumble
Make a bot in the Developer Portal and copy its token. Then change two settings (marked):
JDABuilder.createDefault(System.getenv("GRUMBLE_TOKEN"))
.enableIntents(GatewayIntent.MESSAGE_CONTENT)
.setRestConfig(new RestConfig().setBaseUrl("https://grumble.gg/api/v10/")) .setSessionController(new SessionControllerAdapter() { @Override public String getGateway() { return "wss://grumble.gg/gateway"; } }) .addEventListeners(new MyBot())
.build();
Set both. JDA doesn't ask the server where its gateway is, so without the session controller 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 JDA at the bridge instead of Grumble: setBaseUrl("http://127.0.0.1:3170/api/v10/"), and the gateway the bridge gives at GET /gateway/bot. 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 JDA 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 JDA 6.7.0: 56 of 56 directly, and 58 of 58 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 | ✓ | ✓ |
| 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. JDA belongs to its authors; Grumble isn't affiliated with Discord Inc.