Aller au contenu
Retour au blog
Tutoriel2 février 202618 min

How to Make a Discord Bot with AI (Claude/GPT)

Build an intelligent Discord bot powered by Claude or GPT-4. Step-by-step tutorial with full code examples, rate limiting, and deployment options.

discordbotclaudeopenaitutorial

Molted Team

molted.cloud

A Discord bot that actually understands context, answers questions intelligently, and maintains conversation history across messages. Not the keyword-matching bots of 2020, but a real AI that integrates with Claude or GPT-4. Building one from scratch teaches you API integration, rate limiting, and asynchronous programming. Or you can skip straight to using one.

What we are building

A Discord bot that:

  • Responds when mentioned or in DMs
  • Maintains conversation context within threads
  • Uses Claude or GPT-4 for responses
  • Handles rate limits gracefully
  • Can be deployed anywhere Node.js runs

The complete code is around 200 lines. Not a weekend project, but a solid afternoon.

Prerequisites

  • Node.js 18+ installed on your machine
  • A Discord account and a server where you have admin rights
  • An Anthropic or OpenAI API key (or your existing subscription—more on this below)
  • Basic JavaScript/TypeScript knowledge

About that API key: You don't necessarily need a pay-as-you-go API key. If you already have a Claude Pro, ChatGPT Plus, or similar subscription, you can often use that instead. Tools like OpenClaw support subscription-based authentication, so you're not stuck paying $100+/month in API fees on top of your existing $20 subscription. Those Reddit horror stories about "$700/month API bills"? Completely avoidable.

Creating a Discord application

Go to the Discord Developer Portal and click "New Application". Name it whatever you want.

Get your bot token

In your application, go to Bot → Reset Token. Copy this token and save it securely. This is your bot's password; never commit it to git or share it publicly.

Set permissions

Under Bot → Privileged Gateway Intents, enable:

  • Message Content Intent (required to read message text)
  • Server Members Intent (optional, for member-related features)

Generate invite link

Go to OAuth2 → URL Generator. Select:

  • Scopes: bot, applications.commands
  • Bot Permissions: Send Messages, Read Message History, View Channels

Copy the generated URL and open it in your browser to add the bot to your server.

Project setup

mkdir discord-ai-bot
cd discord-ai-bot
npm init -y
npm install discord.js @anthropic-ai/sdk dotenv

Create a .env file:

DISCORD_TOKEN=your-bot-token
ANTHROPIC_API_KEY=your-anthropic-key

Create .gitignore:

.env
node_modules/

Basic bot structure

Create index.js:

require('dotenv').config();
const { Client, GatewayIntentBits, Partials } = require('discord.js');
const Anthropic = require('@anthropic-ai/sdk');

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

const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

// Store conversation history per channel
const conversations = new Map();

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

client.on('messageCreate', async (message) => {
  // Ignore bot messages
  if (message.author.bot) return;

  // Check if bot was mentioned or is a DM
  const isMentioned = message.mentions.has(client.user);
  const isDM = !message.guild;

  if (!isMentioned && !isDM) return;

  // Remove the mention from the message
  const content = message.content
    .replace(/<@!?\d+>/g, '')
    .trim();

  if (!content) return;

  // Get or create conversation history
  const channelId = message.channel.id;
  if (!conversations.has(channelId)) {
    conversations.set(channelId, []);
  }
  const history = conversations.get(channelId);

  // Add user message to history
  history.push({ role: 'user', content });

  // Keep only last 10 messages for context
  if (history.length > 20) {
    history.splice(0, history.length - 20);
  }

  try {
    // Show typing indicator
    await message.channel.sendTyping();

    // Call Claude
    const response = await anthropic.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      system: 'You are a helpful assistant in a Discord server. Keep responses concise and friendly.',
      messages: history,
    });

    const reply = response.content[0].text;

    // Add assistant response to history
    history.push({ role: 'assistant', content: reply });

    // Send response (split if too long)
    if (reply.length > 2000) {
      const chunks = reply.match(/.{1,2000}/g);
      for (const chunk of chunks) {
        await message.reply(chunk);
      }
    } else {
      await message.reply(reply);
    }
  } catch (error) {
    console.error('Error:', error);
    await message.reply('Sorry, I encountered an error. Please try again.');
  }
});

client.login(process.env.DISCORD_TOKEN);

Run it:

node index.js

Mention your bot in Discord and it should respond.

Skip the coding?

OpenClaw includes Discord integration out of the box. Zero code needed.

Start 7-day trial

Using OpenAI instead

If you prefer GPT-4, install the OpenAI SDK:

npm install openai

Replace the Anthropic setup:

const OpenAI = require('openai');

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

