Baileys WhatsApp API: Library Node.js Populer

Tutorial Baileys WhatsApp API untuk Node.js. Setup, kirim pesan, terima pesan, multi-device. Library unofficial terpopuler!

Baileys WhatsApp API
Baileys WhatsApp API

Baileys = Library WhatsApp API paling populer untuk Node.js!

Unofficial, tapi powerful dan actively maintained. Banyak developer pakai untuk bot.


Apa Itu Baileys?

- Library Node.js untuk WhatsApp Web API
- Unofficial (bukan dari Meta)
- Open source (MIT license)
- Support multi-device
- Actively maintained
- Dipakai ribuan developer

GitHub: @whiskeysockets/baileys

Installation

bash

# NPM
npm install @whiskeysockets/baileys

# Yarn
yarn add @whiskeysockets/baileys

# Dependencies
npm install qrcode-terminal pino

Basic Setup

javascript

const { 
    makeWASocket, 
    useMultiFileAuthState,
    DisconnectReason 
} = require('@whiskeysockets/baileys');
const pino = require('pino');

async function startBot() {
    // Auth state untuk persist session
    const { state, saveCreds } = await useMultiFileAuthState('./auth_info');
    
    // Create socket connection
    const sock = makeWASocket({
        auth: state,
        printQRInTerminal: true,
        logger: pino({ level: 'silent' })
    });
    
    // Save credentials saat update
    sock.ev.on('creds.update', saveCreds);
    
    // Handle connection updates
    sock.ev.on('connection.update', (update) => {
        const { connection, lastDisconnect, qr } = update;
        
        if (qr) {
            console.log('Scan QR code untuk connect!');
        }
        
        if (connection === 'close') {
            const shouldReconnect = 
                lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
            
            if (shouldReconnect) {
                console.log('Reconnecting...');
                startBot();
            } else {
                console.log('Logged out. Delete auth_info dan scan ulang.');
            }
        } else if (connection === 'open') {
            console.log('Bot connected! ✅');
        }
    });
    
    return sock;
}

startBot();

Kirim Pesan

Text Message:

javascript

