Discord
Send global chat, joins, leaves, server switches, and private messages to Discord with a bot or webhooks, and show Discord chat in Minecraft.
Discord settings are in plugins/nexusshout/discord.yml (plugins/NexusShout/discord.yml on BungeeCord), apart from config.yml, so you can keep tokens and webhook URLs out of shared or version-controlled files. The integration is off by default (enabled: false). Run nshoutreload after editing.
The default discord.yml explains every setting in its comments.
Bot or webhook
Each message is sent either by a bot or by a webhook. You choose per event, so you can mix them, for example the bot for chat and webhooks for joins and leaves.
| Bot | Webhook | |
|---|---|---|
| Minecraft to Discord | Yes | Yes |
| Discord to Minecraft | Yes | No |
| Name and avatar | The bot's own | The player's name and head |
| Embeds | Yes | Yes |
| Needs | A bot token, your server ID, and channel IDs | Webhook URLs |
Quick start: webhook
- In Discord, open the channel settings, go to Integrations, then Webhooks, and create a webhook. Copy its URL.
- In
discord.yml:
enabled: true
channel-routing:
default-route:
webhook-url: "https://discord.com/api/webhooks/..."
events:
global-chat:
enabled: true
transport: "webhook"
- Run
nshoutreload.
With the default file, joins and leaves also go to this webhook. Turn them off under events if you do not want them.
Quick start: bot
- Create an application at the Discord Developer Portal, add a bot, and copy its token.
- To show Discord chat in Minecraft, turn on Message Content Intent and Server Members Intent on the Bot page.
- Invite the bot to your Discord server with View Channels, Send Messages, Read Message History, and Add Reactions. Add Embed Links if you use embeds.
- Turn on Developer Mode in Discord (User Settings, Advanced). Then right-click your server and your channel to copy their IDs.
- In
discord.yml:
enabled: true
bot:
enabled: true
token: "your-bot-token"
guild-id: "111111111111111111"
inbound:
enabled: true
channel-routing:
default-route:
channel-id: "222222222222222222"
events:
global-chat:
enabled: true
transport: "bot"
- Run
nshoutreload. The console showsDiscord bot logged in as ...once the bot is connected.
Keep the token secret. Anyone with it can control the bot.
Routing
channel-routing:
default-route:
channel-id: "111111111111111111"
webhook-url: ""
overrides:
Lobby-1:
channel-id: "222222222222222222"
SkyBlock:
channel-id: "333333333333333333"
webhook-url: "https://discord.com/api/webhooks/..."
Keys under overrides are server names from the proxy config (velocity.toml, or config.yml on BungeeCord). channel-id is used by bot events, and webhook-url by webhook events.
| Event | Where it goes |
|---|---|
global-chat | The sender's server in overrides, otherwise default-route |
server-switch | The server the player moved to, in overrides, otherwise default-route |
player-join, player-leave | default-route |
private-messages | Its own channel-id or webhook-url under events.private-messages |
For webhook events other than private-messages, when no webhook URL is found, webhooks.default-url is used.
Events
| Event | Default | Transport | Placeholders |
|---|---|---|---|
global-chat | On | bot | {name}, {uuid}, {server}, {server_alias}, {message}, {custom_rank}, {custom_name} |
private-messages | Off | webhook | {sender}, {receiver}, {message} |
player-join | On | webhook | {name}, {uuid} |
player-leave | On | webhook | {name}, {uuid} |
server-switch | Off | webhook | {name}, {uuid}, {from_server}, {to_server}, {from_server_alias}, {to_server_alias} |
Join and leave mean joining and leaving the network, not a single server. {server_alias} is the display name from server-aliases in config.yml. The join is posted when the player reaches their first server. Joins, leaves, and server switches of vanished players (PremiumVanish or SayanVanish) are not posted.
Each event can have these settings:
| Setting | Default | Notes |
|---|---|---|
enabled | see above | |
transport | see above | bot or webhook |
format | see the default file | The Discord text. Discord markdown works here |
strip-formatting | true | Removes Minecraft colors from the values |
allowed-mentions | ["users"] ([] for private-messages) | Which mentions can ping: users, roles, everyone. Use [] for none |
use-embed | false | Sends the text as an embed. Not used for private-messages |
embed-color | see the default file | Embed color in hex, for example #2ecc71 |
enabled-servers | [] | global-chat and server-switch only. Empty: all servers |
Player names and messages are escaped, so players cannot use Discord markdown such as bold text or quotes. When {name} or {message} is inside backticks in your format, only backticks in the value are replaced.
Webhook settings
webhooks:
default-url: ""
use-player-head-avatar: true
crafatar-url-template: "https://crafatar.com/avatars/{uuid}?overlay=true"
fallback-avatar-url: ""
username-template: "{name}"
| Setting | Notes |
|---|---|
default-url | Used when no route has a webhook URL |
use-player-head-avatar | Shows the player's head as the avatar, from crafatar-url-template |
fallback-avatar-url | Avatar used when use-player-head-avatar is false. Empty: the webhook's own avatar |
username-template | Name shown on the message. Placeholders: {name}, {server}, {server_alias} |
These apply to webhooks only. Bot messages use the bot's own name and avatar.
Discord to Minecraft
Messages from Discord need the bot, with bot.inbound.enabled: true and the two intents from the quick start.
bot:
inbound:
enabled: false
channels: []
allowed-role-ids: []
mc-format: "&9[Discord] &b{discord_display_name}&7: &f{message}"
show-replies: true
convert-markdown: true
sanitize-mentions: true
ignore-bots: true
max-length: 256
| Setting | Notes |
|---|---|
channels | Channel IDs whose messages go to Minecraft. Empty: every channel-id in channel-routing |
allowed-role-ids | Only members with one of these role IDs reach Minecraft. Empty: everyone in the channel |
mc-format | How the message looks in Minecraft. Placeholders: {discord_name} (username), {discord_display_name} (server nickname), {role} (their top role), {channel}, {message} |
show-replies | When the message is a reply, shows the original above it in gray italics |
convert-markdown | Turns bold, italic, underline, strikethrough, and code into Minecraft formatting |
sanitize-mentions | Shows mentions as @name and #channel, custom emoji as :name:, and stops @everyone and @here |
ignore-bots | Skips messages from bots, including other bridge bots. Keep it on to avoid loops |
max-length | Longer messages are cut short and end with ... |
deny-feedback | What happens when a member without an allowed role posts: react with reaction-emoji, and reply with reply-message. By default it only reacts |
- When
guild-idis set, only messages from that Discord server are used. - Discord text cannot add Minecraft formatting of its own.
- Messages from Discord follow
enabled-serversinconfig.yml, and they are never sent back to Discord.
Bot status
bot:
activity:
type: "PLAYING"
text: "Minecraft on {player_count} servers"
update-interval: 60
type:PLAYING,WATCHING,LISTENING,COMPETING,STREAMING, orNONE.STREAMINGuses a generic Twitch link.text:{player_count}is the number of players on this proxy, and{server_count}the number of servers registered on it.update-interval: seconds between updates.0sets the status once at startup.
Intents
| Setup | Privileged intents needed |
|---|---|
| Bot only sends to Discord | None |
| Discord to Minecraft is on | Message Content Intent and Server Members Intent |
Delivery
delivery:
queue-size: 500
min-interval-ms: 250
max-retries: 3
retry-backoff-ms: 1000
| Setting | Notes |
|---|---|
queue-size | Messages waiting per channel or webhook. When full, the oldest is dropped and a warning is logged |
min-interval-ms | Shortest time between two sends to the same channel or webhook. Discord allows about 5 messages per 5 seconds per channel |
max-retries | Webhooks only. How many times a failed send is tried again, after a Discord server error or a rate limit |
retry-backoff-ms | Webhooks only. Wait before the first retry, doubled each time. After a rate limit, the wait Discord asks for is used |
More than one proxy
You can use the same discord.yml on every proxy. Each chat message reaches Discord once, and each Discord message reaches Minecraft once. See multi-proxy.