OpenClaw Discord Integration: Setting Up a Server Bot That Actually Helps

If you’re trying to integrate OpenClaw with Discord to automate tasks or provide AI assistance, and you’ve found that generic “Discord bot” tutorials don’t quite cut it, you’re not alone. The challenge with OpenClaw isn’t just sending messages; it’s about context, managing rate limits, and ensuring your bot doesn’t become a spam factory. We’re going to set up a server bot that uses OpenClaw to answer specific questions, summarize channel activity, or even generate creative content on demand, all while being mindful of resource usage and API costs.

Prerequisites and Initial Setup

Before we dive into the Discord-specific bits, ensure you have a working OpenClaw instance. For this setup, I’m assuming you’re running OpenClaw on a Linux server, perhaps a DigitalOcean Droplet or an AWS EC2 instance. You’ll need Node.js (v18 or higher) and npm installed. Our bot will be written in JavaScript, primarily because the Discord.js library is robust and well-maintained. Make sure your OpenClaw API key is configured correctly in ~/.openclaw/config.json under the "api_key" field, and that OpenClaw itself is accessible, ideally running as a service or via pm2.


# Check Node.js version
node -v

# If not installed, or old, install nvm and then Node.js
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install 18
nvm use 18

# Verify OpenClaw API key
cat ~/.openclaw/config.json
# Ensure it contains: "api_key": "oc_your_api_key_here"

# Install pm2 if you haven't already
npm install -g pm2

For the Discord bot, create a new directory, navigate into it, and initialize a new Node.js project:


mkdir openclaw-discord-bot
cd openclaw-discord-bot
npm init -y
npm install discord.js openclaw-sdk dotenv

The openclaw-sdk is crucial here, as it provides a convenient interface to your OpenClaw instance. dotenv will help us manage sensitive environment variables like your Discord bot token.

Discord Bot Creation and Permissions

Go to the Discord Developer Portal. Click “New Application,” give it a name (e.g., “ClawAssistant”), and click “Create.” Navigate to the “Bot” tab on the left, then click “Add Bot.” Copy your bot’s token – keep this secret! We’ll store it in a .env file. Under “Privileged Gateway Intents,” enable “MESSAGE CONTENT INTENT.” This is critical; without it, your bot won’t be able to read message content, effectively rendering it useless for our purposes. Make sure to save changes.

Now, generate an invite link for your bot. Go to “OAuth2” > “URL Generator.” Select “bot” under “SCOPES.” Under “BOT PERMISSIONS,” select “Read Message History” and “Send Messages.” You might also want “Manage Messages” if you plan to have the bot delete its own responses or user prompts. Copy the generated URL and paste it into your browser to invite the bot to your Discord server.

Building the Bot’s Logic

Create a .env file in your openclaw-discord-bot directory:


DISCORD_TOKEN=YOUR_BOT_TOKEN_HERE
OPENCLAW_API_BASE_URL=http://localhost:8000 # Or wherever your OpenClaw instance is
OPENCLAW_API_KEY=oc_your_api_key_here # Only if not in ~/.openclaw/config.json

Next, create an index.js file:


require('dotenv').config();
const { Client, GatewayIntentBits } = require('discord.js');
const { OpenClaw } = require('openclaw-sdk');

const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent
    ]
});

const openclaw = new OpenClaw({
    baseURL: process.env.OPENCLAW_API_BASE_URL,
    apiKey: process.env.OPENCLAW_API_KEY
});

const PREFIX = '!claw'; // Our command prefix

client.once('ready', () => {
    console.log(`Logged in as ${client.user.tag}!`);
});

client.on('messageCreate', async message => {
    if (message.author.bot) return; // Ignore messages from other bots
    if (!message.content.startsWith(PREFIX)) return; // Only respond to our prefix

    const args = message.content.slice(PREFIX.length).trim().split(/ +/);
    const command = args.shift().toLowerCase();
    const prompt = args.join(' ');

    if (command === 'ask') {
        if (!prompt) {
            return message.reply('Please provide a prompt after !claw ask.');
        }

        try {
            await message.channel.send('Thinking...'); // Acknowledge the request

            const response = await openclaw.completion.create({
                model: "claude-haiku-4-5", // Non-obvious insight: haiku is usually enough and much cheaper
                prompt: prompt,
                maxTokens: 500,
                temperature: 0.7
            });

            // Split long responses to avoid Discord's 2000 character limit
            const fullResponse = response.choices[0].message.content;
            if (fullResponse.length > 2000) {
                const chunks = fullResponse.match(/[\s\S]{1,1900}/g) || [];
                for (const chunk of chunks) {
                    await message.channel.send(chunk);
                }
            } else {
                await message.channel.send(fullResponse);
            }

        } catch (error) {
            console.error('Error calling OpenClaw:', error);
            message.reply('Sorry, I encountered an error. Please try again later.');
        }
    } else if (command === 'summarize') {
        if (!message.reference) {
            return message.reply('Please reply to a message or provide a message link to summarize.');
        }
        let targetMessage;
        try {
            targetMessage = await message.channel.messages.fetch(message.reference.messageId);
        } catch (error) {
            return message.reply('Could not find the message to summarize. Is it in this channel?');
        }

        const summaryPrompt = `Summarize the following Discord message concisely:\n\n"${targetMessage.content}"`;

        try {
            await message.channel.send('Summarizing...');
            const summaryResponse = await openclaw.completion.create({
                model: "claude-haiku-4-5",
                prompt: summaryPrompt,
                maxTokens: 200,
                temperature: 0.5
            });
            await message.reply(`Summary: ${summaryResponse.choices[0].message.content}`);
        } catch (error) {
            console.error('Error summarizing with OpenClaw:', error);
            message.reply('Failed to summarize the message.');
        }
    }
});

client.login(process.env.DISCORD_TOKEN);

A non-obvious insight here: while the OpenClaw documentation might suggest using the default model (often a more powerful, expensive one), for most Discord interactions like answering questions or summarizing, claude-haiku-4-5 is incredibly capable. It’s also significantly cheaper (often 10x or more per token) and faster, which is crucial for a responsive bot. Unless you’re doing complex code generation or in-depth analysis, Haiku is your friend for cost-effectiveness.

Running and Managing the Bot

To start your bot, simply run node index.js. However, for a production environment, you should use pm2 to keep it running reliably and automatically restart it if it crashes:


pm2 start index.js --name openclaw-discord-bot
pm2 save

You can check its status with pm2 status and view logs with pm2 logs openclaw-discord-bot. This ensures your bot is resilient and doesn’t go offline just because of an unhandled error or server restart.

🤖 Get the OpenClaw Automation Starter Kit ($29) →
Instant download — no subscription needed

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *