Un bot de modération Discord est le moyen le plus pratique de garder un serveur en croissance sous contrôle : il réagit aux infractions en quelques secondes, enregistre chaque action et ne confie les pouvoirs de modération qu'aux bonnes personnes. Dans ce guide, nous construisons les commandes ban, kick et mute (timeout) à partir de zéro avec discord.js v14. L'objectif n'est pas seulement que les commandes fonctionnent ; ce sont les détails qui comptent sur de vrais serveurs — contrôle des permissions, hiérarchie des rôles et raisons d'audit log.
Permissions et intents requis
Les commandes de modération exigent que le bot puisse gérer les membres. Dans le Discord Developer Portal, accordez à votre bot les permissions Ban Members, Kick Members et Moderate Members. Moderate Members est obligatoire pour les timeouts (mutes). Vous devez aussi activer l'intent GuildMembers dans le code et cocher ce privileged intent dans le portail pour accéder aux données des membres.
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
],
});
Dans les paramètres du serveur, le rôle du bot doit se trouver au-dessus des rôles des membres qu'il modérera. Discord ne le laissera pas bannir quelqu'un de rang supérieur au sien, et nous appliquerons aussi cette règle dans le code.
Définition de la commande et permission par défaut
En définissant les slash commands, vous pouvez limiter leur visibilité par défaut avec setDefaultMemberPermissions. Cela masque la commande aux membres sans la permission, mais ce n'est qu'un filtre d'interface — vous devez tout de même effectuer le vrai contrôle de sécurité à l'exécution.
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const banCommand = new SlashCommandBuilder()
.setName('ban')
.setDescription('Bannit un membre du serveur')
.addUserOption(o =>
o.setName('membre').setDescription('Membre à bannir').setRequired(true))
.addStringOption(o =>
o.setName('raison').setDescription('Raison du bannissement'))
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers);
Contrôle des permissions et de la hiérarchie
Pour chaque commande de modération, vous devez vérifier deux choses : la permission de la personne qui l'exécute et la hiérarchie des rôles. discord.js propose des getters tout faits qui simplifient cela : member.bannable, member.kickable et member.moderatable. Ils tiennent compte à la fois des permissions du bot et de l'ordre des rôles. Il reste néanmoins recommandé de vérifier aussi que le modérateur est de rang supérieur au membre ciblé.
function canModerate(interaction, target) {
const actor = interaction.member;
// Le propriétaire du serveur peut tout faire
if (actor.id === interaction.guild.ownerId) return true;
// Le modérateur est-il au-dessus de la cible ?
return actor.roles.highest.comparePositionTo(target.roles.highest) > 0;
}
Si comparePositionTo renvoie une valeur positive, actor est de rang supérieur. Ignorer ce contrôle pourrait permettre à un modérateur de bannir quelqu'un ayant plus d'autorité que lui.
Implémentation de ban, kick et timeout
Nous regroupons les commandes dans un seul handler. Point clé : la raison d'audit log, transmise à la méthode concernée via le champ reason, apparaît dans l'audit log de Discord. Ainsi, la question « qui a fait quoi à qui, et pourquoi » ne restera pas sans réponse par la suite.
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
const target = interaction.options.getMember('membre');
const raison = interaction.options.getString('raison') ?? 'Non précisée';
if (!target) {
return interaction.reply({ content: 'Membre introuvable.', ephemeral: true });
}
if (!canModerate(interaction, target)) {
return interaction.reply({ content: 'Tu ne peux pas modérer ce membre.', ephemeral: true });
}
if (interaction.commandName === 'ban') {
if (!target.bannable) {
return interaction.reply({ content: 'Je ne peux pas bannir ce membre.', ephemeral: true });
}
await target.ban({ reason: raison, deleteMessageSeconds: 60 * 60 * 24 });
await interaction.reply(`🔨 ${target.user.tag} a été banni. Raison : ${raison}`);
}
if (interaction.commandName === 'kick') {
if (!target.kickable) {
return interaction.reply({ content: 'Je ne peux pas expulser ce membre.', ephemeral: true });
}
await target.kick(raison);
await interaction.reply(`👢 ${target.user.tag} a été expulsé. Raison : ${raison}`);
}
if (interaction.commandName === 'mute') {
if (!target.moderatable) {
return interaction.reply({ content: 'Je ne peux pas réduire ce membre au silence.', ephemeral: true });
}
const minutes = interaction.options.getInteger('minutes') ?? 10;
await target.timeout(minutes * 60 * 1000, raison);
await interaction.reply(`🔇 ${target.user.tag} a été muté pour ${minutes} minutes.`);
}
});
Pour le mute, nous ne créons pas de rôle séparé ; nous utilisons la fonction timeout intégrée de Discord. member.timeout() prend une durée en millisecondes et est plafonnée à 28 jours. Passez null comme durée pour lever le timeout. Le timeout intégré est plus fiable qu'un rôle « muted » séparé, car le silence reste valable même si l'utilisateur rejoint de nouveaux salons.
Ne masquez pas les erreurs
Les pannes réseau, les permissions manquantes ou un membre déjà parti sont fréquents en pratique. Enveloppez les commandes dans un try/catch et renvoyez un message clair à l'utilisateur ; une erreur qui tombe silencieusement dans la console est la cause la plus courante des plaintes « le bot ne marche pas ».
try {
await target.ban({ reason: raison });
await interaction.reply(`🔨 ${target.user.tag} a été banni.`);
} catch (err) {
console.error(err);
await interaction.reply({ content: 'L\'action a échoué.', ephemeral: true });
}
Bonnes pratiques
- Réponses éphémères : affichez les messages d'erreur et de permission avec
ephemeral: truepour que seul l'auteur de la commande les voie ; le salon reste propre. - Raison obligatoire : pour les actions graves, utilisez
setRequired(true)afin d'obliger le modérateur à écrire une explication. - Salon de logs dédié : envoyez aussi chaque action de modération sous forme d'embed dans un salon de logs privé ; c'est une trace permanente en plus de l'audit log.
- Protégez-vous et le bot : refusez l'action si la cible est l'auteur de la commande ou le bot lui-même.
Questions fréquentes
Dois-je créer un rôle séparé pour le mute ?
Non. Avec discord.js v14, utiliser la fonction de timeout intégrée de Discord (member.timeout()) est bien plus robuste. Un rôle « muted » séparé exige des overrides de permissions dans chaque salon et peut laisser des failles quand un utilisateur rejoint de nouveaux salons ; un timeout s'applique automatiquement à l'ensemble du serveur.
Pourquoi mon bot ne peut-il pas bannir des membres de rang supérieur ?
Discord ne laisse un bot ou un membre gérer que les membres situés en dessous de son rôle le plus élevé. Déplacez le rôle du bot au-dessus de ces membres dans Paramètres du serveur → Rôles. Si le getter member.bannable renvoie false, la cause est presque toujours la hiérarchie.
Comment inscrire une raison dans l'audit log ?
Il suffit de passer le champ reason à la méthode concernée : target.ban({ reason: 'Spam' }) ou target.timeout(ms, 'Publicité'). Discord ajoute ce texte à côté de l'action dans l'audit log du serveur.
Vous voulez un bot de modération sécurisé et respectueux des permissions pour votre serveur ? Planifions ensemble une configuration avec ban/kick/timeout, un salon de logs automatique et des mesures anti-raid — contactez-moi.