Claude
Skills
Sign in
Back

discord-bot-helper

Included with Lifetime
$97 forever

Discord.js v14 for building Discord bots - slash commands, events, components, embeds, and permissions When user works with Discord bots, discord.js, slash commands, Discord API, or mentions discord.js patterns

Backend & APIs

What this skill does


# Discord Bot Helper Agent

## What's New in Discord.js v14 (2024-2025)

- **Node.js 18.17+** required (v14.14+), 22+ recommended
- **PascalCase enums**: `ButtonStyle.Primary` instead of `'PRIMARY'`
- **Renamed builders**: `EmbedBuilder` (was `MessageEmbed`), `AttachmentBuilder` (was `MessageAttachment`)
- **Display components**: New layout and content elements beyond embeds
- **Gateway v10**: Updated event handling and intents

## Installation

```bash
# Install discord.js
npm install discord.js
# or
bun add discord.js
```

## Basic Bot Setup

### Main File (index.js)

```typescript
import { Client, Events, GatewayIntentBits } from "discord.js";

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

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

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand()) return;

  if (interaction.commandName === "ping") {
    await interaction.reply("Pong!");
  }
});

client.login(process.env.DISCORD_TOKEN);
```

## Gateway Intents

Intents control which events your bot receives:

### Common Intents

| Intent             | Events Received                                   |
| ------------------ | ------------------------------------------------- |
| `Guilds`           | Guild create/update/delete, channels, roles       |
| `GuildMembers`     | Member join/leave/update (privileged)             |
| `GuildMessages`    | Message events in guilds                          |
| `MessageContent`   | Message content, attachments, embeds (privileged) |
| `GuildVoiceStates` | Voice channel activity                            |
| `GuildPresences`   | Member presence updates (privileged)              |
| `DirectMessages`   | DM message events                                 |

### Privileged Intents

Require manual enabling in Discord Developer Portal:

- `GuildMembers`
- `GuildPresences`
- `MessageContent`

```typescript
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMembers, // Privileged
    GatewayIntentBits.GuildPresences, // Privileged
    GatewayIntentBits.MessageContent, // Privileged
  ],
});
```

## Slash Commands

### Command Definition

```typescript
// commands/ping.js
import { SlashCommandBuilder } from "discord.js";

export const data = new SlashCommandBuilder()
  .setName("ping")
  .setDescription("Replies with Pong!");

export async function execute(interaction) {
  await interaction.reply("Pong!");
}
```

### Command with Options

```typescript
import { SlashCommandBuilder } from "discord.js";

export const data = new SlashCommandBuilder()
  .setName("echo")
  .setDescription("Replies with your input")
  .addStringOption((option) =>
    option
      .setName("message")
      .setDescription("The message to echo")
      .setRequired(true),
  )
  .addUserOption((option) =>
    option.setName("target").setDescription("User to mention"),
  )
  .addIntegerOption((option) =>
    option
      .setName("count")
      .setDescription("Number of times")
      .setMinValue(1)
      .setMaxValue(10),
  );

export async function execute(interaction) {
  const message = interaction.options.getString("message");
  const target = interaction.options.getUser("target");
  const count = interaction.options.getInteger("count") ?? 1;

  const reply = target
    ? `${target}, ${message.repeat(count)}`
    : message.repeat(count);

  await interaction.reply(reply);
}
```

### Command with Choices

```typescript
export const data = new SlashCommandBuilder()
  .setName("gif")
  .setDescription("Sends a gif")
  .addStringOption((option) =>
    option
      .setName("category")
      .setDescription("The gif category")
      .setRequired(true)
      .addChoices(
        { name: "Funny", value: "gif_funny" },
        { name: "Meme", value: "gif_meme" },
        { name: "Cute", value: "gif_cute" },
      ),
  );
```

### Subcommands

```typescript
export const data = new SlashCommandBuilder()
  .setName("user")
  .setDescription("User commands")
  .addSubcommand((subcommand) =>
    subcommand
      .setName("info")
      .setDescription("Get user info")
      .addUserOption((option) =>
        option.setName("target").setDescription("The user"),
      ),
  )
  .addSubcommand((subcommand) =>
    subcommand
      .setName("avatar")
      .setDescription("Get user avatar")
      .addUserOption((option) =>
        option.setName("target").setDescription("The user"),
      ),
  );

export async function execute(interaction) {
  const subcommand = interaction.options.getSubcommand();
  const target = interaction.options.getUser("target") ?? interaction.user;

  if (subcommand === "info") {
    await interaction.reply(`User: ${target.tag}\nID: ${target.id}`);
  } else if (subcommand === "avatar") {
    await interaction.reply(target.displayAvatarURL({ size: 256 }));
  }
}
```

### Registering Commands

```typescript
// deploy-commands.js
import { REST, Routes } from "discord.js";
import { commands } from "./commands/index.js";

const rest = new REST().setToken(process.env.DISCORD_TOKEN);

// Guild commands (instant, for development)
await rest.put(Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID), {
  body: commands.map((c) => c.data.toJSON()),
});

// Global commands (takes up to 1 hour to propagate)
await rest.put(Routes.applicationCommands(CLIENT_ID), {
  body: commands.map((c) => c.data.toJSON()),
});
```

### Autocomplete

```typescript
export const data = new SlashCommandBuilder()
  .setName("search")
  .setDescription("Search something")
  .addStringOption((option) =>
    option
      .setName("query")
      .setDescription("Search query")
      .setAutocomplete(true),
  );

export async function autocomplete(interaction) {
  const focusedValue = interaction.options.getFocused();

  const choices = ["apple", "banana", "cherry", "date", "elderberry"];
  const filtered = choices.filter((c) => c.startsWith(focusedValue));

  await interaction.respond(
    filtered.slice(0, 25).map((choice) => ({ name: choice, value: choice })),
  );
}

export async function execute(interaction) {
  const query = interaction.options.getString("query");
  await interaction.reply(`You searched for: ${query}`);
}
```

## Response Methods

### Basic Responses

```typescript
// Simple reply
await interaction.reply("Hello!");

// Ephemeral reply (only visible to user)
await interaction.reply({ content: "Secret!", ephemeral: true });

// Deferred reply (for long operations)
await interaction.deferReply();
// ... do work ...
await interaction.editReply("Done!");

// Follow-up messages
await interaction.reply("First message");
await interaction.followUp("Second message");
await interaction.followUp({ content: "Ephemeral followup", ephemeral: true });
```

### Fetching the Reply

```typescript
const reply = await interaction.fetchReply();
console.log(reply.id);
```

## Embeds

### Creating Embeds

```typescript
import { EmbedBuilder } from "discord.js";

const embed = new EmbedBuilder()
  .setColor(0x0099ff)
  .setTitle("Embed Title")
  .setURL("https://discord.js.org/")
  .setAuthor({
    name: "Author Name",
    iconURL: "https://example.com/icon.png",
    url: "https://example.com",
  })
  .setDescription("This is the main description")
  .setThumbnail("https://example.com/thumbnail.png")
  .addFields(
    { name: "Field 1", value: "Value 1", inline: true },
    { name: "Field 2", value: "Value 2", inline: true },
    { name: "Field 3", value: "Value 3" },
  )
  .setImage("https://example.com/image.png")
  .setTimestamp()
  .setFooter({
    text: "Footer text",
    iconURL: "https://example.com/footer.png",
  });

await interaction.reply({ embeds: [embed] });
```

### Multiple Embeds

```typescript
const embed1 = new EmbedBuilder().setTitle("Embed 1").setColor(0xff0000);
const embed2 =

Related in Backend & APIs