Back to Blog
Channel Tutorials35 min readBeginner

Discord Bot Tutorial

Launch a Discord bot with OpenClaw, including app registration, intents, slash commands, and server automation basics.

Published March 18, 2026Updated March 23, 2026
Discord bot tutorialOpenClaw DiscordDiscord automation

Complete Discord Bot Automation Guide

Target keywords: Discord bot tutorial, OpenClaw Discord, Discord automation, AI Discord bot


Introduction

Discord is a leading platform for community management and gaming communities. This tutorial shows you how to build an intelligent Discord bot with OpenClaw for community automation, gaming assistance, and AI support.

What you will learn:

  • Discord bot creation and configuration
  • OpenClaw integration
  • Command and event handling
  • Advanced features (embeds, buttons, and modals)

Estimated time: 35 minutes
Difficulty: Beginner


Prerequisites

What You Need

  1. A Discord account
  2. A Discord Application (created in the Discord Developer Portal)
  3. Server administrator permissions (for testing)
  4. OpenClaw installed

Step 1: Create a Discord Application

1.1 Open the Developer Portal

  1. Visit discord.com/developers/applications
  2. Log in to your Discord account
  3. Click "New Application"
  4. Enter an app name, such as "MyAIBot"

1.2 Get the Bot Token

  1. Click "Bot" in the left menu
  2. Click "Add Bot" → "Yes, do it!"
  3. Click "Reset Token"
  4. Copy and save the token (it is shown only once)
Token: MTAxMjM0NTY3ODkwMTIzNDU2Nw.GabcdE.abcdefghijklmnopqrstuvwxyz

1.3 Configure Bot Permissions

On the "Bot" page:

Privileged Gateway Intents:

  • ✅ SERVER MEMBERS INTENT
  • ✅ MESSAGE CONTENT INTENT
  • ✅ PRESENCE INTENT

Authorization Flow:

  • Turn off "Public Bot" if you need private deployment
  • Turn on "Requires OAuth2 Code Grant" if needed

Step 2: Invite the Bot to Your Server

2.1 Generate an Invite Link

  1. Click "OAuth2" → "URL Generator" on the left

  2. Select Scopes:

    • bot
    • applications.commands
  3. Select Bot Permissions:

    • ✅ Send Messages
    • ✅ Read Message History
    • ✅ Embed Links
    • ✅ Attach Files
    • ✅ Add Reactions
    • ✅ Use Slash Commands
    • ✅ Manage Messages (optional, for cleanup)
    • ✅ Manage Channels (optional)
  4. Copy the generated URL

2.2 Invite the Bot

  1. Open the generated URL in your browser
  2. Select your server
  3. Click "Authorize"
  4. Complete the CAPTCHA

The bot should now appear in your server member list.


Step 3: Configure OpenClaw

3.1 Install the Discord Skill

openclaw skill install discord

3.2 Configure the Connection

Edit the configuration file:

openclaw config edit

Add:

skills:
  discord:
    enabled: true
    bot_token: "${DISCORD_BOT_TOKEN}"
    
    # Application commands (slash commands)
    application_id: "1234567890123456789"
    
    # Permission configuration
    intents:
      - guilds
      - guild_messages
      - message_content
      - guild_members
      
    # Command prefix (optional, besides slash commands)
    prefix: "!"

3.3 Set Environment Variables

export DISCORD_BOT_TOKEN="MTAxMjM0NTY3ODkwMTIzNDU2Nw.GabcdE.abcdefghijklmnopqrstuvwxyz"
export DISCORD_APPLICATION_ID="1234567890123456789"

Step 4: Create an AI Agent

4.1 Basic Agent

openclaw agent create discord-assistant

Configuration:

agent:
  name: "Discord AI Assistant"
  description: "AI assistant for Discord communities"
  
  model:
    provider: openai
    model: gpt-4o-mini
    api_key: "${OPENAI_API_KEY}"
    
  system_prompt: |
    You are a helpful Discord community assistant.
    
    Guidelines:
    - Keep responses under 2000 characters (Discord limit)
    - Use Discord Markdown formatting
    - Be friendly and engaging
    - Use emojis appropriately
    - For code, use code blocks with language
    
    Community rules:
    - Be respectful
    - No spam
    - Help others learn
    
  memory:
    enabled: true
    max_messages: 10
    per_channel: true  # Separate memory for each channel

