A professionally enhanced, feature-rich fork of the Baileys WhatsApp Web API. Built for developers who need robust, stable WhatsApp automation with extended message types, improved connection handling, and comprehensive documentation.
Maintainer: π±π‘_ππ₯π’π§ππ¨π§ β
- β¨ Features
- π¦ Installation
- π Quick Start
- π Connection & Configuration
- πΎ Authentication State Management
- π€ Sending Messages
- π Chat & Message Management
- π₯ Group Management
- π€ User & Profile Management
- π‘ Newsletter / Channel Management
- π Privacy & Block Management
- ποΈ Data Store Implementation
- π οΈ Utility Functions
- π‘ Best Practices & Tips
β οΈ Important Legal Notice- π Getting Help
- π License
- π Modern & Fast β Latest WA version
[2,3000,1035194821], optimised pre-key upload (812 keys) - π§ Enhanced Stability β Improved connection handling, rate-limit backoff, 5 s keepAlive grace
- π± Multi-Device Support β Full WhatsApp multi-device protocol with improved
historySyncConfig - π End-to-End Encryption β Signal Protocol,
inlineInitialPayloadInE2EeMsg: true - π¨ Extended Message Types β Interactive, album, event, poll result, group status, payment, product
- π₯ Advanced Group Management β Group controls, group status V2, communities support
- πΎ Flexible Auth β Multi-file auth state with
makeCacheableSignalKeyStore - π‘ Full Newsletter/Channel API β Follow, create, metadata,
newsletterId()helper - π οΈ Developer Friendly β
toxicHandlerexposed on socket, clean API - π WebSocket Improvements β
perMessageDeflate: false, 100 MB max payload
npm install toxic-baileysyarn add toxic-baileysnpm install github:xhclintohn/Baileys{
"dependencies": {
"@whiskeysockets/baileys": "npm:toxic-baileys@latest"
}
}Basic Connection (QR Code)
const { makeWASocket, useMultiFileAuthState, DisconnectReason } = require('toxic-baileys');
const { Boom } = require('@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', ({ connection, lastDisconnect }) => {
if (connection === 'close') {
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
if (shouldReconnect) connectToWhatsApp();
} else if (connection === 'open') {
console.log('Connected!');
}
});
sock.ev.on('messages.upsert', async ({ messages }) => {
for (const m of messages) {
if (!m.message) continue;
console.log('Message:', JSON.stringify(m, undefined, 2));
}
});
sock.ev.on('creds.update', saveCreds);
}
connectToWhatsApp().catch(console.error);Pairing Code (no QR)
const { makeWASocket, useMultiFileAuthState } = require('toxic-baileys');
async function connectWithPairing() {
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys');
const sock = makeWASocket({ auth: state, printQRInTerminal: false });
sock.ev.on('creds.update', saveCreds);
if (!sock.authState.creds.registered) {
const phoneNumber = '254712345678'; // no + or spaces
const code = await sock.requestPairingCode(phoneNumber);
console.log('Pairing Code:', code);
}
}
connectWithPairing().catch(console.error);Full Socket Configuration
const { makeWASocket, Browsers } = require('toxic-baileys');
const NodeCache = require('@cacheable/node-cache');
const groupCache = new NodeCache({ stdTTL: 300, useClones: false });
const sock = makeWASocket({
browser: Browsers.macOS('Chrome'),
syncFullHistory: true,
markOnlineOnConnect: false,
connectTimeoutMs: 60_000,
defaultQueryTimeoutMs: 60_000,
keepAliveIntervalMs: 30_000,
generateHighQualityLinkPreview: true,
cachedGroupMetadata: async (jid) => groupCache.get(jid),
getMessage: async (key) => await yourStore.getMessage(key),
});
sock.ev.on('groups.update', async ([event]) => {
const metadata = await sock.groupMetadata(event.id);
groupCache.set(event.id, metadata);
});Multi-File Auth (Development)
const { makeWASocket, useMultiFileAuthState } = require('toxic-baileys');
const { state, saveCreds } = await useMultiFileAuthState('./auth_info');
const sock = makeWASocket({ auth: state });
sock.ev.on('creds.update', saveCreds);Custom Database Auth (Production)
const { makeWASocket, makeCacheableSignalKeyStore } = require('toxic-baileys');
const myAuthState = {
creds: await db.getAuthCreds(),
keys: makeCacheableSignalKeyStore(await db.getSignalKeys(), console)
};
const sock = makeWASocket({ auth: myAuthState });
sock.ev.on('creds.update', async (creds) => await db.saveAuthCreds(creds));Text, Reply, Mention, Forward, Edit, Delete, React
await sock.sendMessage(jid, { text: 'Hello World!' });
await sock.sendMessage(jid, { text: 'Reply!' }, { quoted: m });
await sock.sendMessage(jid, { text: 'Hi @user!', mentions: ['254712345678@s.whatsapp.net'] });
await sock.sendMessage(jid, { forward: m });
const sent = await sock.sendMessage(jid, { text: 'Original' });
await sock.sendMessage(jid, { text: 'Edited!', edit: sent.key });
await sock.sendMessage(jid, { delete: sent.key });
await sock.sendMessage(jid, { react: { text: 'π₯', key: m.key } });
await sock.sendMessage(jid, { react: { text: '', key: m.key } }); // remove reactionImage, Video, Audio, Document, Sticker, View Once
await sock.sendMessage(jid, { image: { url: './image.jpg' }, caption: 'Caption' });
await sock.sendMessage(jid, { image: fs.readFileSync('./img.jpg') });
await sock.sendMessage(jid, { video: { url: './video.mp4' }, caption: 'Video' });
await sock.sendMessage(jid, { video: { url: './animation.mp4' }, gifPlayback: true });
await sock.sendMessage(jid, { audio: { url: './voice.ogg' }, mimetype: 'audio/ogg; codecs=opus', ptt: true });
await sock.sendMessage(jid, { audio: { url: './song.mp3' }, mimetype: 'audio/mp4' });
await sock.sendMessage(jid, { document: { url: './file.pdf' }, fileName: 'MyDoc.pdf', mimetype: 'application/pdf' });
await sock.sendMessage(jid, { sticker: { url: './sticker.webp' } });
await sock.sendMessage(jid, { image: fs.readFileSync('./img.jpg'), viewOnce: true });Interactive Message with Native Flow Buttons
// Copy button
await sock.sendMessage(jid, {
interactiveMessage: {
header: 'toxic-baileysβ’',
title: 'Hello World',
footer: 'By π±π‘_ππ₯π’π§ππ¨π§ β',
buttons: [
{
name: 'cta_copy',
buttonParamsJson: JSON.stringify({ display_text: 'Copy Code', id: '1', copy_code: 'TOXIC123' })
}
]
}
}, { quoted: m });
// URL button
await sock.sendMessage(jid, {
interactiveMessage: {
header: 'Visit Us',
title: 'toxic-baileys',
footer: 'GitHub',
buttons: [
{
name: 'cta_url',
buttonParamsJson: JSON.stringify({ display_text: 'Open GitHub', url: 'https://github.com/xhclintohn/Baileys' })
}
]
}
}, { quoted: m });
// With image thumbnail
await sock.sendMessage(jid, {
interactiveMessage: {
header: 'With Image',
title: 'toxic-baileysβ’',
footer: 'Best Baileys Fork',
image: { url: 'https://example.com/image.jpg' },
buttons: [
{ name: 'cta_copy', buttonParamsJson: JSON.stringify({ display_text: 'Copy', id: '1', copy_code: 'HELLO' }) }
]
}
}, { quoted: m });
// Single select list
await sock.sendMessage(jid, {
interactiveMessage: {
header: 'Choose',
title: 'Menu',
footer: 'Select below',
nativeFlowMessage: {
buttons: [
{
name: 'single_select',
buttonParamsJson: JSON.stringify({
title: 'Options',
sections: [
{
title: 'Commands',
rows: [
{ title: 'Option 1', description: 'First', id: 'opt_1' },
{ title: 'Option 2', description: 'Second', id: 'opt_2' }
]
}
]
})
}
]
}
}
}, { quoted: m });
// With externalAdReply
await sock.sendMessage(jid, {
interactiveMessage: {
header: 'Premium',
title: 'toxic-baileysβ’',
footer: 'By π±π‘_ππ₯π’π§ππ¨π§',
externalAdReply: {
title: 'toxic-baileys',
body: 'Best WhatsApp Library',
mediaType: 1,
thumbnailUrl: 'https://example.com/thumb.jpg',
sourceUrl: 'https://github.com/xhclintohn/Baileys',
showAdAttribution: true,
renderLargerThumbnail: true
},
buttons: [
{ name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Visit', url: 'https://github.com/xhclintohn/Baileys' }) }
]
}
}, { quoted: m });
// Interactive with document
await sock.sendMessage(jid, {
interactiveMessage: {
header: 'Document',
title: 'File',
footer: 'toxic-baileysβ’',
document: fs.readFileSync('./file.pdf'),
mimetype: 'application/pdf',
fileName: 'document.pdf',
buttons: [
{ name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'GitHub', url: 'https://github.com/xhclintohn/Baileys' }) }
]
}
}, { quoted: m });Send multiple images/videos in a single album
await sock.sendMessage(jid, {
albumMessage: [
{ image: fs.readFileSync('./photo1.jpg'), caption: 'First photo' },
{ image: { url: 'https://example.com/photo2.jpg' }, caption: 'Second photo' },
{ video: fs.readFileSync('./clip.mp4'), caption: 'A video clip' }
]
}, { quoted: m });Send WhatsApp event invitations
await sock.sendMessage(jid, {
eventMessage: {
isCanceled: false,
name: 'toxic-baileys Launch',
description: 'Join us for the launch!',
location: { degreesLatitude: -1.2921, degreesLongitude: 36.8219, name: 'Nairobi, Kenya' },
joinLink: 'https://call.whatsapp.com/video/your-link',
startTime: String(Math.floor(Date.now() / 1000) + 3600),
endTime: String(Math.floor(Date.now() / 1000) + 7200),
extraGuestsAllowed: true
}
}, { quoted: m });Polls and displaying poll results
// Create poll
await sock.sendMessage(jid, {
poll: {
name: 'Best WhatsApp library?',
values: ['toxic-baileys', 'Baileys', 'Other'],
selectableCount: 1
}
});
// Display poll results
await sock.sendMessage(jid, {
pollResultMessage: {
name: 'Best Library Results',
pollVotes: [
{ optionName: 'toxic-baileys', optionVoteCount: '42' },
{ optionName: 'Baileys', optionVoteCount: '10' },
{ optionName: 'Other', optionVoteCount: '2' }
]
}
}, { quoted: m });Post status to a group
await sock.sendMessage(groupJid, { groupStatusMessage: { text: 'Hello group! π' } });
await sock.sendMessage(groupJid, { groupStatusMessage: { image: fs.readFileSync('./banner.jpg'), caption: 'Update!' } });
await sock.sendMessage(groupJid, { groupStatusMessage: { video: fs.readFileSync('./promo.mp4'), caption: 'Promo' } });
await sock.sendMessage(groupJid, { groupStatusMessage: { audio: fs.readFileSync('./audio.mp4'), mimetype: 'audio/mp4' } });Send payment requests
await sock.sendMessage(jid, {
requestPaymentMessage: {
currency: 'KES',
amount: 500000,
from: m.sender,
background: { id: 'DEFAULT', placeholderArgb: 0xFFF0F0F0 }
}
}, { quoted: m });Send product catalog messages
await sock.sendMessage(jid, {
productMessage: {
title: 'Premium Script',
description: 'Best bot script available',
thumbnail: { url: 'https://example.com/product.jpg' },
productId: 'PROD001',
retailerId: 'xhclinton',
url: 'https://github.com/xhclintohn/Baileys',
body: 'Full featured automation',
footer: 'Special price',
priceAmount1000: 10000,
currencyCode: 'USD',
buttons: [{ name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Buy Now', url: 'https://github.com/xhclintohn/Baileys' }) }]
}
}, { quoted: m });Classic buttons, list messages, template buttons
// Classic buttons
await sock.sendMessage(jid, {
text: 'Choose:',
footer: 'toxic-baileysβ’',
buttons: [
{ buttonId: 'btn_1', buttonText: { displayText: 'Option 1' }, type: 1 },
{ buttonId: 'btn_2', buttonText: { displayText: 'Option 2' }, type: 1 }
],
headerType: 1
});
// List message
await sock.sendMessage(jid, {
text: 'Select an item:',
footer: 'toxic-baileysβ’',
title: 'Main Menu',
buttonText: 'Open Menu',
sections: [
{
title: 'Commands',
rows: [
{ title: '!help', rowId: 'help', description: 'Show help' },
{ title: '!ping', rowId: 'ping', description: 'Check bot' }
]
}
]
});
// Template buttons
await sock.sendMessage(jid, {
text: 'Quick actions:',
footer: 'toxic-baileysβ’',
templateButtons: [
{ index: 1, urlButton: { displayText: 'π GitHub', url: 'https://github.com/xhclintohn/Baileys' } },
{ index: 2, callButton: { displayText: 'π Call', phoneNumber: '+254712345678' } },
{ index: 3, quickReplyButton: { displayText: 'β
OK', id: 'ok_reply' } }
]
});Send status with mentions
// Send status and mention specific contacts/groups
await sock.sendStatusMention(
{ text: 'Hello everyone! π', backgroundColor: '#FF5733' },
['254712345678@s.whatsapp.net', groupJid]
);
// Media status with mention
await sock.sendStatusMention(
{ image: fs.readFileSync('./banner.jpg'), caption: 'New update!' },
['254712345678@s.whatsapp.net']
);Chat Operations
await sock.chatModify({ archive: true }, jid);
await sock.chatModify({ archive: false }, jid);
await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid);
await sock.chatModify({ mute: null }, jid);
await sock.chatModify({ pin: true }, jid);
await sock.chatModify({ pin: false }, jid);
await sock.chatModify({ markRead: true }, jid);
await sock.chatModify({ markRead: false }, jid);
await sock.readMessages([m.key]);
const { downloadMediaMessage } = require('toxic-baileys');
const buffer = await downloadMediaMessage(m, 'buffer', {}, { logger: console });
fs.writeFileSync('./download.jpg', buffer);Group Operations
const group = await sock.groupCreate('My Group', ['254712345678@s.whatsapp.net']);
await sock.groupParticipantsUpdate(groupJid, ['254712345678@s.whatsapp.net'], 'add');
await sock.groupParticipantsUpdate(groupJid, ['254712345678@s.whatsapp.net'], 'remove');
await sock.groupParticipantsUpdate(groupJid, ['254712345678@s.whatsapp.net'], 'promote');
await sock.groupParticipantsUpdate(groupJid, ['254712345678@s.whatsapp.net'], 'demote');
await sock.groupUpdateSubject(groupJid, 'New Group Name');
await sock.groupUpdateDescription(groupJid, 'New description');
await sock.groupSettingUpdate(groupJid, 'announcement');
await sock.groupSettingUpdate(groupJid, 'not_announcement');
await sock.groupSettingUpdate(groupJid, 'locked');
await sock.groupSettingUpdate(groupJid, 'unlocked');
const code = await sock.groupInviteCode(groupJid);
await sock.groupAcceptInvite('INVITE_CODE');
const meta = await sock.groupMetadata(groupJid);
await sock.groupLeave(groupJid);
await sock.setLabelGroup(groupJid, 'VIP');Profile & Presence Operations
const [result] = await sock.onWhatsApp('254712345678');
console.log(result.exists, result.jid);
const status = await sock.checkWhatsApp('254712345678@s.whatsapp.net');
console.log(status.isBanned, status.isNeedOfficialWa);
const ppUrl = await sock.profilePictureUrl(jid, 'image');
await sock.updateProfileName('My New Name');
await sock.updateProfileStatus('Powered by toxic-baileysβ’ π');
await sock.updateProfilePicture(sock.user.id, fs.readFileSync('./avatar.jpg'));
sock.ev.on('presence.update', ({ id, presences }) => console.log(id, presences));
await sock.presenceSubscribe(jid);
const biz = await sock.getBusinessProfile(jid);Full Newsletter / Channel API
// Get ID from URL (unique to toxic-baileys)
const info = await sock.newsletterId('https://whatsapp.com/channel/YOUR_CODE');
console.log(JSON.parse(info)); // { name, id }
// Get full metadata from URL
const meta = await sock.newsletterFromUrl('https://whatsapp.com/channel/YOUR_CODE');
// Full metadata by JID
const fullMeta = await sock.newsletterMetadata('jid', '120363427340708111@newsletter');
// Follow / unfollow / mute / unmute
await sock.newsletterFollow('120363427340708111@newsletter');
await sock.newsletterUnfollow('120363427340708111@newsletter');
await sock.newsletterMute('120363427340708111@newsletter');
await sock.newsletterUnmute('120363427340708111@newsletter');
// Create a newsletter
const channel = await sock.newsletterCreate('My Channel', 'Description', 'ALL');
// Update
await sock.newsletterUpdateName('120363427340708111@newsletter', 'New Name');
await sock.newsletterUpdateDescription('120363427340708111@newsletter', 'New description');
await sock.newsletterUpdatePicture('120363427340708111@newsletter', fs.readFileSync('./pic.jpg'));
await sock.newsletterRemovePicture('120363427340708111@newsletter');
// React to a newsletter message
await sock.newsletterReactMessage('120363427340708111@newsletter', serverMessageId, 'π₯');
// Fetch messages
const msgs = await sock.newsletterFetchMessages('jid', '120363427340708111@newsletter', 10);
// Get all subscribed newsletters
const subscribed = await sock.newsletterFetchAllSubscribe();
// Subscribe to live updates
await sock.subscribeNewsletterUpdates('120363427340708111@newsletter');
// Delete newsletter
await sock.newsletterDelete('120363427340708111@newsletter');Privacy Settings & Block List
await sock.updateLastSeenPrivacy('contacts'); // 'all' | 'contacts' | 'contact_blacklist' | 'none'
await sock.updateOnlinePrivacy('match_last_seen');
await sock.updateProfilePicturePrivacy('contacts');
await sock.updateStatusPrivacy('contacts');
await sock.updateReadReceiptsPrivacy('all'); // 'all' | 'none'
await sock.updateGroupsAddPrivacy('contacts');
const privacy = await sock.fetchPrivacySettings(true);
await sock.updateBlockStatus(jid, 'block');
await sock.updateBlockStatus(jid, 'unblock');
const blocked = await sock.fetchBlocklist();In-Memory Store (Development)
const { makeInMemoryStore } = require('toxic-baileys');
const store = makeInMemoryStore({ logger: console });
store.readFromFile('./baileys_store.json');
setInterval(() => store.writeToFile('./baileys_store.json'), 10_000);
const sock = makeWASocket({});
store.bind(sock.ev);Using toxicHandler Directly
// toxicHandler is exposed on the socket for advanced usage
const { toxicHandler } = sock;
const paymentContent = await toxicHandler.handlePayment(content, quoted);
const interactiveContent = await toxicHandler.handleInteractive(content, jid, quoted);
const albumResult = await toxicHandler.handleAlbum(content, jid, quoted);
const eventResult = await toxicHandler.handleEvent(content, jid, quoted);
const pollResult = await toxicHandler.handlePollResult(content, jid, quoted);
const storyResult = await toxicHandler.handleGroupStory(content, jid, quoted);Core Utilities
const {
getContentType, areJidsSameUser, isJidGroup, isJidBroadcast,
isJidStatusBroadcast, isJidNewsLetter, jidNormalizedUser,
generateMessageID, generateMessageIDV2, generateWAMessage,
generateWAMessageContent, generateWAMessageFromContent,
downloadContentFromMessage, getAggregateVotesInPollMessage,
extractMessageContent, normalizeMessageContent, proto
} = require('toxic-baileys');
const type = getContentType(m.message);
console.log(isJidGroup('123@g.us')); // true
console.log(isJidNewsLetter('123@newsletter')); // true
const votes = getAggregateVotesInPollMessage(
{ message: pollMsg.message, pollUpdates },
sock.user.id
);
const stream = await downloadContentFromMessage(m.message.imageMessage, 'image');
const chunks = [];
for await (const chunk of stream) chunks.push(chunk);
const buffer = Buffer.concat(chunks);- Always implement reconnect logic on
connection === 'close' - Cache group metadata using
cachedGroupMetadata - Use
markOnlineOnConnect: falseto still receive phone notifications - Set
syncFullHistory: truefor complete history
- Use
@cacheable/node-cachefor group metadata caching - Implement a message queue with rate limiting for bulk sends
- Use databases instead of in-memory store for production
Auto-reconnect pattern
async function connectWithRetry(maxRetries = 10) {
let attempt = 0;
const connect = async () => {
attempt++;
try {
const { state, saveCreds } = await useMultiFileAuthState('./auth');
const sock = makeWASocket({ auth: state });
sock.ev.on('creds.update', saveCreds);
sock.ev.on('connection.update', async ({ connection, lastDisconnect }) => {
if (connection === 'close') {
const code = lastDisconnect?.error?.output?.statusCode;
if (code === DisconnectReason.loggedOut) return;
const delay = Math.min(5000 * attempt, 60000);
if (attempt < maxRetries) setTimeout(connect, delay);
} else if (connection === 'open') {
attempt = 0;
}
});
} catch (err) {
if (attempt < maxRetries) setTimeout(connect, 5000 * attempt);
}
};
await connect();
}Message queue with rate limiting
class MessageQueue {
constructor(sock, delayMs = 1000) {
this.sock = sock;
this.queue = [];
this.processing = false;
this.delayMs = delayMs;
}
async add(jid, content, options = {}) {
this.queue.push({ jid, content, options });
if (!this.processing) this._process();
}
async _process() {
this.processing = true;
while (this.queue.length > 0) {
const { jid, content, options } = this.queue.shift();
try {
await this.sock.sendMessage(jid, content, options);
await new Promise(r => setTimeout(r, this.delayMs));
} catch (err) {
console.error('Send failed:', err.message);
}
}
this.processing = false;
}
}
const queue = new MessageQueue(sock, 1500);
await queue.add(jid, { text: 'Message 1' });
await queue.add(jid, { text: 'Message 2' });This project is NOT affiliated with, authorized, maintained, sponsored, or endorsed by WhatsApp LLC or any of its affiliates.
- Only message users who have explicitly consented
- Do NOT use for spamming, bulk unsolicited messaging, or harassment
- Respect WhatsApp's Terms of Service and rate limits
- The maintainer assumes NO liability for misuse or damages
- GitHub Issues β github.com/xhclintohn/Baileys/issues
- WhatsApp β +254735342808
- Response Time β Typically within 24β48 hours
MIT License. See LICENSE for details.
Credits: Original Baileys by WhiskeySockets Β· toxic-baileys enhancements by π±π‘_ππ₯π’π§ππ¨π§ β
π toxic-baileysβ’ β Crafted with β€οΈ by π±π‘_ππ₯π’π§ππ¨π§ β
The most powerful WhatsApp automation toolkit
β Star the repository if this helped you!