This recipe posts a welcome message every time someone joins your server: a friendly embed with the new member's name, avatar, and their member number. The catch — and the whole reason this needs its own guide — is that join events don't reach your bot until you flip one privileged switch in the Developer Portal.
| At a glance | |
|---|---|
| You need | a working bot from Host a discord.js bot, and a channel to post welcomes in |
| Plan | Free or premium |
| Time | About fifteen minutes |
Start from the discord.js bot guide if you haven't — you need a bot with your token in .env already running.
Turn on the Server Members intent first
Your bot can't be told about new members unless Discord is allowed to send it member events, and that permission is a privileged intent you toggle by hand.
⚠️ Heads up — this is a privileged intent. In the Discord Developer Portal, open your application → Bot → scroll to Privileged Gateway Intents → turn on Server Members Intent → save. The code below requests
GatewayIntentBits.GuildMembers; if that toggle is off, the bot crashes at login withUsed disallowed intentsinstead of starting. On servers over 100 members Discord also asks you to verify the bot before it will grant this intent.
The code
The complete index.js. It reads the target channel's ID from .env, so you don't hard-code it:
require('dotenv').config();
const {
Client, Events, GatewayIntentBits,
EmbedBuilder,
} = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
],
});
client.once(Events.ClientReady, (c) => {
console.log(`Listening as ${c.user.tag}`);
});
client.on(Events.GuildMemberAdd, async (member) => {
const channel = member.guild.channels.cache.get(process.env.WELCOME_CHANNEL_ID);
if (!channel) return;
const embed = new EmbedBuilder()
.setColor(0x57f287)
.setTitle('👋 Welcome!')
.setDescription(`Hey ${member}, welcome to **${member.guild.name}**!`)
.setThumbnail(member.user.displayAvatarURL())
.addFields(
{ name: 'Member', value: `${member.user.tag}`, inline: true },
{ name: 'You are member #', value: `${member.guild.memberCount}`, inline: true },
)
.setTimestamp();
await channel.send({ content: `${member}`, embeds: [embed] });
});
client.login(process.env.DISCORD_TOKEN);
Then add the channel's ID to your .env, next to the token:
DISCORD_TOKEN=your-token
WELCOME_CHANNEL_ID=123456789012345678
To get a channel's ID, enable Developer Mode in Discord (User Settings → Advanced), then right-click the welcome channel and choose Copy Channel ID. Save .env and restart.
The parts that matter
GatewayIntentBits.GuildMembersin the intents array is what asks Discord to sendGuildMemberAddevents. It only works because you enabled the matching toggle above — the two must agree.Events.GuildMemberAddfires once per join. Itsmemberargument is the person who joined, carrying their guild (member.guild) and user (member.user).member.guild.channels.cache.get(process.env.WELCOME_CHANNEL_ID)looks up the channel to post in. Theif (!channel) returnguard means a wrong or deleted ID fails quietly instead of crashing.${member}in a string becomes a live@mentionthat pings the new member. Putting it incontent(outside the embed) is what actually notifies them — mentions inside an embed don't ping.member.guild.memberCountis the running total, so "You are member #1,024" comes for free.
The embed itself is standard — Embeds deep dive covers every field it can hold.
Making it yours
- Post in the system channel automatically. Swap the lookup for
member.guild.systemChannelto use whatever channel Discord already flags for system messages — no ID needed. - DM the newcomer instead.
await member.send('Welcome!')messages them directly. Wrap it intry/catch: people who block DMs from server members will throw an error. - Say goodbye too. Add an
Events.GuildMemberRemovehandler for a leave message — it uses the same member object and needs the same intent. - Auto-assign a role while you're here. Since you've already enabled the Server Members intent, Give every new member a role is a two-line addition to this same handler.
Troubleshooting
Used disallowed intentsat startup — the Server Members Intent toggle is off in the Developer Portal. Turn it on (see the callout) and restart. See Bot appears offline.- Bot starts fine but never welcomes anyone — either the intent toggle is off (no crash, just silence on older setups) or
WELCOME_CHANNEL_IDis wrong. Confirm the ID with Copy Channel ID and that the bot can see and post in that channel. - The welcome posts but doesn't ping the new member — the mention has to be in
content, not inside the embed. The code puts${member}incontentfor exactly this reason. - Nothing in a channel the bot can't access — check the bot's role has View Channel and Send Messages on the welcome channel.