Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/whiskeysockets/baileys/llms.txt

Use this file to discover all available pages before exploring further.

Quick start

This guide walks you through creating a fully functional WhatsApp bot that can connect, authenticate, and respond to messages.

Create your first bot

Let’s build a simple bot that echoes received messages back to the sender.
1

Set up your project

Create a new directory and initialize a Node.js project:
mkdir my-whatsapp-bot
cd my-whatsapp-bot
npm init -y
npm install @whiskeysockets/baileys
npm install -D tsx
2

Create the bot file

Create a file named bot.ts with the following code:
bot.ts
import makeWASocket, { 
  DisconnectReason, 
  useMultiFileAuthState 
} from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'

async function connectToWhatsApp() {
  // Load authentication state from file
  const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
  
  const sock = makeWASocket({
    auth: state
  })

  // Handle connection updates
  sock.ev.on('connection.update', (update) => {
    const { connection, lastDisconnect, qr } = update
    
    if (qr) {
      console.log('QR Code:', qr)
      // You can use qrcode-terminal to display the QR in terminal
    }
    
    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!')
    }
  })

  // Save credentials whenever they update
  sock.ev.on('creds.update', saveCreds)

  // Handle incoming messages
  sock.ev.on('messages.upsert', async ({ messages }) => {
    const message = messages[0]
    
    // Ignore if no message content or if it's from us
    if (!message.message || message.key.fromMe) return

    const text = message.message.conversation || 
                 message.message.extendedTextMessage?.text
    
    if (text) {
      console.log('Received message:', text)
      
      // Send a reply
      await sock.sendMessage(
        message.key.remoteJid!, 
        { text: `You said: ${text}` }
      )
    }
  })
}

// Start the bot
connectToWhatsApp()
3

Run your bot

Start the bot using tsx:
npx tsx bot.ts
A QR code will appear in your terminal.
4

Scan the QR code

  1. Open WhatsApp on your phone
  2. Go to Settings > Linked Devices
  3. Tap Link a Device
  4. Scan the QR code displayed in your terminal
The authentication session will be saved in the auth_info_baileys folder. You won’t need to scan the QR code again on subsequent runs.
5

Test your bot

Send a message to your WhatsApp number from another device or contact. Your bot should echo it back!

Using pairing codes

Instead of QR codes, you can authenticate using a pairing code:
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
import readline from 'readline'

const rl = readline.createInterface({ 
  input: process.stdin, 
  output: process.stdout 
})

const question = (text: string) => 
  new Promise<string>((resolve) => rl.question(text, resolve))

async function connectWithPairingCode() {
  const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
  
  const sock = makeWASocket({
    auth: state
  })

  // Request pairing code if not registered
  if (!sock.authState.creds.registered) {
    const phoneNumber = await question('Enter your phone number: ')
    const code = await sock.requestPairingCode(phoneNumber)
    console.log('Pairing code:', code)
  }

  sock.ev.on('creds.update', saveCreds)
  
  // ... rest of your event handlers
}

connectWithPairingCode()
The phone number must include the country code without +, (), or -. For example: 14155552671 for a US number.

Understanding authentication

Baileys uses useMultiFileAuthState to manage authentication credentials:
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
This function:
  • Loads existing credentials from the specified folder
  • Creates the folder if it doesn’t exist
  • Returns a state object to pass to makeWASocket
  • Returns a saveCreds function to save updates
Always call saveCreds in the creds.update event. Failing to save credentials will cause authentication issues and message delivery failures.

Handling events

Baileys uses an event-driven architecture. Here are the most important events:

Connection updates

sock.ev.on('connection.update', (update) => {
  const { connection, lastDisconnect, qr } = update
  
  if (qr) {
    console.log('QR Code:', qr)
    // Display QR code to user using qrcode-terminal or other method
  }
  
  if (connection === 'close') {
    // Handle disconnection
  } else if (connection === 'open') {
    // Handle successful connection
  }
})

Incoming messages

sock.ev.on('messages.upsert', async ({ messages, type }) => {
  for (const message of messages) {
    // Process each message
    console.log(JSON.stringify(message, null, 2))
  }
})
Always use a loop to process messages from messages.upsert since the array can contain multiple messages.

Message updates

sock.ev.on('messages.update', (updates) => {
  for (const { key, update } of updates) {
    // Handle message status changes (delivered, read, deleted, etc.)
  }
})

Sending messages

Baileys provides a single sendMessage function for all message types:

Text messages

await sock.sendMessage('1234567890@s.whatsapp.net', { 
  text: 'Hello, World!' 
})

Media messages

import fs from 'fs'

// Image
await sock.sendMessage(jid, {
  image: { url: './photo.jpg' },
  caption: 'Check out this image!'
})

// Video
await sock.sendMessage(jid, {
  video: fs.readFileSync('./video.mp4'),
  caption: 'Watch this!'
})

// Audio
await sock.sendMessage(jid, {
  audio: { url: './audio.ogg' },
  mimetype: 'audio/ogg; codecs=opus'
})
You can pass media as { url: string }, { stream: Stream }, or directly as a Buffer. Using streams or URLs is more memory-efficient.

Replying to messages

await sock.sendMessage(
  jid,
  { text: 'This is a reply' },
  { quoted: message }
)

Understanding WhatsApp IDs

WhatsApp uses JIDs (Jabber IDs) to identify users and groups:
  • Individual users: [country code][number]@s.whatsapp.net
    Example: 14155552671@s.whatsapp.net
  • Groups: [group-id]@g.us
    Example: 120363123456789012@g.us
  • Broadcast lists: [timestamp]@broadcast
  • Status/Stories: status@broadcast
You can extract the JID from a message using message.key.remoteJid.

Next steps

Now that you have a working bot, explore more advanced features:

Sending messages

Learn about all message types and options

Events

Master the event system for building complex bots

Groups

Work with group chats and management

Configuration

Optimize your socket configuration