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 = 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/baileysInstallation
bash
# NPM
npm install @whiskeysockets/baileys
# Yarn
yarn add @whiskeysockets/baileys
# Dependencies
npm install qrcode-terminal pinoBasic 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); // MembersCreate 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-scan3. Graceful Shutdown
javascript
process.on('SIGINT', async () => {
console.log('Shutting down...');
await sock.logout();
process.exit(0);
});FAQ
Apakah Baileys legal?
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!
| Pro | Con |
|---|---|
| Free | Unofficial |
| Feature-rich | Risk of ban |
| Active community | No official support |
| Multi-device | ToS violation |
Great for learning & small projects!