4.2 Connect Discord

routes:
  discord:
    # Regular messages
    - pattern: "*"
      agent: discord-assistant
      
    # Reply only when mentioned (recommended)
    - pattern: "*"
      agent: discord-assistant
      condition: "message.mentions_bot"
      
    # Dedicated to a specific channel
    - channel_id: "1234567890123456789"
      agent: discord-assistant

Step 5: Slash Commands

5.1 Register Commands

skills:
  discord:
    slash_commands:
      - name: "ask"
        description: "Ask the AI assistant"
        options:
          - name: "question"
            description: "Your question"
            type: string
            required: true
            
      - name: "summarize"
        description: "Summarize recent messages"
        options:
          - name: "count"
            description: "Number of messages to summarize"
            type: integer
            required: false
            
      - name: "help"
        description: "Show available commands"

5.2 Command Handler

# ~/.openclaw/skills/discord_commands.py
from openclaw import discord

@discord.slash_command("ask")
def ask_command(interaction, question: str):
    """Handle /ask command"""
    # Show "thinking"
    interaction.response.defer()
    
    # Get the AI response
    response = ai_chat(question)
    
    # Send the reply
    interaction.followup.send(f"**Q:** {question}\n\n**A:** {response}")

@discord.slash_command("summarize")
def summarize_command(interaction, count: int = 10):
    """Summarize recent messages"""
    # Get channel history
    messages = discord.get_channel_history(interaction.channel_id, limit=count)
    
    # Generate the summary
    summary = ai_summarize(messages)
    
    interaction.response.send_message(
        f"📋 Summary of last {count} messages:\n\n{summary}",
        ephemeral=True  # Visible only to the sender
    )

Step 6: Advanced Features

6.1 Embed Messages

import discord
from discord import Embed, Color

@discord.command("status")
def status_command(interaction):
    """Show bot status"""
    
    embed = Embed(
        title="🤖 Bot Status",
        description="Current system status",
        color=Color.green()
    )
    
    embed.add_field(
        name="Uptime",
        value="3 days, 2 hours",
        inline=True
    )
    
    embed.add_field(
        name="Messages Processed",
        value="1,234",
        inline=True
    )
    
    embed.add_field(
        name="Active Users",
        value="56",
        inline=True
    )
    
    embed.set_footer(text="HowToClaw Discord Bot")
    embed.timestamp = datetime.now()
    
    interaction.response.send_message(embed=embed)

6.2 Buttons and Interactions

from discord import Button, ButtonStyle, View

@discord.command("poll")
def poll_command(interaction, question: str):
    """Create a poll"""
    
    # Create buttons
    yes_button = Button(
        label="Yes",
        style=ButtonStyle.green,
        custom_id="poll_yes"
    )
    
    no_button = Button(
        label="No",
        style=ButtonStyle.red,
        custom_id="poll_no"
    )
    
    view = View()
    view.add_item(yes_button)
    view.add_item(no_button)
    
    interaction.response.send_message(
        f"📊 **Poll:** {question}",
        view=view
    )

@discord.button_handler("poll_yes")
def handle_yes(interaction):
    # Record the vote
    record_vote(interaction.user.id, "yes")
    interaction.response.send_message(
        "✅ You voted Yes!",
        ephemeral=True
    )

6.3 Modals

from discord import Modal, TextInput

@discord.command("feedback")
def feedback_command(interaction):
    """Open feedback form"""
    
    modal = Modal(title="Feedback")
    
    modal.add_item(
        TextInput(
            label="What do you like?",
            style=TextInputStyle.paragraph,
            required=False
        )
    )
    
    modal.add_item(
        TextInput(
            label="What can we improve?",
            style=TextInputStyle.paragraph,
            required=True
        )
    )
    
    interaction.response.send_modal(modal)

@discord.modal_submit("feedback")
def handle_feedback(interaction, responses):
    # Save the feedback
    save_feedback(interaction.user.id, responses)
    
    interaction.response.send_message(
        "Thank you for your feedback! 🙏",
        ephemeral=True
    )

Step 7: Community Management Features

7.1 Automatic Welcome

