Skip to content

Setting Up the Discord Gateway

I have spent plenty of nights fighting with bot integrations where everything seems right, but the bot just stays offline. It usually comes down to a missed checkbox in a developer portal or a token that isn’t being read correctly. I want to help you avoid that loop and get your Discord connection running quickly.

  • A Discord Developer Portal application.
  • A Bot token.
  • Message Content Intent enabled.
  • Server Members Intent enabled.

I recommend following these four steps to get your gateway online.

1. Create a Discord bot and enable intents

Section titled “1. Create a Discord bot and enable intents”

Go to the Discord Developer Portal and create your application. Add a bot to the project and make sure you toggle these specific switches:

  • Message Content Intent
  • Server Members Intent (I suggest this for name-to-ID lookups and allowlist matching)

You can set your token in your configuration file. If you are using the default account, you can use an environment variable instead.

{
channels: {
discord: {
enabled: true,
token: "YOUR_BOT_TOKEN",
},
},
}

Or use the environment fallback:

Terminal window
DISCORD_BOT_TOKEN=...

I should mention that configuration values take priority. If you have a token in your config file, it will override the DISCORD_BOT_TOKEN environment variable.

Invite the bot to your server. Make sure it has message permissions. Once invited, run the gateway command:

Terminal window
openclaw gateway

Discord DMs use pairing mode by default. You need to list the active pairing requests and approve them using the provided code.

Terminal window
openclaw pairing list discord
openclaw pairing approve discord <CODE>

If things aren’t working as expected, check these two areas:

  • Expired Pairing Codes: Pairing codes only last for 1 hour. If you wait too long, you will need to generate a new one.
  • Group DMs: By default, group DMs are ignored because channels.discord.dm.groupEnabled is set to false.

If you run into a specific error not covered here, ask the AI Setup Assistant.

I’ve been in that spot where you deploy a bot and it immediately starts responding to every random message in a server, or worse, strangers start messaging it directly. It is a headache to clean up. I want to show you how to set up routing and access control properly so your bot only talks to the people and channels you actually want.

  • A Discord bot token from the Developer Portal.
  • Privileged Gateway Intents enabled (Message Content and Server Members).
  • Numeric IDs for your server, channels, and user account.
  • OAuth scopes: bot and applications.commands.

I find the fastest way to get running is to set up a strict allowlist from the start. This prevents the bot from leaking into places it doesn’t belong.

  1. Create your App: Head to the Discord Developer Portal, hit New Application, go to Bot, and click Add Bot. Copy your token.
  2. Enable Intents: In the Bot tab, scroll to Privileged Gateway Intents and toggle on Message Content Intent and Server Members Intent.
  3. Get your IDs: Enable Developer Mode in your Discord client settings. Right-click your server, your channel, and your own profile to copy their numeric IDs.
  4. Configure the Allowlist: Drop this into your config to lock the bot to specific channels.
{
channels: {
discord: {
groupPolicy: "allowlist",
guilds: {
"123456789012345678": {
requireMention: true,
users: ["987654321098765432"],
channels: {
general: { allow: true },
help: { allow: true, requireMention: true },
},
},
},
},
},
}

I usually recommend being very specific about who can DM the bot. You can control this via channels.discord.dm.policy.

  • pairing: This is the default. It prompts unknown users for pairing.
  • allowlist: Only specific users you’ve listed can talk to the bot.
  • open: Anyone can message it (requires channels.discord.dm.allowFrom to include "*").
  • disabled: DMs are completely off.

When you are targeting a user for delivery, I suggest using the format user:<id> or the <@id> mention. I’ve noticed that bare numeric IDs are often ambiguous and will be rejected unless you explicitly provide the target kind.

If you have channels.discord in your config, the bot defaults to a secure allowlist policy for guilds. If you don’t create a specific block but provide a DISCORD_BOT_TOKEN, it falls back to open but will throw a warning in your logs.

For the allowlist behavior:

  • The guild must match an ID or slug in channels.discord.guilds.
  • If you list a guild but don’t define a channels block inside it, the bot allows all channels in that guild.
  • If you do define a channels block, any channel not explicitly listed is denied.

By default, guild messages are mention-gated. This means the bot won’t respond unless it is explicitly called out. I’ve found this is the best way to keep noise down in busy servers. The bot looks for:

  • An explicit @bot mention.
  • Configured mention patterns in agents.list[].groupChat.mentionPatterns.
  • Implicit replies to the bot’s own messages.

You can toggle this per channel using requireMention.

