DEV Community

Cover image for Build a Discord Bot That Checks Messages for AI-Generated Text (discord.js v14)
ProofAI | AI Content Detector
ProofAI | AI Content Detector

Posted on AI-assisted

Build a Discord Bot That Checks Messages for AI-Generated Text (discord.js v14)

Community managers are seeing more AI-generated posts: bot-like "introductions", copy-pasted answers in help channels, and contest entries that read suspiciously polished.

In this tutorial we'll build a small Discord bot with discord.js v14 that lets moderators right-click any message and choose "Check for AI". The bot replies privately (only the moderator sees it) with an AI-likelihood score.

We deliberately don't auto-scan every message or auto-delete anything. More on why at the end.

What you'll need

  • Node.js 20.6+ (for the built-in --env-file flag)
  • A Discord application and bot token from the Developer Portal
  • An AI detection API key (we use ProofAI's, but any detector with a probability score works)
mkdir ai-check-bot && cd ai-check-bot
npm init -y
npm pkg set type=module   # we use ES modules and top-level await
npm install discord.js
Enter fullscreen mode Exit fullscreen mode
# .env (never commit this)
DISCORD_TOKEN=your-bot-token
DISCORD_CLIENT_ID=your-application-id
PROOFAI_API_KEY=sk_live_...
PROOFAI_ORIGIN=https://yourapp.com
Enter fullscreen mode Exit fullscreen mode

Step 1: Register a message context-menu command

Context-menu commands appear when you right-click a message โ†’ Apps. No slash command typing, and no need for the privileged Message Content intent, because Discord passes the target message to your bot when a moderator uses the command.

// register.js
import { REST, Routes, ContextMenuCommandBuilder, ApplicationCommandType, PermissionFlagsBits } from "discord.js";

const command = new ContextMenuCommandBuilder()
  .setName("Check for AI")
  .setType(ApplicationCommandType.Message)
  .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages); // moderators only by default

const rest = new REST().setToken(process.env.DISCORD_TOKEN);
await rest.put(Routes.applicationCommands(process.env.DISCORD_CLIENT_ID), { body: [command.toJSON()] });
console.log("Registered 'Check for AI'");
Enter fullscreen mode Exit fullscreen mode

Run it once:

node --env-file=.env register.js
Enter fullscreen mode Exit fullscreen mode

Step 2: The detection helper

// detect.js
const API_URL = "https://ai.proofai.in/api/v1/detect";

export async function detectAI(text) {
  const words = text.trim().split(/\s+/).filter(Boolean).length;
  if (words < 50) return { status: "too_short", words };

  const res = await fetch(API_URL, {
    method: "POST",
    headers: {
      "x-api-key": process.env.PROOFAI_API_KEY,
      "Origin": process.env.PROOFAI_ORIGIN,
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: new URLSearchParams({ content: text }),
  });

  if (res.status === 429) return { status: "rate_limited" };
  if (!res.ok) return { status: "error" };
  const data = await res.json();
  return { status: "ok", p: data.ai_probability };
}
Enter fullscreen mode Exit fullscreen mode

Short Discord messages ("lol same", "thanks!") can't be scored meaningfully, so we refuse anything under 50 words instead of returning a misleading number.

Step 3: The bot

// bot.js
import { Client, Events, GatewayIntentBits, MessageFlags } from "discord.js";
import { detectAI } from "./detect.js";

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

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

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isMessageContextMenuCommand()) return;
  if (interaction.commandName !== "Check for AI") return;

  // Detection can take a few seconds, so acknowledge first (privately)
  await interaction.deferReply({ flags: MessageFlags.Ephemeral });

  const text = interaction.targetMessage.content ?? "";
  const result = await detectAI(text);

  let reply;
  if (result.status === "too_short") {
    reply = `This message has only ${result.words} words. Detection needs at least 50 words to be meaningful.`;
  } else if (result.status === "rate_limited") {
    reply = "Daily detection limit reached. Try again later.";
  } else if (result.status !== "ok") {
    reply = "Couldn't check this message right now.";
  } else {
    const level = result.p >= 85 ? "High" : result.p >= 60 ? "Medium" : "Low";
    reply = `**${level} likelihood of AI-generated text** (${result.p}%).\n` +
            `Treat this as one signal, not proof. Talk to the member before taking action.`;
  }

  await interaction.editReply(reply);
});

client.login(process.env.DISCORD_TOKEN);
Enter fullscreen mode Exit fullscreen mode
node --env-file=.env bot.js
Enter fullscreen mode Exit fullscreen mode

Invite the bot with the applications.commands and bot scopes, then right-click a long message โ†’ Apps โ†’ Check for AI.

Why the reply is ephemeral

MessageFlags.Ephemeral means only the moderator who ran the command sees the result. Posting "this person used AI!" publicly, based on a probability, is a fast way to embarrass a real member and lose trust in your mod team.

Things we deliberately didn't build

  • Auto-scanning every message. It needs the privileged Message Content intent, burns your API quota on small talk, and creates a feeling of surveillance.
  • Auto-delete or auto-ban. Detectors make mistakes. False positives are more common for non-native English writers and very formal writing.
  • Public "AI" badges. Same reason.

Good uses: checking contest submissions, long "introductions" from brand-new accounts that look spammy, or answers copy-pasted into help channels.

Ideas to extend it

  • Log checks to a private #mod-log channel for transparency within the mod team
  • Add a per-moderator cooldown so nobody burns the quota
  • Support attachments (PDF/DOCX) using the extraction code from our batch-scanning post

Full API reference: ProofAI API docs ยท Try the free web detector.

Do you moderate a community? How are you handling AI-generated posts? Tell us in the comments. ๐Ÿ‘‡


Disclosure: we're the team behind ProofAI at 4Born Solutions. This article was drafted with AI assistance and reviewed and edited by our team.

Top comments (0)