Un système Discord reaction role permet aux membres de s'attribuer eux-mêmes un rôle en réagissant à un message avec un emoji ou en cliquant sur un bouton. Au lieu de distribuer un à un les rôles « couleur », « notifications » ou « centres d'intérêt jeu », vous laissez les membres choisir ; le serveur reste mieux rangé et la charge de modération diminue. Dans ce guide, nous construisons la logique d'auto-rôle de zéro : d'abord avec la réaction emoji classique, puis avec l'approche moderne par bouton recommandée aujourd'hui. Les exemples de code visent discord.js v14 et Node.js.
Quelle méthode : réaction emoji ou bouton ?
Il existe deux approches principales, et il vaut la peine d'en connaître la différence :
- Méthode réaction (emoji) : le membre clique sur un emoji du message, le bot écoute l'événement
messageReactionAddet attribue le rôle ; retirer l'emoji retire le rôle. Classique et familière, mais le bot a besoin d'unintentsupplémentaire pour voir les réactions, et la gestion des emojis est fragile. - Méthode bouton : vous attachez des boutons au message, le membre clique, et le bot bascule le rôle via
interactionCreate. Plus propre, plus fiable sur mobile, et c'est la voie moderne vers laquelle Discord vous oriente.
Pour les nouveaux projets, je recommande la méthode bouton. Cela dit, comme l'approche emoji reste très répandue sur les anciens serveurs, je la montre aussi.
Permissions et intents nécessaires
Le bot a besoin de la permission Manage Roles (Gérer les rôles) pour gérer les rôles. Il y a une autre règle d'or : le rôle du bot doit se situer au-dessus des rôles qu'il distribue. Discord ne laisse un bot attribuer que les rôles situés sous son rôle le plus élevé. Dans Paramètres du serveur > Rôles, faites donc glisser le rôle du bot au-dessus des rôles cibles.
Choisissez les bons intents à la création du client. Pour la méthode bouton, Guilds suffit ; la méthode emoji exige aussi GuildMessageReactions :
const { Client, GatewayIntentBits, Partials } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessageReactions, // uniquement pour la méthode emoji
],
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
});
Les partials sont importants : ils permettent au bot de capter les réactions sur d'anciens messages ajoutées pendant qu'il était hors ligne, faute de quoi ces réactions sont ignorées après un redémarrage.
Mettre en place l'auto-rôle avec des boutons
On envoie d'abord un message contenant les boutons de rôle. On intègre l'ID du rôle cible dans le customId de chaque bouton afin de savoir quel rôle est demandé au clic :
const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
// Appelé depuis une commande/un handler
async function sendRolePanel(channel) {
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId('role:123456789012345678') // ID du rôle cible
.setLabel('Notifications événements')
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setCustomId('role:987654321098765432')
.setLabel('Annonces')
.setStyle(ButtonStyle.Secondary),
);
await channel.send({
content: 'Cliquez sur un bouton pour prendre ou retirer le rôle :',
components: [row],
});
}
On écoute maintenant les clics et on bascule le rôle. Si le membre l'a déjà, on le retire, sinon on l'ajoute :
client.on('interactionCreate', async (interaction) => {
if (!interaction.isButton()) return;
if (!interaction.customId.startsWith('role:')) return;
const roleId = interaction.customId.split(':')[1];
const member = interaction.member;
try {
if (member.roles.cache.has(roleId)) {
await member.roles.remove(roleId);
await interaction.reply({ content: 'Rôle retiré.', ephemeral: true });
} else {
await member.roles.add(roleId);
await interaction.reply({ content: 'Rôle attribué !', ephemeral: true });
}
} catch (err) {
console.error(err);
await interaction.reply({
content: 'Impossible de définir le rôle. Vérifie mes permissions et l’ordre des rôles.',
ephemeral: true,
});
}
});
ephemeral: true n'affiche la réponse qu'au membre qui a cliqué, sans polluer le salon. Le try/catch renvoie un message d'erreur propre si la hiérarchie des rôles est mauvaise, informant l'utilisateur au lieu d'échouer en silence.
Auto-rôle classique avec réactions emoji
Si vous préférez la méthode emoji, vous devez stocker quelque part l'ID du message panneau et la correspondance emoji-rôle. Un simple objet suffit pour les petits serveurs ; sur de plus gros projets, vous le déplacerez dans une base de données (par exemple SQLite) :
const PANEL_MESSAGE_ID = '111111111111111111';
const map = {
'🔴': '123456789012345678', // rôle rouge
'🟢': '987654321098765432', // rôle vert
};
client.on('messageReactionAdd', async (reaction, user) => {
if (user.bot) return;
if (reaction.message.id !== PANEL_MESSAGE_ID) return;
if (reaction.partial) await reaction.fetch();
const roleId = map[reaction.emoji.name];
if (!roleId) return;
const member = await reaction.message.guild.members.fetch(user.id);
await member.roles.add(roleId).catch(console.error);
});
client.on('messageReactionRemove', async (reaction, user) => {
if (user.bot) return;
if (reaction.message.id !== PANEL_MESSAGE_ID) return;
if (reaction.partial) await reaction.fetch();
const roleId = map[reaction.emoji.name];
if (!roleId) return;
const member = await reaction.message.guild.members.fetch(user.id);
await member.roles.remove(roleId).catch(console.error);
});
Remarque : pour les emojis personnalisés, faites la correspondance sur reaction.emoji.id plutôt que sur reaction.emoji.name, car les noms peuvent changer alors que l'ID reste stable.
Sécurité et erreurs fréquentes
- Ordre des rôles : c'est le problème le plus courant. Si le rôle du bot est sous le rôle cible, vous obtiendrez une erreur « Missing Permissions ».
- Rôles gérés (managed) : les rôles de bot/intégration ou le rôle Nitro Booster ne peuvent pas être attribués manuellement ; ne les mettez pas sur le panneau.
- Élévation de privilèges : ne placez jamais sur le panneau des rôles aux permissions dangereuses comme
Manage RolesouAdministrator, sinon n'importe qui peut se nommer staff. - Fixez l'ID du message : n'oubliez pas le contrôle qui ne réagit qu'au message panneau, sinon le bot réagit à chaque message.
Questions fréquentes
De quels intents un bot reaction role a-t-il besoin ?
La méthode bouton ne nécessite que Guilds. La méthode emoji exige en plus l'intent GuildMessageReactions, ainsi que le réglage partials pour capter les réactions ajoutées pendant que le bot était hors ligne.
Pourquoi le rôle du bot doit-il être au-dessus du rôle cible ?
En raison d'une règle de sécurité de Discord, un bot ne peut ajouter ou retirer que les rôles situés sous son propre rôle le plus élevé. Si vous ne faites pas glisser le rôle du bot au-dessus des rôles distribués dans Paramètres du serveur > Rôles, vous obtiendrez une erreur « Missing Permissions ».
Que se passe-t-il si un membre réagit pendant que le bot est hors ligne ?
Avec la méthode bouton, aucun souci : l'interaction est traitée au retour du bot. Avec la méthode emoji, vous ratez cette réaction si vous n'avez pas défini partials — c'est précisément pourquoi la méthode bouton est plus fiable.
Vous voulez un système d'auto-rôle propre et sécurisé pour votre serveur ? Je peux construire un bot Discord basé sur les boutons, adossé à une base de données et doté d'une gestion d'erreurs solide. Contactez-moi pour votre projet.