
Security News
AI Agent Lands PRs in Major OSS Projects, Targets Maintainers via Cold Outreach
An AI agent is merging PRs into major OSS projects and cold-emailing maintainers to drum up more work.
@chatunity/baileystest
Advanced tools
The developers of Baileys and its maintainers cannot be held responsible for misuse of the application, as indicated in the MIT License.
The team does not approve any use that violates WhatsApp's Terms of Service. Every user is invited to act responsibly and use the tool only for its intended purposes.
[!IMPORTANT]
The original repository was removed by the main author – development continues officially in this new community-maintained version.
You can check out and run the example available in example.ts to see practical usage of the library.
The script demonstrates the most common use cases.
To run it:
cd path/to/Baileysyarnyarn exampleUse the stable version:
yarn add @chatunitycenter/baileys
Use the edge version (no guarantee of stability, but latest fixes + features)
yarn add github:chatunitycenter/baileys
Then import in your code using:
import makeWASocket from '@chatunitycenter/baileys'
WhatsApp provides a multi-device system that allows Baileys to authenticate as a second WhatsApp client via QR code or Pairing Code scanned from the app on your phone.
[!NOTE] Here you'll find a simple event handling example
[!TIP] You can view all supported socket configurations here (Recommended)
[!TIP] If you connect via QR-CODE, you can customize the browser name using the
Browserconstant. Several predefined configurations are available, viewable here.
import makeWASocket from '@chatunitycenter/baileys'
const sock = makeWASocket({
browser: Browsers.ubuntu('My App'),
printQRInTerminal: true
})
If the connection is successful, you will see a QR code printed on your terminal screen. Scan it with WhatsApp on your phone and you'll be logged in!
[!IMPORTANT] Pairing Code is not Mobile API; it's a method to connect WhatsApp Web without QR-CODE. You can only connect with one device, see here
The phone number cannot have +, (), or -, only numbers. You must provide country code.
import makeWASocket from '@chatunitycenter/baileys'
const chatunity = makeWASocket({
printQRInTerminal: false // must be false
})
if (!chatunity.authState.creds.registered) {
const number = 'XXXXXXXXXXX'
const code = await chatunity.requestPairingCode(number)
console.log(code)
}
syncFullHistory to trueconst chatunity = makeWASocket({
browser: Browsers.macOS('Desktop'),
syncFullHistory: true
})
If you use Baileys for groups, we recommend setting cachedGroupMetadata in socket config:
const groupCache = new NodeCache({stdTTL: 5 * 60, useClones: false})
const chatunity = makeWASocket({
cachedGroupMetadata: async (jid) => groupCache.get(jid)
})
chatunity.ev.on('groups.update', async ([event]) => {
const metadata = await chatunity.groupMetadata(event.id)
groupCache.set(event.id, metadata)
})
chatunity.ev.on('group-participants.update', async (event) => {
const metadata = await chatunity.groupMetadata(event.id)
groupCache.set(event.id, metadata)
})
To improve message sending, retrying on errors, and decrypt poll votes, set up a store with getMessage config:
const chatunity = makeWASocket({
getMessage: async (key) => await getMessageFromStore(key)
})
To receive notifications in the WhatsApp app, set markOnlineOnConnect to false:
const chatunity = makeWASocket({
markOnlineOnConnect: false
})
You don't need to scan the QR code every time you connect. Load credentials to log back in:
import makeWASocket, { useMultiFileAuthState } from '@chatunitycenter/baileys'
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
const chatunity = makeWASocket({ auth: state })
chatunity.ev.on('creds.update', saveCreds)
[!IMPORTANT]
useMultiFileAuthStateis a utility function to help save the auth state in a folder. This serves as a good guide for implementing auth & key states for SQL/NoSQL databases, which is recommended for production systems.
[!NOTE] When messages are received/sent, auth keys need updating. You must save updated keys. The
useMultiFileAuthStatefunction handles this automatically, but for other implementations you must be careful with key state management.
import makeWASocket, { useSingleFileAuthState, useMongoFileAuthState } from '@chatunitycenter/baileys'
// Single File Auth
const { state, saveState } = await useSingleFileAuthState('./auth_info_baileys.json')
const chatunity = makeWASocket({ auth: state, printQRInTerminal: true })
chatunity.ev.on('creds.update', saveState)
// MongoDB Auth
import { MongoClient } from "mongodb"
const connectAuth = async() => {
const client = new MongoClient('mongoURL')
await client.connect()
const collection = client.db("@itchatunitychann").collection("sessions")
return collection
}
const Authentication = await connectAuth()
const { state, saveCreds } = await useMongoFileAuthState(Authentication)
const chatunity = makeWASocket({ auth: state, printQRInTerminal: true })
chatunity.ev.on('creds.update', saveCreds)
Baileys uses the EventEmitter syntax for events with full TypeScript support.
[!IMPORTANT] See all available events here
const chatunity = makeWASocket()
chatunity.ev.on('messages.upsert', ({ messages }) => {
console.log('got messages', messages)
})
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@chatunitycenter/baileys'
import { Boom } from '@hapi/boom'
async function connectToWhatsApp () {
const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys')
const chatunity = makeWASocket({
auth: state,
printQRInTerminal: true
})
chatunity.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('opened connection')
}
})
chatunity.ev.on('messages.upsert', event => {
for (const m of event.messages) {
console.log(JSON.stringify(m, undefined, 2))
console.log('replying to', m.key.remoteJid)
await chatunity.sendMessage(m.key.remoteJid!, { text: 'Hello World' })
}
})
chatunity.ev.on('creds.update', saveCreds)
}
connectToWhatsApp()
[!IMPORTANT] In
messages.upsert, use a loop likefor (const message of event.messages)to handle all messages in the array.
Poll votes are encrypted by default and handled in messages.update:
import pino from "pino"
import { makeInMemoryStore, getAggregateVotesInPollMessage } from '@chatunitycenter/baileys'
const logger = pino({ timestamp: () => `,"time":"${new Date().toJSON()}"` }).child({ class: "@Itchatunitychann" })
logger.level = "fatal"
const store = makeInMemoryStore({ logger })
async function getMessage(key){
if (store) {
const msg = await store.loadMessage(key.remoteJid, key.id)
return msg?.message
}
return { conversation: "Itchatunityi Kawaiii" }
}
chatunity.ev.on("messages.update", async (chatUpdate) => {
for(const { key, update } of chatUpdate) {
if(update.pollUpdates && key.fromMe) {
const pollCreation = await getMessage(key)
if(pollCreation) {
const pollUpdate = await getAggregateVotesInPollMessage({
message: pollCreation,
pollUpdates: update.pollUpdates,
})
const toCmd = pollUpdate.filter(v => v.voters.length !== 0)[0]?.name
if (toCmd == undefined) return
console.log(toCmd)
}
}
}
})
Event responses are encrypted by default and handled in messages.update:
import { jidNormalizedUser, getAggregateResponsesInEventMessage } from '@chatunitycenter/baileys'
chatunity.ev.on("messages.update", async ([chatUpdate]) => {
const eventResponses = chatUpdate.update?.eventResponses
const agregate = getAggregateResponsesInEventMessage({ eventResponses }, jidNormalizedUser(chatunity.user.lid))
console.log(agregate)
})
connection.update is fired requesting socket restartmessaging.history-setBaileys does not include built-in storage for chats, contacts, or messages. However, a simple in-memory implementation is provided:
[!IMPORTANT] We highly recommend building your own data store, as storing entire chat history in memory wastes RAM.
import makeWASocket, { makeInMemoryStore } from '@chatunitycenter/baileys'
const store = makeInMemoryStore({ })
store.readFromFile('./baileys_store.json')
setInterval(() => {
store.writeToFile('./baileys_store.json')
}, 10_000)
const chatunity = makeWASocket({ })
store.bind(chatunity.ev)
chatunity.ev.on('chats.upsert', () => {
console.log('got chats', store.chats.all())
})
chatunity.ev.on('contacts.upsert', () => {
console.log('got contacts', Object.values(store.contacts))
})
id (also called jid) is the WhatsApp ID of the person or group you're messaging.
[country code][phone number]@s.whatsapp.net
+19999999999@s.whatsapp.net123456789-123345@g.us[timestamp of creation]@broadcaststatus@broadcastgetContentType - returns the content type for any messagegetDevice - returns the device from a messagemakeCacheableSignalKeyStore - speeds up auth storedownloadContentFromMessage - downloads content from any messageSend all types of messages with a single function:
await chatunity.sendMessage(jid, content, options)
await chatunity.sendMessage(jid, { text: 'hello world' })
await chatunity.sendMessage(jid, { text: 'hello world' }, { quoted: message })
await chatunity.sendMessage(jid, {
text: '@12345678901',
mentions: ['12345678901@s.whatsapp.net']
})
const msg = getMessageFromStore()
await chatunity.sendMessage(jid, { forward: msg, force: true })
await chatunity.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
}
})
await chatunity.sendMessage(jid, {
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221
},
live: true
})
const vcard = 'BEGIN:VCARD\n'
+ 'VERSION:3.0\n'
+ 'FN:Jeff Singh\n'
+ 'ORG:Ashoka Uni\n'
+ 'TEL;type=CELL;type=VOICE;waid=911234567890:+91 12345 67890\n'
+ 'END:VCARD'
await chatunity.sendMessage(id, {
contacts: {
displayName: 'Itchatunitychann',
contacts: [{ vcard }]
}
})
await chatunity.sendMessage(jid, {
react: {
text: '💖',
key: message.key
}
})
await chatunity.sendMessage(jid, {
pin: {
type: 1, // 2 to remove
time: 86400, // 24h in seconds
key: Key
}
})
await chatunity.sendMessage(jid, {
keep: {
key: Key,
type: 1
}
})
await chatunity.sendMessage(jid, {
poll: {
name: 'My Poll',
values: ['Option 1', 'Option 2'],
selectableCount: 1,
toAnnouncementGroup: false
}
})
await chatunity.sendMessage(jid, {
pollResult: {
name: 'Hi',
values: [['Option 1', 1000], ['Option 2', 2000]]
}
})
await chatunity.sendMessage(jid, {
call: {
name: 'Hey',
type: 1 // 2 for video
}
})
await chatunity.sendMessage(jid, {
event: {
isCanceled: false,
name: 'Holiday together!',
description: 'Who wants to come along?',
location: {
degreesLatitude: 24.121231,
degreesLongitude: 55.1121221,
name: 'Location name'
},
call: 'audio',
startTime: number,
endTime: number,
extraGuestsAllowed: true
}
})
await chatunity.sendMessage(jid, {
order: {
orderId: '574xxx',
thumbnail: 'your_thumbnail',
itemCount: 'your_count',
status: 'INQUIRY',
surface: 'CATALOG',
message: 'your_caption',
orderTitle: "your_title",
sellerJid: 'your_jid',
token: 'your_token',
totalAmount1000: 'your_amount',
totalCurrencyCode: 'IDR'
}
})
await chatunity.sendMessage(jid, {
product: {
productImage: { url: 'your_url' },
productId: 'your_id',
title: 'your_title',
description: 'your_description',
currencyCode: 'IDR',
priceAmount1000: 'your_amount',
url: 'your_url',
productImageCount: 'your_imageCount'
},
businessOwnerJid: 'your_jid'
})
await chatunity.sendMessage(jid, {
payment: {
note: 'Hi!',
currency: 'IDR',
amount: '10000',
expiry: 0
}
})
await chatunity.sendMessage(id, {
paymentInvite: {
type: 1,
expiry: 0
}
})
await chatunity.sendMessage(jid, {
adminInvite: {
jid: '123xxx@newsletter',
name: 'newsletter_name',
caption: 'Please be my channel admin',
expiration: 86400
}
})
await chatunity.sendMessage(jid, {
groupInvite: {
jid: '123xxx@g.us',
name: 'group_name',
caption: 'Please Join My WhatsApp Group',
code: 'code_invite',
expiration: 86400
}
})
await chatunity.sendMessage(jid, {
stickerPack: {
name: 'Hiii',
publisher: 'By Itchatunitychann',
description: 'Hello',
cover: Buffer,
stickers: [{
sticker: { url: 'https://example.com/1234kjd.webp' },
emojis: ['❤'],
isLottie: false,
isAnimated: false
}]
}
})
await chatunity.sendMessage(jid, { sharePhoneNumber: {} })
await chatunity.sendMessage(jid, { requestPhoneNumber: {} })
// List
await chatunity.sendMessage(jid, {
buttonReply: {
name: 'Hi',
description: 'description',
rowId: 'ID'
},
type: 'list'
})
// Plain
await chatunity.sendMessage(jid, {
buttonReply: {
displayText: 'Hi',
id: 'ID'
},
type: 'plain'
})
// Template
await chatunity.sendMessage(jid, {
buttonReply: {
displayText: 'Hi',
id: 'ID',
index: 'number'
},
type: 'template'
})
// Interactive
await chatunity.sendMessage(jid, {
buttonReply: {
body: 'Hi',
nativeFlows: {
name: 'menu_options',
paramsJson: JSON.stringify({ id: 'ID', description: 'description' }),
version: 1
}
},
type: 'interactive'
})
await chatunity.sendMessage(jid, {
text: 'This is a button message!',
footer: 'Hello World!',
buttons: [{
buttonId: 'Id1',
buttonText: { displayText: 'Button 1' }
}, {
buttonId: 'Id2',
buttonText: { displayText: 'Button 2' }
}]
})
await chatunity.sendMessage(jid, {
text: 'This is a list!',
footer: 'Hello World!',
title: 'Amazing list title',
buttonText: 'View list',
sections: [{
title: 'Section 1',
rows: [{
title: 'Option 1',
rowId: 'option1'
}, {
title: 'Option 2',
rowId: 'option2',
description: 'Description'
}]
}]
})
await chatunity.sendMessage(jid, {
text: 'This is a list!',
footer: 'Hello World!',
title: 'Product list',
buttonText: 'View list',
productList: [{
title: 'This is a title',
products: [{ productId: '1234' }, { productId: '5678' }]
}],
businessOwnerJid: '628xxx@s.whatsapp.net',
thumbnail: 'https://example.com/image.jpg'
})
await chatunity.sendMessage(jid, {
text: 'Body Message',
title: 'Title Message',
cards: [{
image: { url: 'https://example.com/image.jpg' },
title: 'Card Title',
body: 'Card Body',
footer: 'Card Footer',
buttons: [{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Button',
id: 'ID'
})
}]
}]
})
await chatunity.sendMessage(jid, {
text: 'Interactive message',
title: 'Title',
footer: 'Footer',
interactiveButtons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Click Me!',
id: 'your_id'
})
},
{
name: 'cta_url',
buttonParamsJson: JSON.stringify({
display_text: 'Follow',
url: 'https://whatsapp.com/channel/0029Vag9VSI2ZjCocqa2lB1y'
})
},
{
name: 'cta_call',
buttonParamsJson: JSON.stringify({
display_text: 'Call',
phone_number: '628xxx'
})
},
{
name: 'open_webview',
buttonParamsJson: JSON.stringify({
title: 'Follow',
link: { url: 'https://example.com' }
})
}
]
})
await chatunity.sendMessage(jid, {
text: '',
interactiveButtons: [{
name: 'payment_info',
buttonParamsJson: JSON.stringify({
payment_settings: [{
type: "pix_static_code",
pix_static_code: {
merchant_name: 'Your Name',
key: 'example@email.com',
key_type: 'EMAIL'
}
}]
})
}]
})
await chatunity.sendMessage(jid, {
text: '',
interactiveButtons: [{
name: 'review_and_pay',
buttonParamsJson: JSON.stringify({
currency: 'IDR',
total_amount: { value: '999999999', offset: '100' },
reference_id: '45XXXXX',
type: 'physical-goods',
order: {
status: 'completed',
items: [{
name: 'Product',
amount: { value: '999999999', offset: '100' },
quantity: '1'
}]
}
})
}]
})
const jids = ['123451679@g.us', '62689xxxx@s.whatsapp.net']
// Text
await chatunity.sendStatusMentions(
{
text: 'Hello Everyone :3',
font: 2
},
jids
)
// Image
await chatunity.sendStatusMentions(
{ image: { url: 'https://example.com/image.jpg' } },
jids
)
// Video
await chatunity.sendStatusMentions(
{ video: { url: 'https://example.com/video.mp4' } },
jids
)
await chatunity.sendMessage(jid, {
text: 'Body',
title: 'Title',
footer: 'Footer',
shop: {
surface: 1,
id: 'https://example.com'
},
viewOnce: true
})
await chatunity.sendMessage(jid, {
text: 'Body',
title: 'Title',
footer: 'Footer',
collection: {
bizJid: 'jid',
id: 'https://example.com',
version: 1
},
viewOnce: true
})
Sending media (video, stickers, images) is easier and more efficient.
[!NOTE] You can pass
{ stream: Stream },{ url: Url }, orBufferdirectly. See more here
[!TIP] Use Stream or Url to save memory
await chatunity.sendMessage(jid, {
video: fs.readFileSync('Media/gif.mp4'),
caption: 'hello world',
gifPlayback: true
})
await chatunity.sendMessage(id, {
video: { url: './Media/video.mp4' },
caption: 'hello world'
})
await chatunity.sendMessage(id, {
video: { url: './Media/video.mp4' },
ptv: true
})
Audio needs to be converted to OGG format with ffmpeg:
ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
await chatunity.sendMessage(jid, {
audio: { url: './Media/audio.mp3' },
mimetype: 'audio/mp4'
})
await chatunity.sendMessage(id, {
image: { url: './Media/image.png' },
caption: 'hello world'
})
await chatunity.sendMessage(id, {
album: [{
image: { url: 'https://example.com/image.jpg' },
caption: 'Caption'
}, {
video: { url: 'https://example.com/video.mp4' },
caption: 'Caption'
}]
})
await chatunity.sendMessage(id, {
image: { url: './Media/image.png' },
viewOnce: true,
caption: 'hello world'
})
By default, WhatsApp does not generate link previews when sent from web. Baileys provides this functionality.
To enable link previews, add link-preview-js to your project:
yarn add link-preview-js
Then send a link:
await chatunity.sendMessage(jid, {
text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
})
await chatunity.sendMessage(jid, { text: 'Hi' }, { ai: true })
// With relay
await chatunity.relayMessage(jid, { extendedTextMessage: { text: 'Hi' } }, { AI: true })
const msg = await chatunity.sendMessage(jid, { text: 'hello world' })
await chatunity.sendMessage(jid, { delete: msg.key })
await chatunity.sendMessage(jid, { edit: msg.key, text: 'edited message' })
Thumbnails can be generated automatically for images & stickers if you add jimp or sharp:
yarn add jimp
# or
yarn add sharp
For videos, install ffmpeg on your system.
import { createWriteStream } from 'fs'
import { downloadMediaMessage, getContentType } from '@chatunitycenter/baileys'
chatunity.ev.on('messages.upsert', async ({ messages }) => {
for (const m of messages) {
if (!m.message) return
const messageType = getContentType(m)
if (messageType === 'imageMessage') {
const stream = await downloadMediaMessage(m, 'stream', {}, {
logger,
reuploadRequest: chatunity.updateMediaMessage
})
stream.pipe(createWriteStream('./my-download.jpeg'))
}
}
})
const downloadedContent = await downloadMediaMessage(...)
const uploadedUrl = await chatunity.uploadMedia(downloadedContent)
FAQs
whatsapp api multidevice by ChatUnity
We found that @chatunity/baileystest demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
An AI agent is merging PRs into major OSS projects and cold-emailing maintainers to drum up more work.

Research
/Security News
Chrome extension CL Suite by @CLMasters neutralizes 2FA for Facebook and Meta Business accounts while exfiltrating Business Manager contact and analytics data.

Security News
After Matplotlib rejected an AI-written PR, the agent fired back with a blog post, igniting debate over AI contributions and maintainer burden.