Fires only on a user's first interaction with the bot — or the first one
after bot.resetWelcome() / the /reset command of slashCommandsPlugin.
Scope: per chat in a DM, per participant in a group (each member
who speaks gets their own welcome), independent of conversationScope. A
DM and a group are different first contacts.
What counts: the first message that reaches the matcher stage. Commands,
an active conversation, a dormant resume, an aborting before-hook or the
groupMode filter consume a message without spending the welcome.
Precedence: above every other trigger (see the module docs). ctx.pass()
inside the handler lets the same message continue to the regular matchers.
Persistence: resolved against the store (IStore cursor key/value,
supported by every bundled store), so it survives restarts with a
persistent store. It is decided inside the per-chat FIFO, so concurrent first
messages cannot both be welcomed. Across several processes sharing a store
it is check-then-set (route a chat to a single process, as conversations
already require).
Cost: with no WELCOME handler registered there are zero extra store
reads. With one, each user costs at most one read (two in groups) plus one
write per process lifetime; later messages hit an in-memory cache.
If the store read fails, WELCOME is skipped for that message (it never
greets on an unknown state), the error goes to bot.on('error'), and the
message continues to the other matchers.
Example
bot.when(WELCOME, async (ctx) => { awaitctx.reply('🙌 ¡Bienvenido! Escribe "menu" para ver las opciones.') }) // or as an onboarding flow (add `.id('onboarding')` to make it `.persistent()`) bot.use(flow(WELCOME).ask('¿Cómo te llamas?', 'name').say((_, c) =>`¡Hola ${c.state.name}!`))
Fires only on a user's first interaction with the bot — or the first one after
bot.resetWelcome()/ the/resetcommand ofslashCommandsPlugin.conversationScope. A DM and a group are different first contacts.groupModefilter consume a message without spending the welcome.ctx.pass()inside the handler lets the same message continue to the regular matchers.IStorecursor key/value, supported by every bundled store), so it survives restarts with a persistent store. It is decided inside the per-chat FIFO, so concurrent first messages cannot both be welcomed. Across several processes sharing a store it is check-then-set (route a chat to a single process, as conversations already require).bot.on('error'), and the message continues to the other matchers.