async function sendText(sock, to, text) {
    const jid = to.includes('@s.whatsapp.net') ? to : `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, { text: text });
}

// Usage
await sendText(sock, '628123456789', 'Hello from Baileys!');

Image:

javascript

async function sendImage(sock, to, imageUrl, caption) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        image: { url: imageUrl },
        caption: caption
    });
}

// Atau dari file lokal
async function sendImageFile(sock, to, filePath, caption) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        image: fs.readFileSync(filePath),
        caption: caption
    });
}

Document:

javascript

async function sendDocument(sock, to, filePath, filename) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        document: fs.readFileSync(filePath),
        fileName: filename,
        mimetype: 'application/pdf'
    });
}

Buttons:

javascript

async function sendButtons(sock, to, text, buttons) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        text: text,
        buttons: buttons.map((btn, i) => ({
            buttonId: `btn_${i}`,
            buttonText: { displayText: btn },
            type: 1
        })),
        headerType: 1
    });
}

// Usage
await sendButtons(sock, '628123456789', 'Pilih menu:', ['Order', 'Katalog', 'Bantuan']);

Location:

javascript

async function sendLocation(sock, to, lat, long, name) {
    const jid = `${to}@s.whatsapp.net`;
    
    await sock.sendMessage(jid, {
        location: {
            degreesLatitude: lat,
            degreesLongitude: long,
            name: name
        }
    });
}

Terima Pesan

javascript

sock.ev.on('messages.upsert', async (m) => {
    const message = m.messages[0];
    
    // Ignore status updates & own messages
    if (!message.message || message.key.fromMe) return;
    
    const from = message.key.remoteJid;
    const sender = message.pushName || 'Unknown';
    
    // Get message content
    const messageType = Object.keys(message.message)[0];
    
    let text = '';
    
    switch (messageType) {
        case 'conversation':
            text = message.message.conversation;
            break;
        case 'extendedTextMessage':
            text = message.message.extendedTextMessage.text;
            break;
        case 'imageMessage':
            text = message.message.imageMessage.caption || '[Image]';
            break;
        case 'documentMessage':
            text = message.message.documentMessage.fileName || '[Document]';
            break;
    }
    
    console.log(`[${sender}]: ${text}`);
    
    // Process message
    await handleMessage(sock, from, text, sender);
});

async function handleMessage(sock, from, text, sender) {
    const lowerText = text.toLowerCase();
    
    if (lowerText === 'hi' || lowerText === 'hello') {
        await sock.sendMessage(from, { 
            text: `Hai ${sender}! 👋 Ada yang bisa dibantu?` 
        });
    }
    
    if (lowerText === 'menu') {
        await sock.sendMessage(from, {
            text: `📋 MENU\n\n1. Katalog\n2. Harga\n3. Order\n4. Bantuan\n\nKetik angka untuk pilih!`
        });
    }
}

Fitur Lanjutan

Reply to Message:

javascript

async function replyToMessage(sock, message, text) {
    await sock.sendMessage(message.key.remoteJid, {
        text: text
    }, {
        quoted: message
    });
}

Read Receipt:

javascript

// Mark as read
await sock.readMessages([message.key]);

Typing Indicator:

javascript

// Show typing...
await sock.sendPresenceUpdate('composing', from);

// Delay untuk natural feel
await new Promise(r => setTimeout(r, 2000));

// Send message
await sock.sendMessage(from, { text: 'Response!' });

// Clear typing
await sock.sendPresenceUpdate('paused', from);

Download Media:

javascript

const { downloadMediaMessage } = require('@whiskeysockets/baileys');

sock.ev.on('messages.upsert', async (m) => {
    const message = m.messages[0];
    
    if (message.message?.imageMessage) {
        const buffer = await downloadMediaMessage(
            message,
            'buffer',
            {},
            { 
                logger: pino({ level: 'silent' }),
                reuploadRequest: sock.updateMediaMessage
            }
        );
        
        // Save to file
        fs.writeFileSync('./downloaded_image.jpg', buffer);
    }
});

Group Features

Send to Group:

javascript

// Group JID format: [email protected]
await sock.sendMessage('[email protected]', { text: 'Hello group!' });

Get Group Info:

javascript

const groupMetadata = await sock.groupMetadata('[email protected]');
console.log(groupMetadata.subject); // Group name
console.log(groupMetadata.participants); // Members

Create Group:

javascript

const group = await sock.groupCreate('Group Name', [
    '[email protected]',
    '[email protected]'
]);
console.log('Group created:', group.id);

Error Handling

javascript

sock.ev.on('connection.update', (update) => {
    const { connection, lastDisconnect } = update;
    
    if (connection === 'close') {
        const statusCode = lastDisconnect?.error?.output?.statusCode;
        
        switch (statusCode) {
            case DisconnectReason.loggedOut:
                console.log('Logged out. Re-scan QR needed.');
                // Delete auth_info folder
                break;
                
            case DisconnectReason.connectionClosed:
            case DisconnectReason.connectionLost:
            case DisconnectReason.timedOut:
                console.log('Connection lost. Reconnecting...');
                startBot();
                break;
                
            case DisconnectReason.restartRequired:
                console.log('Restart required.');
                startBot();
                break;
                
            default:
                console.log('Unknown disconnect:', statusCode);
                startBot();
        }
    }
});

Best Practices

1. Rate Limiting

javascript

const messageQueue = [];
let isProcessing = false;

async function queueMessage(to, content) {
    messageQueue.push({ to, content });
    processQueue();
}

async function processQueue() {
    if (isProcessing || messageQueue.length === 0) return;
    
    isProcessing = true;
    
    while (messageQueue.length > 0) {
        const { to, content } = messageQueue.shift();
        await sock.sendMessage(to, content);
        await new Promise(r => setTimeout(r, 3000)); // 3 sec delay
    }
    
    isProcessing = false;
}

2. Session Persistence

javascript

// Selalu gunakan useMultiFileAuthState
const { state, saveCreds } = await useMultiFileAuthState('./auth_info');

// Jangan delete auth_info kecuali mau re-scan

3. Graceful Shutdown

javascript

process.on('SIGINT', async () => {
    console.log('Shutting down...');
    await sock.logout();
    process.exit(0);
});

FAQ

Gray area. Unofficial API melanggar ToS WhatsApp. Risiko banned ada. Gunakan dengan bijak.

Kenapa reconnect terus?

Check: Internet stable? Auth valid? WhatsApp Web logged out? Try delete auth_info dan re-scan.

Bisa untuk production?

Bisa, tapi dengan risiko. Untuk bisnis serius, pertimbangkan Official Cloud API.


Kesimpulan

Baileys = Powerful unofficial library!

ProCon
FreeUnofficial
Feature-richRisk of ban
Active communityNo official support
Multi-deviceToS violation

Great for learning & small projects!

Build Bot dengan Baileys →


Artikel Terkait