// In the message handler, replace the Claude call:
const response = await openai.chat.completions.create({
  model: 'gpt-4o',
  max_tokens: 1024,
  messages: [
    { role: 'system', content: 'You are a helpful assistant in a Discord server.' },
    ...history,
  ],
});

const reply = response.choices[0].message.content;

Conversation context management

The basic implementation stores all history in memory. For production:

// Better context management with expiry
const conversations = new Map();
const CONTEXT_EXPIRY = 30 * 60 * 1000; // 30 minutes
const MAX_CONTEXT_LENGTH = 20;

function getConversation(channelId) {
  const now = Date.now();

  if (!conversations.has(channelId)) {
    conversations.set(channelId, { messages: [], lastActivity: now });
  }

  const conv = conversations.get(channelId);

  // Reset if stale
  if (now - conv.lastActivity > CONTEXT_EXPIRY) {
    conv.messages = [];
  }

  conv.lastActivity = now;
  return conv.messages;
}

function addMessage(channelId, role, content) {
  const messages = getConversation(channelId);
  messages.push({ role, content });

  // Trim to max length
  while (messages.length > MAX_CONTEXT_LENGTH) {
    messages.shift();
  }
}

// Clean up old conversations periodically
setInterval(() => {
  const now = Date.now();
  for (const [id, conv] of conversations) {
    if (now - conv.lastActivity > CONTEXT_EXPIRY) {
      conversations.delete(id);
    }
  }
}, 60000);

Rate limiting

Both Discord and AI APIs have rate limits. Handle them gracefully:

const rateLimit = new Map();
const RATE_LIMIT_WINDOW = 60000; // 1 minute
const MAX_REQUESTS_PER_WINDOW = 10;

function isRateLimited(userId) {
  const now = Date.now();
  const userLimits = rateLimit.get(userId) || { count: 0, windowStart: now };

  // Reset window if expired
  if (now - userLimits.windowStart > RATE_LIMIT_WINDOW) {
    userLimits.count = 0;
    userLimits.windowStart = now;
  }

  if (userLimits.count >= MAX_REQUESTS_PER_WINDOW) {
    return true;
  }

  userLimits.count++;
  rateLimit.set(userId, userLimits);
  return false;
}

// In message handler:
if (isRateLimited(message.author.id)) {
  await message.reply('You are sending messages too quickly. Please wait a moment.');
  return;
}

Error handling

Production bots need robust error handling:

async function callAI(messages, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await anthropic.messages.create({
        model: 'claude-sonnet-4-20250514',
        max_tokens: 1024,
        messages,
      });
      return response.content[0].text;
    } catch (error) {
      if (error.status === 429) {
        // Rate limited, wait and retry
        await new Promise(r => setTimeout(r, 1000 * (i + 1)));
        continue;
      }
      if (error.status >= 500) {
        // Server error, retry
        await new Promise(r => setTimeout(r, 1000 * (i + 1)));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

Let us handle the bot

Molted deploys OpenClaw with Discord ready. 7-day free trial.

Start 7-day trial

Deployment options

VPS (DigitalOcean, Hetzner)

Cheapest long-term. Run with PM2 for process management:

npm install -g pm2
pm2 start index.js --name discord-bot
pm2 startup
pm2 save

Railway

Connect your GitHub repo, set environment variables, deploy. Pricing based on usage, typically $5-10/month for a bot.

Fly.io

Similar to Railway, good free tier for small bots.

Home server

If you have a machine that is always on, run it there. Same PM2 setup as VPS.

The simpler path

Building a Discord bot from scratch teaches valuable skills: API integration, async programming, error handling, deployment. It is worth doing once for the learning experience.

But if you want a working AI bot without the coding and maintenance, pre-built solutions exist. OpenClaw, for example, includes Discord integration that connects in minutes. You configure a bot token, enable the channel, and you have AI responses without writing code.

The tradeoff is customization versus convenience. A custom bot does exactly what you program. OpenClaw does what OpenClaw does, but it does it reliably without you managing servers or debugging at 2 AM.

For teams, the calculation usually favors managed solutions. Developer time spent maintaining a Discord bot is developer time not spent on your actual product. For personal projects and learning, building your own is rewarding.

Related guides

Free 7-day trial

Discord AI bot in 60 seconds

OpenClaw on Molted includes full Discord integration. No coding, no hosting headaches.

7-day free trial · card on file · cancel anytime

Articles liés.

Votre Molted pourrait déjà être au travail.

Trois clics, quinze secondes, et les vingt-quatre premières heures sont pour nous.

Dès 14 $/mois · en ligne en 3 clics · les 7 premiers jours offerts