ModerationAnti-spamAutoMod8 min read

Automatic moderation bot

Anti-spam system, word filter, raid protection, warn/mute/ban system and audit logs.


Moderation bot architecture

A complete moderation bot needs: automatic infraction detection, progressive sanction system and action logging.

Step 1: Anti-spam system

javascript
const spamMap = new Map();

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

  const key = `${message.guild.id}-${message.author.id}`;
  const userData = spamMap.get(key) || { count: 0, lastMessage: 0, warnings: 0 };

  const now = Date.now();
  if (now - userData.lastMessage < 2000) {
    userData.count++;
  } else {
    userData.count = 1;
  }
  userData.lastMessage = now;
  spamMap.set(key, userData);

  // 5 messages in less than 10 seconds = spam
  if (userData.count >= 5) {
    await message.member.timeout(60000, 'Anti-spam: messages too fast');
    await message.channel.send(`${message.author} muted for spam.`);
    userData.count = 0;
    spamMap.set(key, userData);
  }
});

// Clean the map every 30 seconds
setInterval(() => {
  const now = Date.now();
  for (const [key, data] of spamMap) {
    if (now - data.lastMessage > 10000) spamMap.delete(key);
  }
}, 30000);

Step 2: Word filter

javascript
const bannedWords = ['badword1', 'badword2', 'slur'];
const bannedPatterns = [
  /discord\.gg\/[a-zA-Z0-9]+/i,  // Invitations
  /https?:\/\/(?!discord\.com)[^\s]+/i  // External links
];

client.on('messageCreate', async message => {
  if (message.author.bot) return;
  if (message.member.permissions.has('ManageMessages')) return;

  const content = message.content.toLowerCase();

  const hasBannedWord = bannedWords.some(word => content.includes(word));
  const hasBannedPattern = bannedPatterns.some(pattern => pattern.test(content));

  if (hasBannedWord || hasBannedPattern) {
    await message.delete();
    await message.channel.send({
      content: `${message.author}, your message was removed for prohibited content.`,
    }).then(msg => setTimeout(() => msg.delete(), 5000));

    await addWarning(message.guild.id, message.author.id, 'Prohibited content');
  }
});

Step 3: Anti-raid protection

javascript
const joinTracker = new Map();

client.on('guildMemberAdd', async member => {
  const guildId = member.guild.id;
  const joins = joinTracker.get(guildId) || [];
  joins.push(Date.now());

  // Clean old joins (last 10 seconds)
  const recent = joins.filter(t => Date.now() - t < 10000);
  joinTracker.set(guildId, recent);

  // If more than 10 users join in 10 seconds = raid
  if (recent.length >= 10) {
    // Activate verification mode
    await member.guild.setVerificationLevel(4); // VERY_HIGH
    const logChannel = member.guild.channels.cache.find(c => c.name === 'mod-logs');
    if (logChannel) {
      await logChannel.send('RAID DETECTED — Verification level elevated automatically.');
    }
  }
});

Step 4: Progressive warning system

javascript
async function addWarning(guildId, userId, reason) {
  // Save to database
  const warns = await db.addWarn(guildId, userId, reason);
  const totalWarns = warns.length;

  const guild = client.guilds.cache.get(guildId);
  const member = await guild.members.fetch(userId);

  // Progressive sanctions
  if (totalWarns >= 5) {
    await member.ban({ reason: '5 accumulated warnings' });
  } else if (totalWarns >= 3) {
    await member.timeout(24 * 60 * 60 * 1000, '3 accumulated warnings');
  } else if (totalWarns >= 2) {
    await member.timeout(60 * 60 * 1000, '2 accumulated warnings');
  }

  return totalWarns;
}

Step 5: /warn command

javascript
new SlashCommandBuilder()
  .setName('warn')
  .setDescription('Warn a user')
  .addUserOption(opt => opt.setName('user').setRequired(true))
  .addStringOption(opt => opt.setName('reason').setRequired(true))
  .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers);

// Handler
if (commandName === 'warn') {
  const target = interaction.options.getUser('user');
  const reason = interaction.options.getString('reason');
  const total = await addWarning(interaction.guild.id, target.id, reason);

  await interaction.reply(`Warning: ${target.tag} has been warned. Total: ${total}/5\nReason: ${reason}`);
}

Recommendations

  • Exclude moderators from anti-spam and filters
  • Log all moderation actions in a dedicated channel
  • Allow mods to review and remove warnings
  • Configure adjustable thresholds per server
  • Implement a /case command to view a user's history

Was this guide helpful?