Regarding commands, commands.native is set to "auto" by default. If you want to turn off Discord native commands, set commands.native=false, which clears any previously registered commands. Even if a user isn’t authorized, they might still see the commands in the Discord UI. However, if they try to run one, the bot enforces the auth policy and returns “not authorized.”

  • IDs being rejected: Make sure you aren’t using bare numbers. Use the user:<id> format for DMs to avoid ambiguity.
  • Bot ignoring messages: Check if requireMention is enabled for that guild or channel. If it is, the bot won’t respond to plain text without a mention.

If you hit a wall while setting this up, I recommend checking the AI Setup Assistant for help.

I’ve spent a lot of time trying to make bots feel like they actually belong in a conversation. It is a common headache when an agent just shouts into a channel instead of replying to a specific person or remembering what was said a few minutes ago. If you want your Discord integration to feel less like a script and more like a participant, you need to get these settings right.

I will show you how to handle replies, manage message history, and set up advanced tools like PluralKit and execution approvals.

  • An active Discord bot integration.
  • Access to your configuration file (JSON5).
  • A PluralKit token (if you use private systems).
  • Specific User IDs for DM-based history or approvals.

You can get the basics running in about five minutes by focusing on history and replies.

  1. Set History Limits: Define how many messages the agent sees.
    • channels.discord.historyLimit: Set this to 20 (the default).
  2. Enable Replies: Decide how the agent responds.
    • Set channels.discord.replyToMode to first or all.
  3. Test Threads: Send a message in a thread to see the agent inherit parent channel settings.

Discord allows agents to target specific messages. I recommend using native replies to keep conversations organized. You can control this with channels.discord.replyToMode.

Available modes:

  • off (default)
  • first
  • all

The agent can use these specific tags in its output:

  • [[reply_to_current]]
  • [[reply_to:<id>]]

Message IDs are included in the context and history, so agents know exactly which message to target.

Managing how much an agent remembers is vital for performance. You can set limits for both guilds and DMs.

  • Guild History: Use channels.discord.historyLimit. It defaults to 20. If this is missing, it uses messages.groupChat.historyLimit. Setting it to 0 disables history.
  • DM History: Use channels.discord.dmHistoryLimit for general DMs. For specific users, use channels.discord.dms["<user_id>"].historyLimit.

For threads, the system routes them as channel sessions. The agent can use parent thread metadata to link sessions. Thread configurations will inherit settings from the parent channel unless you create a specific entry for that thread. Note that channel topics are injected as untrusted context, not as system prompts.

You can decide how the agent reacts to emoji interactions. This is set per-guild using these modes:

  • off
  • own (default)
  • all
  • allowlist (uses guilds.<id>.users)

When a reaction occurs, the system turns it into a system event and attaches it to the Discord session.

By default, the system allows channel-initiated config writes. This is what makes /config set|unset commands work. If you want to stop this, use the following configuration:

{
channels: {
discord: {
configWrites: false,
},
},
}

If your community uses PluralKit, you can map proxied messages to system member identities. This helps the agent recognize who is actually speaking.

{
channels: {
discord: {
pluralkit: {
enabled: true,
token: "pk_live_...", // optional; needed for private systems
},
},
},
}

Key points for PluralKit:

  • You can use pk:<memberId> in allowlists.
  • The system matches member display names by name or slug.
  • Lookups are constrained by a time window.
  • If a lookup fails, proxied messages are dropped as bot messages unless allowBots=true is set.

You can handle execution approvals directly in Discord DMs using buttons. This is great for maintaining security without leaving the app.

Configuration paths:

  • channels.discord.execApprovals.enabled
  • channels.discord.execApprovals.approvers
  • Other options include agentFilter, sessionFilter, and cleanupAfterResolve.

Approvals are failing with “unknown approval IDs” If you run into this, you should verify your approvers list. Also, double-check that the execApprovals.enabled flag is actually set to true in your config.

Proxied messages are being ignored If you are using PluralKit and messages aren’t showing up, the lookup might be failing. The system drops these as bot messages by default. You can fix this by setting allowBots=true.

Agent is ignoring channel topics Remember that channel topics are treated as untrusted context. They are not system prompts, so the agent might not follow them as strictly as you expect.

Need more help with your specific configuration? Check out the AI Setup Assistant.

Dealing with bot permissions often feels like a guessing game. You want your integration to perform specific tasks, but figuring out which actions are allowed and where to toggle them can be a headache when you are just trying to get your code running. I find it much easier to have a clear map of what is available and what is locked by default.

  • Access to the channels.discord.actions.* configuration path.
  • Knowledge of your required action groups (like messaging or moderation).

