Baileys uses an event-driven architecture. All socket events are typed through the BaileysEventMap interface.
BaileysEventEmitter
The event emitter interface used by Baileys sockets.
Register an event listeneron<T extends keyof BaileysEventMap>(
event: T,
listener: (arg: BaileysEventMap[T]) => void
): void
Remove an event listeneroff<T extends keyof BaileysEventMap>(
event: T,
listener: (arg: BaileysEventMap[T]) => void
): void
Remove all listeners for an eventremoveAllListeners<T extends keyof BaileysEventMap>(event: T): void
Emit an eventemit<T extends keyof BaileysEventMap>(
event: T,
arg: BaileysEventMap[T]
): boolean
BaileysEventMap
Complete mapping of all events to their payload types.
Connection Events
Fired when connection state changes (WS opened, closed, connecting, etc.)sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect, qr } = update
if (connection === 'close') {
// Handle disconnection
}
})
Authentication Events
creds.update
Partial<AuthenticationCreds>
Fired when credentials are updated (keys, identity, etc.)sock.ev.on('creds.update', saveCreds)
Message Events
New messages received or synced from history
type
MessageUpsertType
required
"notify": New message, show notification
"append": Historical message, no notification
Present if messages were requested from phone due to unavailability
sock.ev.on('messages.upsert', ({ messages, type }) => {
for (const msg of messages) {
if (type === 'notify') {
console.log('New message:', msg)
}
}
})
Updates to existing messages (delivery receipts, edits, etc.)sock.ev.on('messages.update', (updates) => {
for (const { key, update } of updates) {
// update.status: delivered, read, etc.
}
})
Messages deleted by user// Specific messages
{ keys: WAMessageKey[] }
// All messages in a chat
{ jid: string; all: true }
Reactions added/removed from messagesArray<{
key: WAMessageKey
reaction: proto.IReaction
}>
Example:sock.ev.on('messages.reaction', (reactions) => {
for (const { key, reaction } of reactions) {
console.log(`${reaction.text} on message ${key.id}`)
}
})
Media encryption info updatesArray<{
key: WAMessageKey
media?: { ciphertext: Uint8Array; iv: Uint8Array }
error?: Boom
}>
message-receipt.update
MessageUserReceiptUpdate[]
Individual user receipts (read, played, etc.)sock.ev.on('message-receipt.update', (receipts) => {
for (const { key, receipt } of receipts) {
console.log(`${receipt.userJid} read at ${receipt.readTimestamp}`)
}
})
Chat Events
New chats createdsock.ev.on('chats.upsert', (chats) => {
console.log(`${chats.length} new chats`)
})
Updates to existing chats (name, unread count, etc.)sock.ev.on('chats.update', (updates) => {
for (const update of updates) {
if (update.unreadCount) {
console.log(`${update.id}: ${update.unreadCount} unread`)
}
}
})
Array of chat JIDs that were deletedsock.ev.on('chats.delete', (deletedChats) => {
console.log('Deleted:', deletedChats)
})
Chat lock status changed{ id: string; locked: boolean }
History Sync Events
Bulk history sync from phone (reverse chronological order)
LID to phone number mappings
Whether this is the latest history batch
syncType
proto.HistorySync.HistorySyncType | null
Type of history sync
Session ID for peer data request
sock.ev.on('messaging-history.set', (history) => {
console.log(`Synced ${history.chats.length} chats`)
console.log(`Synced ${history.messages.length} messages`)
console.log(`Progress: ${history.progress * 100}%`)
})
Updates to existing contacts
Group Events
Updates to group metadata (name, subject, etc.)
group-participants.update
Participant changes in a group
participants
GroupParticipant[]
required
Affected participants
action
ParticipantAction
required
Action: 'add', 'remove', 'promote', 'demote'
sock.ev.on('group-participants.update', (update) => {
console.log(`${update.action} in ${update.id}`)
console.log('Participants:', update.participants)
})
Someone requested to join a group
Participant’s phone number
action
RequestJoinAction
required
'create' or 'revoke'
method
RequestJoinMethod
required
How they requested: 'invite_link', etc.
Labels assigned to group member changed{
groupId: string
participant: string
participantAlt?: string
label: string
messageTimestamp?: number
}
Presence Events
Contact presence changed (typing, online, etc.){
id: string // chat JID
presences: {
[participant: string]: PresenceData
}
}
Example:sock.ev.on('presence.update', ({ id, presences }) => {
for (const [jid, presence] of Object.entries(presences)) {
console.log(`${jid} is ${presence.lastKnownPresence}`)
// 'unavailable', 'available', 'composing', 'recording', 'paused'
}
})
Blocklist Events
Entire blocklist replaced
Blocklist updated incrementally{
blocklist: string[]
type: 'add' | 'remove'
}
Call Events
Incoming/outgoing call eventssock.ev.on('call', (calls) => {
for (const call of calls) {
console.log(`Call from ${call.from}: ${call.status}`)
}
})
Label Events
Label associated/disassociated with item{
association: LabelAssociation
type: 'add' | 'remove'
}
Newsletter Events
Reaction on newsletter message{
id: string
server_id: string
reaction: {
code?: string
count?: number
removed?: boolean
}
}
Newsletter message viewed{
id: string
server_id: string
count: number
}
newsletter-participants.update
Newsletter participant role changed{
id: string
author: string
user: string
new_role: string
action: string
}
newsletter-settings.update
Newsletter settings changed{
id: string
update: any
}
Settings Events
Account settings changed. Union of:| { setting: 'unarchiveChats'; value: boolean }
| { setting: 'locale'; value: string }
| { setting: 'disableLinkPreviews'; value: proto.SyncActionValue.IPrivacySettingDisableLinkPreviewsAction }
| { setting: 'timeFormat'; value: proto.SyncActionValue.ITimeFormatAction }
| { setting: 'privacySettingRelayAllCalls'; value: proto.SyncActionValue.IPrivacySettingRelayAllCalls }
| { setting: 'statusPrivacy'; value: proto.SyncActionValue.IStatusPrivacyAction }
| { setting: 'notificationActivitySetting'; value: proto.SyncActionValue.NotificationActivitySettingAction.NotificationActivitySetting }
| { setting: 'channelsPersonalisedRecommendation'; value: proto.SyncActionValue.IPrivacySettingChannelsPersonalisedRecommendationAction }
LID to phone number mapping updated{
pn: string // phone number
lid: string // LID
}
BufferedEventData
Internal type used for buffering events before emission:
type BufferedEventData = {
historySets: { ... }
chatUpserts: { [jid: string]: Chat }
chatUpdates: { [jid: string]: ChatUpdate }
chatDeletes: Set<string>
contactUpserts: { [jid: string]: Contact }
contactUpdates: { [jid: string]: Partial<Contact> }
messageUpserts: { [key: string]: { type: MessageUpsertType; message: WAMessage } }
messageUpdates: { [key: string]: WAMessageUpdate }
messageDeletes: { [key: string]: WAMessageKey }
messageReactions: { [key: string]: { key: WAMessageKey; reactions: proto.IReaction[] } }
messageReceipts: { [key: string]: { key: WAMessageKey; userReceipt: proto.IUserReceipt[] } }
groupUpdates: { [jid: string]: Partial<GroupMetadata> }
}
Example: Complete Event Handler
import makeWASocket from '@whiskeysockets/baileys'
const sock = makeWASocket({ /* config */ })
// Connection
sock.ev.on('connection.update', (update) => {
console.log('Connection:', update.connection)
})
// Credentials
sock.ev.on('creds.update', saveCreds)
// Messages
sock.ev.on('messages.upsert', async ({ messages, type }) => {
for (const msg of messages) {
if (type === 'notify' && !msg.key.fromMe) {
await handleIncomingMessage(msg)
}
}
})
// Message updates
sock.ev.on('messages.update', (updates) => {
for (const { key, update } of updates) {
if (update.status) {
console.log(`Message ${key.id} status: ${update.status}`)
}
}
})
// Presence
sock.ev.on('presence.update', ({ id, presences }) => {
for (const [jid, presence] of Object.entries(presences)) {
if (presence.lastKnownPresence === 'composing') {
console.log(`${jid} is typing in ${id}`)
}
}
})
// Groups
sock.ev.on('group-participants.update', (update) => {
console.log(`${update.action} in ${update.id}:`, update.participants)
})