Each example below was run against a test copy of Discord, with people joining and leaving (some of them unknown to the bot) to check that every greeting and goodbye goes out.
Switch on Server Members
Joins and leaves only reach a bot that asks for the Server Members intent. It is privileged, so it has to be switched on twice: in the code, as below, and in the Developer Portal on your application's Bot page under Privileged Gateway Intents. With only the code, the bot does not connect at all (PrivilegedIntentsRequired in discord.py, Used disallowed intents in discord.js). With only the portal, it connects and the events never fire. Once the bot is in 100 servers, Discord asks you to apply for it.
The bot also needs View Channel, Send Messages and Embed Links in the channel it greets in.
discord.py
import os
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True # the Server Members intent: switch it on in the Developer Portal too
bot = commands.Bot(command_prefix="!", intents=intents)
@bot.event
async def on_member_join(member: discord.Member):
channel = member.guild.system_channel
if channel is None:
return
embed = discord.Embed(
title=f"Welcome to {member.guild.name}!",
description=f"Hi {member.mention}, you are member number {member.guild.member_count}.",
colour=discord.Colour.green(),
)
embed.set_thumbnail(url=member.display_avatar.url)
await channel.send(embed=embed)
@bot.event
async def on_raw_member_remove(payload: discord.RawMemberRemoveEvent):
guild = bot.get_guild(payload.guild_id)
if guild and guild.system_channel:
await guild.system_channel.send(f"{payload.user.display_name} has left the server.")
bot.run(os.environ["BOT_TOKEN"])- Which channel.
system_channelis the server's system messages channel, where Discord posts its own join messages, so the greeting lands where people expect it. To use another one, look it up by ID instead:member.guild.get_channel(123456789012345678). - Why the raw event for goodbyes.
on_member_removeonly fires for members the bot has in memory.on_raw_member_removefires for everyone who leaves and carries their user, which is all a goodbye needs. - The mention.
member.mentionpings the newcomer, as Discord's own welcome does. The goodbye uses the name instead: there is nobody left to ping.
discord.js
const { Client, Colors, EmbedBuilder, Events, GatewayIntentBits, Partials } = require("discord.js");
const client = new Client({
// GuildMembers is the Server Members intent: switch it on in the Developer Portal too.
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
partials: [Partials.GuildMember], // goodbyes for people the bot never had in memory
});
client.on(Events.GuildMemberAdd, async (member) => {
const channel = member.guild.systemChannel;
if (!channel) return;
const embed = new EmbedBuilder()
.setTitle(`Welcome to ${member.guild.name}!`)
.setDescription(`Hi ${member}, you are member number ${member.guild.memberCount}.`)
.setColor(Colors.Green)
.setThumbnail(member.displayAvatarURL());
await channel.send({ embeds: [embed] });
});
client.on(Events.GuildMemberRemove, async (member) => {
const channel = member.guild.systemChannel;
if (channel) await channel.send(`${member.user.displayName} has left the server.`);
});
client.login(process.env.BOT_TOKEN);- Why
Partials.GuildMember. discord.js only firesGuildMemberRemovefor members it has in memory, and a bot rarely has everyone: in a bigger server, the people who were there before it started are mostly not. Without the partial, their goodbyes are skipped with no error. With it, the event comes with what Discord sends, which includes the user. ${member}in a string is a mention, andmember.guild.memberCountalready counts the newcomer.
A welcome DM as well
Some people only accept DMs from friends, and Discord then refuses the message. That is normal, not a bug, so catch it rather than letting it fill the logs. In discord.py, inside on_member_join:
try:
await member.send(f"Welcome to {member.guild.name}! The rules are pinned in the first channel.")
except discord.Forbidden:
pass # they do not take DMs from server membersIn discord.js, inside the GuildMemberAdd handler, with RESTJSONErrorCodes added to the require:
await member.send(`Welcome to ${member.guild.name}! The rules are pinned in the first channel.`).catch((err) => {
if (err.code !== RESTJSONErrorCodes.CannotSendMessagesToThisUser) console.error(err); // 50007: DMs closed
});Common problems
- Nothing happens when someone joins: Server Members is on in the portal but not in the code, or the other way round, or the server has no system messages channel (
system_channelisNone). - Welcomes work, goodbyes do not: in discord.js,
Partials.GuildMemberis missing. In discord.py, the code useson_member_removeinstead of the raw event. 50013 Missing Permissionswhen posting: the bot cannot send messages or embeds in that channel. Check the channel's own permission overrides, not only the bot's role.50007 Cannot send messages to this user: their DMs are closed. Catch it, as above.- The member number is off: it is the server's member count at that moment, bots included.
Did this page help?
Thanks for the feedback.