Discord is where communities live. Gaming guilds, developer hangouts, study groups, NFT projects. If your community is on Discord, your AI agent should be too.
Unlike Telegram (simple bot setup) or WhatsApp (complicated approval process), Discord sits in the middle: powerful bot features but requires understanding permissions and intents. This guide walks you through creating a Discord bot from scratch, connecting it to OpenClaw, and avoiding the #1 mistake that breaks 80% of new bots — forgetting to enable gateway intents.
Why Discord Bots Are Different
Discord’s approach: bots are first-class citizens. Discord wants bots — excellent docs, generous rate limits, rich features. The catch is complexity. Every Discord bot needs:
- ●Application — registered in Discord Developer Portal
- ●Bot user — the actual bot account
- ●OAuth2 scopes — what the bot can access
- ●Permissions — what the bot can do
- ●Gateway intents — which events the bot receives
Miss one and the bot either doesn’t work or has bizarre partial functionality. Let’s set it up correctly from the start.
Step 1: Create Discord Application
Go to discord.com/developers/applications and log in. Click New Application, name it “OpenClaw Bot”, accept the ToS, and click Create. You now have a Discord Application — the container for your bot. Copy the Application ID from the General Information tab; you’ll need it later.
Step 2: Create Bot User & Token
- 1.Click Bot in the left sidebar
- 2.Click Add Bot, then confirm
- 3.Under Token, click Reset Token, then Copy immediately
- 4.Save it somewhere secure — you can’t view it again, only reset
Bot Settings
- ●Public Bot — uncheck unless you want anyone to add it
- ●Require OAuth2 Code Grant — leave unchecked
Step 2.5: Privileged Gateway Intents (CRITICAL)
This is where 80% of new bot devs fail. Still in the Bot tab, scroll to Privileged Gateway Intents and enable:
- ●Presence Intent — see when users go online/offline
- ●Server Members Intent — see member join/leave events
- ●Message Content Intent — read message content
Without Message Content Intent, your bot can see that messages exist but can’t read what they say. It’s like having eyes but no brain. Discord made this privileged for privacy reasons, but OpenClaw needs it. Click Save Changes at the bottom.
Step 3: OAuth2 Scopes & Permissions
Click OAuth2 → URL Generator. Under SCOPES, check:
- ●bot — your application has a bot user
- ●applications.commands — bot can create slash commands
Minimal Bot Permissions
- ●Read Messages / View Channels
- ●Send Messages
- ●Embed Links
- ●Attach Files
- ●Read Message History
- ●Add Reactions
Additional Permissions for Moderation
- ●Manage Messages — delete spam
- ●Kick Members
- ●Ban Members
- ●Manage Roles
At the bottom, copy the generated invite URL. It looks like:
https://discord.com/api/oauth2/authorize?client_id=APP_ID&permissions=274878024768&scope=bot%20applications.commands
Step 4: Add Bot to Your Server
- 1.Paste the OAuth2 URL into your browser
- 2.Select which server (you need Manage Server permission)
- 3.Review permissions, click Authorize, complete CAPTCHA
The bot appears in your member list with a “BOT” tag (offline until you start the code).
Step 5: Configure OpenClaw for Discord
In your .env file:
DISCORD_ENABLED=true DISCORD_BOT_TOKEN=your-bot-token-here DISCORD_APPLICATION_ID=123456789012345678
Create the Discord Adapter
// adapters/discord.js
const { Client, GatewayIntentBits, Partials } = require('discord.js');
class DiscordAdapter {
constructor(config) { this.config = config; this.client = null; }
async initialize() {
this.client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMembers,
],
partials: [Partials.Channel, Partials.Message],
});
this.client.on('ready', () => {
console.log(`[Discord] Logged in as ${this.client.user.tag}`);
});
this.client.on('messageCreate', async (msg) => await this.handleMessage(msg));
this.client.on('interactionCreate', async (i) => await this.handleInteraction(i));
await this.client.login(this.config.token);
}
async handleMessage(message) {
if (message.author.bot) return;
const isMentioned = message.mentions.has(this.client.user);
const isDM = message.channel.type === 'DM';
if (!isMentioned && !isDM) return;
const text = message.content.replace(`<@${this.client.user.id}>`, '').trim();
const response = await this.processWithOpenClaw(message.author.id, text);
await message.reply(response);
}
async handleInteraction(interaction) {
if (!interaction.isChatInputCommand()) return;
await interaction.deferReply();
const response = await this.processSlashCommand(interaction);
await interaction.editReply(response);
}
}
module.exports = DiscordAdapter;Install discord.js: npm install discord.js. Then enable the channel in config/channels.yml:
channels:
discord:
enabled: true
adapter: adapters/discord.js
token: ${DISCORD_BOT_TOKEN}
application_id: ${DISCORD_APPLICATION_ID}
respond_to_mentions: true
respond_to_dms: true
rate_limit:
messages_per_second: 1Step 6: Test Your Bot
Run npm start. You should see [Discord] Logged in as OpenClaw Bot#1234 and the bot will switch to Online (green) in your server. Mention it in any channel — @OpenClaw Bot what's 2+2? — or send a DM. If it doesn’t reply, check that the bot is online, that OpenClaw logs show the message arriving, and that Message Content Intent is enabled.
Step 7: Register Slash Commands
Slash commands are Discord’s modern command interface — they appear when users type /. Create scripts/register-discord-commands.js:
const { REST, Routes } = require('discord.js');
require('dotenv').config();
const commands = [
{
name: 'ask',
description: 'Ask OpenClaw a question',
options: [{ name: 'question', description: 'Your question', type: 3, required: true }],
},
{ name: 'help', description: 'Show available commands' },
{ name: 'skills', description: 'List available skills' },
];
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_BOT_TOKEN);
(async () => {
await rest.put(
Routes.applicationCommands(process.env.DISCORD_APPLICATION_ID),
{ body: commands }
);
console.log('Successfully registered slash commands!');
})();Run node scripts/register-discord-commands.js. Global commands take up to 1 hour to appear; for instant testing, register against a single guild using Routes.applicationGuildCommands(APP_ID, GUILD_ID) instead.
Gateway Intents: What They Actually Mean
- ●Guilds (always on) — required for the bot to work at all
- ●Guild Members (privileged) — see members join/leave; required for welcome messages and role assignment
- ●Guild Messages — know that messages were sent (but not their content)
- ●Message Content (privileged) — actually read message text; the one most people forget
- ●Guild Presences (privileged) — see online/offline/idle status
Permissions vs Intents (Common Confusion)
Permissions: what the bot can do in a server (send messages, ban members). Intents: what events the bot receives from Discord (messages, joins). A moderation bot needs the “Ban Members” permission AND the “Guild Members” intent. Missing either and the bot won’t work as expected.
Common Discord Bot Issues (And Fixes)
Bot doesn’t respond to messages
- ●Cause 1: Message Content Intent disabled — re-enable in Developer Portal → Bot
- ●Cause 2: Bot wasn’t mentioned and isn’t in a DM — adjust the trigger logic
Slash commands don’t appear
Re-run the registration script. Wait up to 1 hour for global commands, or use guild-scoped commands for instant updates.
Bot goes offline randomly
client.on('error', err => console.error('[Discord] Client error:', err));
process.on('unhandledRejection', err => console.error('[Discord] Unhandled:', err));
// Auto-restart with PM2
pm2 start npm --name "openclaw" -- startRate limit errors
Discord allows ~5 requests per 5 seconds per channel. Add a per-channel rate limiter and queue bursts.
Community Moderation Starter Persona
OpenClaw can act as a community moderator. A starter config/discord-moderation.yml:
moderation:
enabled: true
rules:
spam_detection:
enabled: true
max_messages_per_minute: 10
action: timeout
duration: 300
forbidden_words:
enabled: true
words: [word1, word2]
action: delete_and_warn
excessive_caps:
enabled: true
threshold: 0.7
action: warn
link_spam:
enabled: true
max_links_per_message: 3
action: delete_and_timeout
warnings:
strike_limit: 3
actions: { 1: warn_dm, 2: timeout_30min, 3: kick, 4: ban }
exempt_roles: [Moderator, Admin]
log_channel: mod-logsPair it with a moderator persona (firm but fair, transparent, never power-trippy) and OpenClaw will auto-delete spam, warn users, escalate to timeout/kick/ban, welcome new members, and log every action to a mod-logs channel.
Advanced Features
Embeds (Rich Messages)
const { EmbedBuilder } = require('discord.js');
const embed = new EmbedBuilder()
.setColor('#FF8C2A')
.setTitle('OpenClaw Response')
.setDescription("Here's what I found:")
.addFields(
{ name: 'Item 1', value: 'Description' },
{ name: 'Item 2', value: 'Description' },
)
.setTimestamp();
await message.reply({ embeds: });Buttons (Interactive UI)
const { ButtonBuilder, ActionRowBuilder, ButtonStyle } = require('discord.js');
const button = new ButtonBuilder()
.setCustomId('confirm')
.setLabel('Confirm')
.setStyle(ButtonStyle.Primary);
const row = new ActionRowBuilder().addComponents(button);
await message.reply({ content: 'Confirm this action?', components: [row] });Voice Channel Integration
Install @discordjs/voice for voice command bots, music bots, or audio announcements.
The PaioClaw Alternative
Self-hosted Discord setup runs ~30-45 minutes if everything goes smoothly, with ongoing maintenance for discord.js updates, command re-registration, rate limit tuning, and moderation rules. PaioClaw’s Discord integration is a 2-minute path: paste your bot token, pick a permissions template (basic or moderation), deploy. Pre-configured intents, slash commands auto-registered, moderation templates, multi-server support. Starts free, $4/month for paid plans.
DIY when: you need custom Discord-specific features, you’re building a Discord-focused product, or learning the API is the goal. Use PaioClaw when: you want Discord plus other channels (Slack, Telegram, WhatsApp), you don’t want to debug intents, or you need moderation features that just work.
The Bottom Line
Discord bot setup is more complex than Telegram but more structured than WhatsApp. The Developer Portal has a lot of options, but they’re all documented and logical. The critical thing: enable Message Content Intent. 80% of “my bot doesn’t work” issues trace back to this single checkbox.
Whether you self-host or use PaioClaw depends on whether you want to become a Discord API expert or just want your agent on Discord.

