Skip to main content

Command Palette

Search for a command to run...

Automated Role System for Discord Guild Tags

Written by
Yasin Çakmak avatar
Yasin Çakmak
Published onFeb 2, 2026
Views
Comments

Discord Guild Tag & Role System

As Discord servers grow, organizing members can become challenging. Especially when you want to identify members carrying a specific community tag and give them exclusive privileges, it can be a lot of work for moderators. That’s exactly where we step in: Automated Role System for Guild Tags.

With this system, whenever a member obtains the server’s designated tag, they automatically receive a special role. If they lose the tag, the role is removed. Moderators can just sit back and smile, thinking “Great, the system works.” 😏


How the System Works

The core of our system is Discord's Raw Event. We listen to the GUILD_MEMBER_UPDATE event and constantly monitor members’ tag status. Here’s how it works:

  1. If the member has the tag and doesn’t have the role: The role is automatically added, and a green embed message is sent to the log channel.
  2. If the member loses the tag and has the role: The role is removed, and a red embed message is logged.
  3. Spam prevention: The debounceCache ensures the same member isn’t processed repeatedly within a short time.

Sample Code

TypeScript
Raw Event File
import { WosskiClient, Event } from '@repo/client'
import { bold, inlineCode, Colors, EmbedBuilder, TextChannel, GatewayDispatchPayload, Events } from 'discord.js'

const debounceCache = new Map<string, number>()

const config = {
  guildID: '852890250312286218',
  log: '1433226826691514378',
  role: '1415371533483901162'
}

export default class RawEvent extends Event {
  constructor(client: WosskiClient) {
    super(client, { name: Events.Raw })
  }

  async run(client: WosskiClient, packet: GatewayDispatchPayload) {
    if (packet.t !== 'GUILD_MEMBER_UPDATE') return
    const data = packet.d
    if (data.guild_id !== config.guildID) return

    const guild = client.guilds.cache.get(config.guildID)
    if (!guild) return
    const member = guild.members.cache.get(data.user.id)
    if (!member || member.user.bot) return

    const last = debounceCache.get(member.id)
    if (last && Date.now() - last < 3000) return
    debounceCache.set(member.id, Date.now())

    const logChannel = client.channels.cache.get(config.log) as TextChannel | undefined

    const hasTag = data.user.primary_guild?.identity_guild_id === config.guildID
    const hasRole = member.roles.cache.has(config.role)

    if (hasTag && !hasRole) {
      await member.roles.add(config.role).catch(() => {})
      logChannel?.send({
        embeds: [
          new EmbedBuilder()
            .setColor(Colors.Green)
            .setDescription(
              `${member} [${inlineCode(member.id)}] ${bold(`@${member.guild.roles.cache.get(config.role)?.name}`)} has been given`
            )
        ]
      })
    } else if (!hasTag && hasRole) {
      await member.roles.remove(config.role).catch(() => {})
      logChannel?.send({
        embeds: [
          new EmbedBuilder()
            .setColor(Colors.Red)
            .setDescription(
              `${member} [${inlineCode(member.id)}] ${bold(`@${member.guild.roles.cache.get(config.role)?.name}`)} has been removed`
            )
        ]
      })
    }
  }
}
Edit on GitHub
Last updated: Feb 2, 2026