Skip to main content
Baileys manages a WebSocket connection to WhatsApp’s servers. Understanding the connection lifecycle is crucial for building reliable bots.

Connection states

The connection can be in one of three states:
type WAConnectionState = 'open' | 'connecting' | 'close'

Connection lifecycle

1

Connecting

Socket is attempting to establish a WebSocket connection to WhatsApp servers.
2

Open

Connection is established and authenticated. The client can send and receive messages.
3

Close

Connection has been terminated. Check lastDisconnect to determine if reconnection is needed.

Monitoring connection updates

Listen to the connection.update event to monitor connection state changes:
import makeWASocket from '@whiskeysockets/baileys'

const sock = makeWASocket({ /* config */ })

sock.ev.on('connection.update', (update) => {
    const { connection, lastDisconnect, qr } = update
    
    console.log('Connection status:', connection)
    
    if (qr) {
        console.log('QR Code:', qr)
    }
})

Connection update properties

connection
'open' | 'connecting' | 'close'
Current connection state
lastDisconnect
object
Information about the last disconnection, including the error and timestamp
qr
string
QR code string to display for authentication (only present during initial authentication)
isNewLogin
boolean
Whether this is a new login session
receivedPendingNotifications
boolean
Whether all pending notifications have been received

Disconnect reasons

When the connection closes, check the DisconnectReason to determine the appropriate action:
DisconnectReason enum
export enum DisconnectReason {
    connectionClosed = 428,
    connectionLost = 408,
    connectionReplaced = 440,
    timedOut = 408,
    loggedOut = 401,
    badSession = 500,
    restartRequired = 515,
    multideviceMismatch = 411,
    forbidden = 403,
    unavailableService = 503
}

Common disconnect reasons

The session was logged out from another device. Do not reconnect automatically.
if (statusCode === DisconnectReason.loggedOut) {
    console.log('Logged out, please re-authenticate')
    // Do not reconnect
}

Implementing reconnection logic

A robust reconnection strategy prevents unnecessary re-authentication:
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 shouldReconnect = 
                (lastDisconnect?.error as Boom)?.output?.statusCode !== 
                DisconnectReason.loggedOut
            
            console.log(
                'Connection closed due to',
                lastDisconnect?.error,
                'reconnecting:',
                shouldReconnect
            )
            
            if (shouldReconnect) {
                connectToWhatsApp()
            }
        } else if (connection === 'open') {
            console.log('Connection opened successfully')
        }
    })
    
    sock.ev.on('creds.update', saveCreds)
}

connectToWhatsApp()
Always check if the disconnect reason is loggedOut before reconnecting. Reconnecting after a logout will fail and may trigger rate limiting.

Advanced reconnection strategies

Exponential backoff

Implement exponential backoff to avoid hammering WhatsApp servers:
let reconnectAttempts = 0
const MAX_RECONNECT_ATTEMPTS = 5
const BASE_DELAY = 1000

async function connectWithBackoff() {
    const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
    
    const sock = makeWASocket({
        auth: state,
        printQRInTerminal: true
    })
    
    sock.ev.on('connection.update', async (update) => {
        const { connection, lastDisconnect } = update
        
        if (connection === 'close') {
            const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
            const shouldReconnect = statusCode !== DisconnectReason.loggedOut
            
            if (shouldReconnect && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
                reconnectAttempts++
                const delay = BASE_DELAY * Math.pow(2, reconnectAttempts - 1)
                
                console.log(`Reconnecting in ${delay}ms (attempt ${reconnectAttempts})...`)
                await new Promise(resolve => setTimeout(resolve, delay))
                connectWithBackoff()
            } else if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
                console.log('Max reconnection attempts reached')
            }
        } else if (connection === 'open') {
            reconnectAttempts = 0 // Reset on successful connection
            console.log('Connected successfully')
        }
    })
    
    sock.ev.on('creds.update', saveCreds)
}

Reconnection with error handling

async function connectToWhatsApp() {
    try {
        const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
        
        const sock = makeWASocket({
            auth: state,
            printQRInTerminal: true,
            connectTimeoutMs: 60000
        })
        
        sock.ev.on('connection.update', (update) => {
            const { connection, lastDisconnect } = update
            
            if (connection === 'close') {
                const error = lastDisconnect?.error as Boom
                const statusCode = error?.output?.statusCode
                
                switch (statusCode) {
                    case DisconnectReason.loggedOut:
                        console.log('Device logged out, please re-authenticate')
                        break
                    
                    case DisconnectReason.badSession:
                        console.log('Bad session, deleting auth state...')
                        // Delete auth files and restart
                        break
                    
                    case DisconnectReason.connectionReplaced:
                        console.log('Connection replaced, reconnecting...')
                        connectToWhatsApp()
                        break
                    
                    default:
                        console.log('Connection closed, reconnecting...')
                        connectToWhatsApp()
                }
            } else if (connection === 'open') {
                console.log('Connection established')
            }
        })
        
        sock.ev.on('creds.update', saveCreds)
        
        return sock
    } catch (error) {
        console.error('Error creating socket:', error)
        throw error
    }
}

Connection configuration

Timeout settings

Configure various timeout settings for connection management:
const sock = makeWASocket({
    connectTimeoutMs: 60000,           // Connection timeout (default: 20000)
    defaultQueryTimeoutMs: 60000,      // Query timeout (default: 60000)
    keepAliveIntervalMs: 25000,        // Ping interval (default: 25000)
    qrTimeout: 40000                   // QR code timeout (default: undefined)
})
connectTimeoutMs
number
default:"20000"
Maximum time to wait for initial connection
defaultQueryTimeoutMs
number
default:"60000"
Default timeout for queries to WhatsApp
keepAliveIntervalMs
number
default:"25000"
Interval for WebSocket ping-pong to keep connection alive
qrTimeout
number
Time to wait for QR code generation before timeout

Online presence

Control whether your client appears online:
const sock = makeWASocket({
    markOnlineOnConnect: false  // Don't mark as online automatically
})
If you want to receive notifications on your primary WhatsApp device, set markOnlineOnConnect to false. WhatsApp doesn’t send push notifications to the primary device when a desktop client is marked as online.

Connection health monitoring

Monitor connection health by tracking state changes:
let connectionState = {
    isConnected: false,
    lastConnected: null as Date | null,
    lastDisconnected: null as Date | null,
    disconnectCount: 0
}

sock.ev.on('connection.update', (update) => {
    const { connection } = update
    
    if (connection === 'open') {
        connectionState.isConnected = true
        connectionState.lastConnected = new Date()
        console.log('Connection established at', connectionState.lastConnected)
    } else if (connection === 'close') {
        connectionState.isConnected = false
        connectionState.lastDisconnected = new Date()
        connectionState.disconnectCount++
        
        console.log('Disconnected at', connectionState.lastDisconnected)
        console.log('Total disconnects:', connectionState.disconnectCount)
    }
})

Graceful shutdown

Properly close the connection when shutting down:
process.on('SIGINT', async () => {
    console.log('Shutting down gracefully...')
    
    // Close the socket
    await sock.logout()
    
    process.exit(0)
})
Use sock.logout() to properly close the session. This prevents the connection from being marked as “Connection Replaced” when restarting.

Next steps

Event system

Learn about handling events and messages

Data store

Implement data storage for messages and contacts

Build docs developers (and LLMs) love