I recommend starting with the core actions. Discord message actions cover everything from basic chatting to server administration and metadata.

Here are the core examples of what you can do:

  • messaging: sendMessage, readMessages, editMessage, deleteMessage, threadReply
  • reactions: react, reactions, emojiList
  • moderation: timeout, kick, ban
  • presence: setPresence

You control these through action gates located under channels.discord.actions.*. While many features are ready to use immediately, some sensitive groups are turned off by default to keep things secure.

Refer to this table to see the default behavior for each action group:

Action groupDefault
reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissionsenabled
rolesdisabled
moderationdisabled
presencedisabled

If you try to use a moderation tool like kick or ban and it fails, check your action gates. Since moderation, roles, and presence are set to disabled by default, your integration will not have permission to execute those specific functions until you change the configuration.

If you have questions about a specific gate, ask the AI Setup Assistant.

I know the feeling when you’ve spent time configuring your Discord gateway only to find the bot won’t respond to a single command. It is frustrating when the logs stay silent or messages seem to vanish without any clear error. I have spent many nights staring at a terminal window wondering why my configuration isn’t picking up events that are clearly happening in the server.

Usually, the fix is hidden in a small intent setting or a specific allowlist rule. I have put together this guide to help you debug these common friction points so you can get back to building.

  • An active Discord Bot Token (stored as DISCORD_BOT_TOKEN).
  • The openclaw CLI tool.
  • Access to your gateway configuration file.
  • Discord Developer Portal access to toggle intents.

If things aren’t working, I recommend this 5-minute check to find the root cause:

  1. Run openclaw doctor to verify your environment and connection.
  2. Check your intents in the Discord Developer Portal; ensure Message Content Intent is on.
  3. Use openclaw channels status --probe to see if the bot can actually “see” your target channels.
  4. Restart the gateway service after any configuration change to ensure the new settings take effect.

If your bot is online but sees no guild messages, it is almost always an intent issue. You need to:

  • Enable Message Content Intent in the Discord Developer Portal.
  • Enable Server Members Intent if your logic depends on user or member resolution.
  • Restart the gateway after changing these intents on the Discord website.

When messages are being sent but the bot ignores them, I check these four areas:

  • Verify the groupPolicy setting.
  • Check the guild allowlist under channels.discord.guilds.
  • If a guild channels map exists, remember that only listed channels are allowed.
  • Verify requireMention behavior and your mention patterns.

I find these commands are the fastest way to verify what is happening:

Terminal window
openclaw doctor
openclaw channels status --probe
openclaw logs --follow

Require mention is false but still blocked

Section titled “Require mention is false but still blocked”

If you set requireMention to false and messages are still blocked, it is likely one of these causes:

  • You have groupPolicy="allowlist" set without a matching guild or channel allowlist.
  • The requireMention toggle is in the wrong place. It must be under channels.discord.guilds or a specific channel entry.
  • The sender is blocked by a guild or channel users allowlist.

The channels status --probe command is great, but it has a limitation. Permission checks only work for numeric channel IDs. If you use slug keys, the runtime matching still works, but the probe cannot fully verify permissions for you.

If your DMs aren’t working, check these two settings:

  • channels.discord.dm.enabled=false (this should be true).
  • channels.discord.dm.policy="disabled".

If you are using pairing mode, the bot will stay silent while it is awaiting pairing approval.

By default, the gateway ignores messages authored by other bots. If you set channels.discord.allowBots=true, I recommend using strict mention and allowlist rules. This prevents the bot from getting stuck in an infinite loop with another automated user.

When you are deep in the config file, these are the high-signal fields I look at first:

  • Startup and Auth: enabled, token, accounts.*, allowBots.
  • Policy: groupPolicy, dm.*, guilds.*, guilds.*.channels.*.
  • Commands: commands.native, commands.useAccessGroups, configWrites.
  • Delivery: textChunkLimit, chunkMode, maxLinesPerMessage.

For a full list, check the Configuration reference - Discord.

I always treat bot tokens as secrets. I prefer using DISCORD_BOT_TOKEN in supervised environments rather than hardcoding it. You should also grant the least-privilege Discord permissions necessary for your bot to function. If your command deployment or state seems stale, restart the gateway and re-check the status with openclaw channels status --probe.

If you are still stuck, try the AI Setup Assistant.

OpenClaw

OpenClaw Expert

Still stuck?

If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.