Overview
Baileys manages a WebSocket connection to WhatsApp servers. Understanding the connection lifecycle, disconnect reasons, and reconnection strategies is essential for building reliable applications.
Connection States
The connection can be in one of three states:
type WAConnectionState = 'open' | 'connecting' | 'close'
Connection State Object
From src/Types/State.ts:17:
type ConnectionState = {
/** Connection is now open, connecting or closed */
connection: WAConnectionState
/** The error that caused the connection to close */
lastDisconnect?: {
error: Boom | Error | undefined
date: Date
}
/** Is this a new login */
isNewLogin?: boolean
/** The current QR code */
qr?: string
/** Has the device received all pending notifications */
receivedPendingNotifications?: boolean
/** If the client is shown as an active, online client */
isOnline?: boolean
}
Disconnect Reasons
From src/Types/index.ts:27:
enum DisconnectReason {
connectionClosed = 428,
connectionLost = 408,
connectionReplaced = 440,
timedOut = 408,
loggedOut = 401,
badSession = 500,
restartRequired = 515,
multideviceMismatch = 411,
forbidden = 403,
unavailableService = 503
}
Understanding Each Reason
loggedOut (401) - User logged out from WhatsApp. Do NOT reconnect.
connectionClosed (428) - Normal connection closure. Safe to reconnect.
connectionLost (408) - Network issue or timeout. Reconnect.
connectionReplaced (440) - Another device took over. Reconnect carefully.
restartRequired (515) - Server requests restart. Reconnect immediately.
timedOut (408) - Connection attempt timed out. Retry.
badSession (500) - Invalid session data. May require re-authentication.
multideviceMismatch (411) - Multi-device protocol mismatch. Update library.
forbidden (403) - Access denied. Check credentials.
unavailableService (503) - WhatsApp service temporarily unavailable.
Handling Connection Updates
Listen to connection.update events to track connection state:
import makeWASocket, { DisconnectReason } from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'
const sock = makeWASocket({ /* config */ })
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect, qr } = update
if (connection === 'close') {
const shouldReconnect =
(lastDisconnect?.error as Boom)?.output?.statusCode
!== DisconnectReason.loggedOut
console.log(
'Connection closed:',
lastDisconnect?.error,
'Reconnecting:',
shouldReconnect
)
if (shouldReconnect) {
connectToWhatsApp() // Reconnect
}
} else if (connection === 'open') {
console.log('Connection opened')
} else if (connection === 'connecting') {
console.log('Connecting...')
}
if (qr) {
console.log('QR Code:', qr)
// Display QR code to user
}
})
Complete Connection Example
From Example/example.ts:40:
import makeWASocket, {
DisconnectReason,
useMultiFileAuthState
} from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'
async function connectToWhatsApp() {
const { state, saveCreds } = await useMultiFileAuthState(
'auth_info_baileys'
)
const sock = makeWASocket({
auth: state,
printQRInTerminal: true
})
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if (connection === 'close') {
const statusCode = (lastDisconnect?.error as Boom)
?.output?.statusCode
const shouldReconnect = statusCode !== DisconnectReason.loggedOut
console.log(
'Connection closed due to',
lastDisconnect?.error,
'reconnecting',
shouldReconnect
)
// Reconnect if not logged out
if (shouldReconnect) {
connectToWhatsApp()
} else {
console.log('Connection closed. You are logged out.')
}
} else if (connection === 'open') {
console.log('Opened connection')
}
})
// Save credentials when updated
sock.ev.on('creds.update', saveCreds)
return sock
}
connectToWhatsApp()
Reconnection Strategies
Basic Reconnection
function reconnect() {
setTimeout(() => {
connectToWhatsApp()
}, 3000) // Wait 3 seconds before reconnecting
}
Exponential Backoff
let reconnectAttempts = 0
const MAX_RECONNECT_ATTEMPTS = 5
const BASE_DELAY = 1000 // 1 second
function reconnectWithBackoff() {
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
console.log('Max reconnection attempts reached')
return
}
const delay = BASE_DELAY * Math.pow(2, reconnectAttempts)
reconnectAttempts++
console.log(`Reconnecting in ${delay}ms (attempt ${reconnectAttempts})`)
setTimeout(() => {
connectToWhatsApp()
}, delay)
}
sock.ev.on('connection.update', (update) => {
if (update.connection === 'close') {
reconnectWithBackoff()
} else if (update.connection === 'open') {
reconnectAttempts = 0 // Reset on successful connection
}
})
Smart Reconnection
function shouldReconnect(
statusCode: number | undefined
): boolean {
// Never reconnect on logout
if (statusCode === DisconnectReason.loggedOut) {
return false
}
// Don't reconnect on bad session - may need re-auth
if (statusCode === DisconnectReason.badSession) {
console.log('Bad session - clearing auth state')
// Clear auth state and restart
return false
}
// Reconnect on all other errors
return true
}
QR Code Generation
When connecting for the first time, a QR code is generated:
sock.ev.on('connection.update', (update) => {
const { qr } = update
if (qr) {
// Option 1: Print to terminal
console.log('Scan this QR code:', qr)
// Option 2: Generate QR code image
// Use a library like 'qrcode' to generate an image
QRCode.toDataURL(qr, (err, url) => {
// Display url as image
})
}
})
Set printQRInTerminal: true in socket config to automatically print the QR code to the terminal.
Pairing Code Flow
From Example/example.ts:88:
const usePairingCode = true
sock.ev.on('connection.update', async (update) => {
const { qr } = update
if (qr && usePairingCode && !sock.authState.creds.registered) {
const phoneNumber = await question('Enter your phone number:\n')
const code = await sock.requestPairingCode(phoneNumber)
console.log(`Pairing code: ${code}`)
}
})
Connection Configuration
Important socket configuration options for connection management:
const sock = makeWASocket({
// Browser identification
browser: Browsers.ubuntu('My App'),
// Print QR to terminal
printQRInTerminal: true,
// Receive full message history
syncFullHistory: true,
// Mark as online when connecting
markOnlineOnConnect: true, // Set false for notifications
// Connection retry settings
connectTimeoutMs: 60_000,
// Custom logger
logger: pino({ level: 'info' })
})
If markOnlineOnConnect is true, your phone won’t receive notifications while Baileys is connected. Set to false if you want to receive notifications on your phone.
Monitoring Connection Health
Check if Connected
function isConnected(sock: WASocket): boolean {
return sock.ws?.readyState === WebSocket.OPEN
}
Presence Updates
// Send presence to indicate online status
await sock.sendPresenceUpdate('available', jid)
// Mark as unavailable to receive notifications
await sock.sendPresenceUpdate('unavailable')
If a desktop client is active, WhatsApp doesn’t send push notifications to the device. Mark your Baileys client as unavailable to receive notifications.
Received Pending Notifications
The receivedPendingNotifications flag indicates when all offline messages have been received:
sock.ev.on('connection.update', (update) => {
if (update.receivedPendingNotifications) {
console.log('All pending notifications received')
// Safe to proceed with operations
}
})
History Synchronization
On first connection, WhatsApp sends message history:
sock.ev.on('messaging-history.set', ({
chats,
contacts,
messages,
isLatest
}) => {
console.log(`Received ${messages.length} messages`)
console.log(`Received ${chats.length} chats`)
console.log(`Received ${contacts.length} contacts`)
console.log('Is latest history:', isLatest)
})
Best Practices
Connection Management Tips:
- Always check
loggedOut - Never reconnect when user logged out
- Implement backoff - Use exponential backoff for reconnection attempts
- Save credentials - Listen to
creds.update and save immediately
- Handle QR expiry - QR codes expire; generate new ones
- Monitor health - Track connection state and last disconnect reason
- Graceful shutdown - Properly close the socket before exiting
- Log errors - Log
lastDisconnect.error for debugging
Graceful Shutdown
process.on('SIGINT', async () => {
console.log('Shutting down gracefully...')
// Close the socket
sock.ws?.close()
// Save any pending data
await saveCreds()
process.exit(0)
})
See Also