skills:
  discord:
    welcome:
      enabled: true
      channel: "welcome"  # Channel name or ID
      message: |
        Welcome {user.mention} to {guild.name}!
        
        I'm the AI assistant. Here are some things I can do:
        • Answer questions with `/ask`
        • Summarize discussions with `/summarize`
        • Help with coding and tech questions
        
        Just mention me (@BotName) or use slash commands!
      
      # Send a welcome DM
      dm: true
      dm_message: "Welcome! Check out #welcome for server info."

7.2 Automatic Moderation

skills:
  discord:
    moderation:
      enabled: true
      
      # Automatically delete spam
      auto_moderation:
        enabled: true
        rules:
          - pattern: "(discord\.gg|discord\.com/invite)"
            action: delete
            reason: "Unauthorized invite link"
            
          - pattern: "(http|https)://.*\.(exe|zip|rar)"
            action: delete
            reason: "Potentially malicious file"
            
          - pattern: "@everyone|@here"
            action: warn
            reason: "Mass mention"
            
      # Repeated message detection
      spam_detection:
        enabled: true
        max_repeats: 3
        time_window: 60  # Seconds
        action: mute
        duration: 10m

7.3 Role Management

@discord.command("role")
def role_command(interaction, role: str):
    """Self-assign roles"""
    
    available_roles = {
        "developer": "1234567890123456789",
        "designer": "1234567890123456790",
        "gamer": "1234567890123456791"
    }
    
    if role.lower() not in available_roles:
        interaction.response.send_message(
            f"Available roles: {', '.join(available_roles.keys())}",
            ephemeral=True
        )
        return
    
    role_id = available_roles[role.lower()]
    
    # Add the role
    discord.add_role(interaction.user.id, role_id)
    
    interaction.response.send_message(
        f"✅ Role '{role}' assigned!",
        ephemeral=True
    )

Step 8: Production Deployment

8.1 Environment Configuration

# Production environment variables
export DISCORD_BOT_TOKEN="your-production-token"
export DISCORD_APPLICATION_ID="your-app-id"
export OPENAI_API_KEY="your-openai-key"
export LOG_LEVEL="info"

8.2 System Service

[Unit]
Description=OpenClaw Discord Bot
After=network.target

[Service]
Type=simple
User=discord-bot
WorkingDirectory=/opt/discord-bot
Environment=DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN}
Environment=OPENAI_API_KEY=${OPENAI_API_KEY}
ExecStart=/usr/local/bin/openclaw start
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

8.3 Docker Deployment

version: '3.8'

services:
  discord-bot:
    image: openclaw/openclaw:latest
    environment:
      - DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    volumes:
      - ./config:/root/.openclaw
      - ./logs:/var/log/openclaw
    restart: unless-stopped

Troubleshooting

Issue 1: Bot does not respond to commands

Check:

# 1. Confirm the token is correct
echo $DISCORD_BOT_TOKEN

# 2. Check logs
openclaw logs | grep discord

# 3. Confirm Intents are enabled
# Discord Developer Portal > Bot > Privileged Gateway Intents

Issue 2: Slash commands do not appear

Fix:

# 1. Re-register commands
openclaw discord sync-commands

# 2. Wait (up to 1 hour)
# Discord caches commands

# 3. Check permissions
# Make sure the bot has the `applications.commands` permission

Issue 3: Cannot read message content

Cause: MESSAGE CONTENT INTENT is not enabled

Fix:

  1. Discord Developer Portal > Bot
  2. Enable "MESSAGE CONTENT INTENT"
  3. Save changes
  4. Restart the bot

Best Practices

1. Error Handling

@discord.error_handler
def handle_error(interaction, error):
    """Handle errors gracefully"""
    
    if isinstance(error, discord.CommandNotFound):
        return
    
    logger.error(f"Error in {interaction}: {error}")
    
    interaction.response.send_message(
        "😅 Something went wrong. Please try again.",
        ephemeral=True
    )

2. Rate Limiting

skills:
  discord:
    rate_limit:
      enabled: true
      per_user: 30  # 30 messages per minute
      per_guild: 100  # 100 messages per minute

3. Logging

logging:
  discord:
    level: info
    log_commands: true
    log_errors: true

Next Steps


Get more tutorials for free:

[Email subscription form]


Last updated: March 2026