Discord.Net on Grumble
C# and .NET. Your Discord.Net bot runs on Grumble with one setting changed: where it sends requests. Tested with Discord.Net 3.20.2.
Install
dotnet add package Discord.Net
Point it at Grumble
Make a bot in the Developer Portal and copy its token. Then change one setting (marked):
var client = new DiscordSocketClient(new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent,
RestClientProvider = _ => DefaultRestClientProvider.Create()("https://grumble.gg/api/v10/"),});
client.MessageReceived += async m =>
{
if (m.Content == "!ping") await m.Channel.SendMessageAsync("pong");
};
await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("GRUMBLE_TOKEN"));
await client.StartAsync();
await Task.Delay(-1);
Discord.Net asks the server where its gateway is, so the API address is all it needs. Give a DiscordWebhookClient the same RestClientProvider.
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.Net at the bridge instead of Grumble: DefaultRestClientProvider.Create()("http://127.0.0.1:3170/api/v10/"). 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.Net 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.Net 3.20.2: 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.Net belongs to its authors; Grumble isn't affiliated with Discord Inc.