7ucg/baron-baileys-v2
7ucg/baron-baileys-v2 has 39 GitHub stars and 8 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 10:19 UTC. Last push 2026-11-01.
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
About
A high-performance WhatsApp Web library with Rust WASM acceleration
Web & AppsREADME.md
Originalbaron-baileys-v2
This repository is no longer maintained. Development continues at github.com/7ucg/velowa — see that repository for more information.
A high-performance WhatsApp Web library built on Baileys, with critical paths accelerated via a Rust WASM bridge.
See CHANGELOG.md for the full version history.
Index
- What's Different
- Installation
- Connecting Account
- Socket Config Notes
- Saving & Restoring Sessions
- Handling Events
- Anti-Ban System
- Sending Messages
- Modifying Messages
- Manipulating Media
- Groups
- Privacy
- User Queries
- Change Profile
- Chat Modifiers
- MEX — WhatsApp's Internal GraphQL
- Writing Custom Functionality
- Rust WASM Bridge
MEX — WhatsApp's Internal GraphQL
All WhatsApp features (privacy, passkeys, profiles, usernames, integrity checks, …) run over MEX — WhatsApp's GraphQL-over-WebSocket protocol. Every method is available directly on your socket:
// Privacy
await sock.setPrivacySetting('LAST_SEEN', 'CONTACTS') // UPPERCASE enums
await sock.updateGroupsAddPrivacy('contact_blacklist') // lowercase IQ helpers also available
// Contact integrity — verify a JID is on WhatsApp before opening a chat
const result = await sock.contactIntegrityQuery(['[email protected]'])
// Username lookup
const user = await sock.findUserByUsername('baron')
// { jid: '[email protected]', contact: false } or null
// About text
const abouts = await sock.getTextStatusList(['[email protected]'])
// Error handling — all MEX methods throw Boom on failure
try {
await sock.setPrivacySetting('LAST_SEEN', 'NONE')
} catch (err) {
// err.output.statusCode: 400 bad request, 403 not available, 404 not found
}
See MEX.md for full documentation.
Feature Documentation
| Topic | File |
|---|---|
| MEX — WhatsApp's internal GraphQL protocol | MEX.md |
| USync — Bulk user data queries (devices, status, picture, LID) | USYNC.md |
| HTTPS GraphQL — Meta AI, Events, Payments | GRAPHQL.md |
| Privacy, Profile & Account | PRIVACY.md |
| Registration, Passkeys & Account Management | REGISTRATION.md |
| Managed Accounts, Payments Passkey & IPLS | MANAGED-ACCOUNT.md |
| Communities & AI Groups | COMMUNITIES.md |
| Interoperability (BirdyChat, Haiket, DMA) | INTEROP.md |
Username (@username) |
USERNAME.md |
| Anti-Ban System | ANTIBAN.md |
| Ban & Enforcement System (APK internals) | BAN-SYSTEM.md |
| WhatsApp Protocol Reference (APK namespaces) | PROTOCOLS.md |
| WA-Web Protocol Port (chat-block, call links, group settings, coexistence) | WA-WEB-PORT.md |
What's Different
Performance — Rust WASM
| Area | Upstream Baileys | This fork |
|---|---|---|
| Binary decode | JS | Rust WASM |
| Noise handshake | JS | Rust WASM |
| AES / HMAC / HKDF | JS (crypto) |
Rust WASM |
| Signal protocol | libsignal-node |
Rust WASM |
Extra Features
| Feature | Notes |
|---|---|
| Meta AI / msmsg decrypt | Full messageSecret-encrypted AI message decryption |
| Meta AI message handling | Receive and process Meta AI bot responses |
| Rich AI composer | Send tables, lists, code blocks, LaTeX, rich menus (header/body/footer), and raw HTML via Meta AI format |
| Interactive buttons | List, reply, template, cards, product list, PIX/PAY |
| Interop (FB/IG) | Near-parity with mobile & web for cross-platform JIDs |
| Anti-ban measures | Connection fingerprinting aligned with official clients |
| Album messages | Send multiple media as an album |
| Sticker packs | Sticker pack message support |
| Newsletter messages | Follower invite messages |
| WA-Web protocol port | Chat-block toggle, call-link waiting room, community sub-group ops, group sharing settings, spam reporting, TOS acceptance, mex group/newsletter events, account dirty/device-sync events — WA-WEB-PORT.md |
| Top-level call signalling | Emits call for both <call>-wrapped and top-level <offer>/<terminate> stanzas (+ acks them) |
Call callKey |
Incoming offer <enc> Signal-decrypted; call.callKey (raw SRTP key bytes) populated on the call event |
| Waiting room | call.status = 'waiting_room_request' + call.peerJid when a participant enters a call link's waiting room |
| Newsletter status recv | newsletter.status event for server-pushed <status> stanzas: text/media/reaction/revoke, engagement counters, edit timestamps |
| Status audience privacy | sendMessage(jid, content, { statusPrivacy: 'contacts' | 'allowlist' | 'denylist' }) controls who receives a status broadcast |
| WAM telemetry | Login and WebcSocketConnect WAM events fired after connect; 30s periodic flush to w:stats IQ |
Installation
npm install github:7ucg/baron-baileys-v2
# or
yarn add github:7ucg/baron-baileys-v2
Requirements: Node.js ≥ 20
Optional peer dependencies:
| Package | Purpose |
|---|---|
sharp |
Image processing / thumbnails |
jimp |
Fallback image processing |
audio-decode |
Voice message metadata |
link-preview-js |
Link preview generation |
Connecting Account
QR Code
const { makeWASocket, useMultiFileAuthState, DisconnectReason } = require('baron-baileys-v2')
const { Boom } = require('@hapi/boom')
const { state, saveCreds } = await useMultiFileAuthState('./auth')
const sock = makeWASocket({ auth: state, printQRInTerminal: true })
sock.ev.on('creds.update', saveCreds)
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
if (connection === 'close') {
const shouldReconnect = new Boom(lastDisconnect?.error)?.output?.statusCode !== DisconnectReason.loggedOut
if (shouldReconnect) connect()
}
})
Pairing Code
const sock = makeWASocket({ auth: state, printQRInTerminal: false })
if (!state.creds.registered) {
const code = await sock.requestPairingCode('49123456789') // phone number without +
console.log('Pairing code:', code)
}
Receive Full History
const sock = makeWASocket({
auth: state,
syncFullHistory: true
})
Socket Config Notes
const sock = makeWASocket({
auth: state,
// Cache group metadata to reduce WA queries (recommended)
cachedGroupMetadata: async jid => groupCache.get(jid),
// Improve retry system and enable poll vote decryption
getMessage: async key => store.getMsg(key),
// Suppress notifications on the phone while connected
markOnlineOnConnect: false
})
Saving & Restoring Sessions
const { useMultiFileAuthState } = require('baron-baileys-v2')
const { state, saveCreds } = await useMultiFileAuthState('./auth')
// Pass state to makeWASocket, call saveCreds on creds.update
sock.ev.on('creds.update', saveCreds)
Handling Events
Messages
// New or received messages
sock.ev.on('messages.upsert', ({ messages, type }) => {})
// Status updates (read receipts, delivery, edits, reactions)
sock.ev.on('messages.update', updates => {})
// Message deleted / cleared
sock.ev.on('messages.delete', ({ keys }) => {})
// Media decryption key update
sock.ev.on('messages.media-update', updates => {})
// Reaction on a message
sock.ev.on('messages.reaction', reactions => {})
// Comment on a message
sock.ev.on('message.comment', ({ message, comment }) => {})
// Message quarantined by WA
sock.ev.on('message.quarantined', ({ message }) => {})
// Poll — new option added
sock.ev.on('poll.add-option', ({ key, senderTimestampMs }) => {})
Chats & Contacts
sock.ev.on('chats.upsert', chats => {})
sock.ev.on('chats.update', chats => {})
sock.ev.on('chats.delete', ids => {})
sock.ev.on('chats.lock', ({ id, locked }) => {})
sock.ev.on('contacts.upsert', contacts => {})
sock.ev.on('contacts.update', contacts => {})
// Blocklist changed
sock.ev.on('blocklist.update', ({ blocklist, type }) => {})
Groups
sock.ev.on('groups.upsert', groups => {})
sock.ev.on('groups.update', updates => {})
sock.ev.on('group-participants.update', ({ id, participants, action }) => {})
// Someone requested to join
sock.ev.on('group.join-request', ({ id, participant, action }) => {})
// Member tag / mention update
sock.ev.on('group.member-tag.update', ({ id, participant }) => {})
Newsletters
sock.ev.on('newsletter-settings.update', update => {})
sock.ev.on('newsletter-participants.update', update => {})
sock.ev.on('newsletter.reaction', update => {})
sock.ev.on('newsletter.view', update => {})
sock.ev.on('newsletter.live-update', update => {})
sock.ev.on('newsletter.pin', update => {})
sock.ev.on('newsletter.invite', update => {})
Connection & Auth
sock.ev.on('connection.update', ({ connection, qr, lastDisconnect, isOnline, reachoutTimeLock }) => {})
sock.ev.on('creds.update', saveCreds)
// Security alert (e.g. linked device removed)
sock.ev.on('security.alert', data => {})
// Identity key change for a contact
sock.ev.on('identity.update', ({ jid }) => {})
// Server config received
sock.ev.on('server.config', config => {})
Calls
// `call` fires for both <call>-wrapped and top-level (<offer>/<terminate>) signalling
sock.ev.on('call', calls => {})
sock.ev.on('call.scheduled', ({ call }) => {})
sock.ev.on('call.schedule-cancelled', ({ call }) => {})
// Call links — create + toggle the link's waiting room
const token = await sock.createCallLink('audio')
await sock.toggleCallLinkWaitingRoom(token, true, 'audio')
// WA-Web coexistence (FB/IG) & business privacy-sync pushes
sock.ev.on('coexistence.update', u => {}) // { kind: 'onboarding' | 'offboarding', status?, productSurface? }
sock.ev.on('business.privacy-settings-sync', s => {})
Labels
sock.ev.on('labels.edit', ({ label }) => {})
sock.ev.on('labels.association', ({ association, type }) => {})
sock.ev.on('labels.reorder', ({ labelIds }) => {})
Presence & Devices
sock.ev.on('presence.update', ({ id, presences }) => {})
sock.ev.on('devices.update', ({ id, devices, isSelf }) => {})
Bot / Meta AI
sock.ev.on('bot.feedback', ({ message }) => {})
sock.ev.on('bot.stop-generation', ({ message }) => {})
sock.ev.on('bot.welcome-request', ({ message }) => {})
sock.ev.on('bot.psi-metadata', ({ message }) => {})
sock.ev.on('bot.query-fanout', ({ message }) => {})
sock.ev.on('bot.media-collection', ({ message }) => {})
sock.ev.on('bot.memu-onboarding', ({ message }) => {})
Sync & Settings
sock.ev.on('messaging-history.set', ({ chats, contacts, messages, isLatest }) => {})
sock.ev.on('messaging-history.status', ({ progress, hasMore }) => {})
sock.ev.on('settings.update', ({ setting, value }) => {})
sock.ev.on('lid-mapping.update', ({ lid, pn }) => {})
sock.ev.on('status.psa', ({ message }) => {})
sock.ev.on('status.mention', ({ message }) => {})
sock.ev.on('media.notify', ({ message }) => {})
sock.ev.on('reminder.update', ({ message }) => {})
sock.ev.on('payment.split', ({ message }) => {})
sock.ev.on('payment.reminder', ({ message }) => {})
sock.ev.on('cloud.thread.control', ({ message }) => {})
sock.ev.on('galaxy.flow.completed', ({ message }) => {})
Decrypt Poll Votes
const { getAggregateVotesInPollMessage } = require('baron-baileys-v2')
sock.ev.on('messages.update', async updates => {
for (const { key, update } of updates) {
if (update.pollUpdates) {
const pollCreation = await getMessage(key)
if (pollCreation) {
const votes = getAggregateVotesInPollMessage({ message: pollCreation, pollUpdates: update.pollUpdates })
console.log(votes)
}
}
}
})
Anti-Ban System
Import from baron-baileys-v2/src/antiban.js:
const {
AntiBan,
RateLimiter,
WarmUp,
HealthMonitor,
TimelockGuard,
ReplyRatioGuard,
ContactGraphWarmer,
PresenceChoreographer,
PostReconnectThrottle,
RetryReasonTracker,
LidResolver,
JidCanonicalizer,
MessageQueue,
Scheduler,
wrapSocket
} = require('baron-baileys-v2/src/antiban')
RateLimiter — throttle outbound messages
const limiter = new RateLimiter({
maxPerMinute: 15,
maxPerHour: 500,
maxPerDay: 3000,
minDelayMs: 1000,
maxDelayMs: 4000,
newChatDelayMs: 2000,
maxIdenticalMessages: 10 // per 30-minute window
})
const delay = await limiter.getDelay(jid, text)
if (delay === -1) return // blocked
if (delay > 0) await sleep(delay)
await sock.sendMessage(jid, { text })
limiter.record(jid, text)
WarmUp — gradual daily limit increase for new numbers
const warmup = new WarmUp({ warmUpDays: 5, day1Limit: 30, growthFactor: 1.8 })
if (!warmup.canSend()) return
await sock.sendMessage(jid, { text })
warmup.record()
console.log(warmup.getStatus())
// { phase: 'warming', day: 2, totalDays: 5, todayLimit: 54, todaySent: 12, progress: 40 }
HealthMonitor — detect ban risk
const health = new HealthMonitor({ autoPauseAt: 'critical' })
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
if (connection === 'close') health.recordDisconnect(lastDisconnect?.error)
if (connection === 'open') health.recordReconnect()
})
const status = health.getStatus()
// { risk: 'low'|'medium'|'high'|'critical', score, recommendation, stats }
if (health.isPaused()) return // auto-pauses at configured risk level
TimelockGuard — handle WA 463 reachout blocks
const guard = new TimelockGuard()
// Feed connection.update events
sock.ev.on('connection.update', ({ reachoutTimeLock }) => {
if (reachoutTimeLock) guard.onTimelockUpdate(reachoutTimeLock)
})
// Check before sending to new contacts
const { allowed, reason } = guard.canSend(jid)
if (!allowed) return console.log(reason)
PresenceChoreographer — human-like typing simulation
const choreo = new PresenceChoreographer({
enabled: true,
typingWPM: 45,
enableCircadianRhythm: true,
timezone: 'Europe/Berlin'
})
const plan = choreo.computeTypingPlan(text.length)
await choreo.executeTypingPlan(sock, jid, plan)
await sock.sendMessage(jid, { text })
wrapSocket — apply all anti-ban layers at once
const { wrapSocket } = require('baron-baileys-v2/src/antiban')
// 'moderate' is the default — use 'conservative' or 'aggressive' to tune
const wrappedSock = wrapSocket(sock, 'moderate')
// All outbound sendMessage calls are now automatically rate-limited,
// presence-simulated, and timelock-aware.
// Or pass individual overrides:
const wrappedSock2 = wrapSocket(sock, { preset: 'moderate', maxPerMinute: 20 })
Sending Messages
Text & Basic
// Text
await sock.sendMessage(jid, { text: 'Hello!' })
// Quote
await sock.sendMessage(jid, { text: 'Reply' }, { quoted: msg })
// Mention
await sock.sendMessage(jid, { text: '@49123456789', mentions: ['[email protected]'] })
// Forward
await sock.sendMessage(jid, { forward: msg })
// Location
await sock.sendMessage(jid, { location: { degreesLatitude: 52.5, degreesLongitude: 13.4 } })
// Live Location
await sock.sendMessage(jid, {
liveLocation: { degreesLatitude: 52.5, degreesLongitude: 13.4 },
accuracyInMeters: 10,
speedInMps: 0,
degreesClockwisefromMagneticNorth: 0,
caption: 'Live',
sequenceNumber: 1
})
// Contact
await sock.sendMessage(jid, { contacts: { displayName: 'Name', contacts: [{ vcard: '...' }] } })
// Reaction
await sock.sendMessage(jid, { react: { text: '👍', key: msg.key } })
// Pin
await sock.sendMessage(jid, { pin: { type: 1, time: 86400, key: msg.key } })
// Poll
await sock.sendMessage(jid, {
poll: { name: 'Vote?', values: ['Yes', 'No'], selectableCount: 1 }
})
// Call
await sock.sendMessage(jid, { call: { callId: '...', callType: 'audio' } })
Buttons & Interactive
// Reply buttons
await sock.sendMessage(jid, {
buttonsMessage: {
text: 'Choose:',
buttons: [
{ buttonId: '1', buttonText: { displayText: 'Option A' } },
{ buttonId: '2', buttonText: { displayText: 'Option B' } }
]
}
})
// List message
await sock.sendMessage(jid, {
listMessage: {
title: 'Menu',
description: 'Pick one',
buttonText: 'Open',
listType: 1,
sections: [
{
title: 'Section',
rows: [{ title: 'Item 1', rowId: 'item1' }]
}
]
}
})
// Template buttons
await sock.sendMessage(jid, {
templateMessage: {
hydratedTemplate: {
hydratedContentText: 'Hello',
hydratedButtons: [
{ quickReplyButton: { displayText: 'Yes', id: 'yes' } },
{ urlButton: { displayText: 'Visit', url: 'https://example.com' } }
]
}
}
})
// Interactive message
await sock.sendMessage(jid, {
interactiveMessage: {
body: { text: 'Choose' },
footer: { text: 'Footer' },
nativeFlowMessage: {
buttons: [{ name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Yes', id: 'yes' }) }]
}
}
})
Media
// Image
await sock.sendMessage(jid, { image: { url: './image.jpg' }, caption: 'Caption' })
// Video
await sock.sendMessage(jid, { video: { url: './video.mp4' }, caption: 'Video' })
// Audio
await sock.sendMessage(jid, { audio: { url: './audio.mp3' }, mimetype: 'audio/mp4' })
// Voice note (PTT)
await sock.sendMessage(jid, { audio: { url: './audio.ogg' }, mimetype: 'audio/ogg; codecs=opus', ptt: true })
// GIF
await sock.sendMessage(jid, { video: { url: './anim.mp4' }, gifPlayback: true })
// PTV (video note)
await sock.sendMessage(jid, { video: { url: './clip.mp4' }, ptv: true })
// View once
await sock.sendMessage(jid, { image: { url: './secret.jpg' }, viewOnce: true })
// Album
await sock.sendAlbumMessage(
jid,
[{ image: { url: './1.jpg' } }, { image: { url: './2.jpg' } }, { video: { url: './3.mp4' } }],
{ caption: 'Album' }
)
Meta AI / Rich Responses
// Send a prompt to Meta AI. Targets the @bot wire JID (867051314767696@bot),
// attaches the required messageSecret + botMetadata and the <bot> persona node,
// and registers the secret so the reply can be decrypted. Returns the message id.
const msgId = await sock.sendMetaAI('Was ist die Hauptstadt von Deutschland?')
// opts: { jid, invokerJid, sessionId, messageSecret, capabilities, quoted, links }
// In a group (Meta AI must already be a member — add it with
// groupParticipantsUpdate(group, ['867051314767696@bot'], 'add')): pass the
// group jid. It summons Meta AI via botGroupMetadata.participantsMetadata; the
// reply comes from 867051314767696@bot as a group participant.
await sock.sendMetaAI('meta, fass das zusammen', { jid: groupJid })
await sock.sendMetaAI('meta?', { jid: groupJid, mention: true }) // visible @Meta AI
// Receive the reply. Meta AI STREAMS its answer as protocolMessage/MESSAGE_EDIT
// chunks from 867051314767696@bot (enc type "msmsg", decrypted with the
// messageSecret the send registered). Each edit carries the full text-so-far.
// extractMetaAiText() normalizes every reply shape — plain extendedTextMessage,
// richResponseMessage.submessages[].messageText, or the base64 unifiedResponse —
// into one string.
const { extractMetaAiText } = require('baron-baileys-v2')
sock.ev.on('messages.upsert', ({ messages }) => {
for (const msg of messages) {
if (!msg.key.remoteJid?.endsWith('@bot')) continue
const text = extractMetaAiText(msg.message)
if (text) console.log('[Meta AI]', text)
}
})
// A richResponseMessage's unifiedResponse is auto-decoded on arrival: the raw
// bytes stay in `.data` while the decoded GenAI JSON is attached as `.decodedData`
// and the flattened markdown as `.text`.
// const ur = msg.message?.protocolMessage?.editedMessage?.richResponseMessage?.unifiedResponse
// ur.data / ur.decodedData / ur.text
// Rich AI response (table, list, code, LaTeX)
await sock.sendTable(jid, 'Comparison', ['Name', 'Value'], [
['Foo', '1'],
['Bar', '2']
])
await sock.sendList(jid, 'My List', ['Item 1', 'Item 2', 'Item 3'])
await sock.sendCodeBlock(jid, 'console.log("hello")', undefined, { language: 'js' })
await sock.sendLatex(jid, undefined, { expressions: [{ latexExpression: 'E = mc^2' }] })
// Capture a Meta AI unified response and resend it as-is elsewhere
const captured = sock.captureUnifiedResponse(metaAiMsg.message)
if (captured) {
await sock.sendUnifiedResponse(jid, undefined, captured)
}
// Rich menu: header (title/image/disclaimer), body (buttons or carousel cards), footer (CTA link)
await sock.richMenu(jid, {
header: { title: 'Choose an option' },
body: { buttons: ['Option A', 'Option B'] },
footer: { text: 'Learn more', url: 'https://example.com' }
})
// Raw HTML rendered via WhatsApp's GenAI unified-response primitive
await sock.sendHtml(jid, '<b>Hello</b> from Baileys')
Status / Stories
// Status with mentions
await sock.sendMessage('status@broadcast', {
text: 'Hello @49123',
mentions: ['[email protected]'],
statusMentionedJids: ['[email protected]']
})
// Status sticker interaction
await sock.sendMessage('status@broadcast', {
stickerInteraction: { sticker: { url: './sticker.webp' }, reactionKey: msg.key }
})
// Quote a status
await sock.sendMessage(jid, { text: 'Reply to status' }, { quoted: statusMsg })
Modifying Messages
// Delete for everyone
await sock.sendMessage(jid, { delete: msg.key })
// Edit
await sock.sendMessage(jid, { edit: msg.key, text: 'Updated text' })
Manipulating Media
const { downloadMediaMessage } = require('baron-baileys-v2')
// Download
const buffer = await downloadMediaMessage(msg, 'buffer', {})
// Re-upload to WhatsApp
const { url } = await sock.waUploadToServer(buffer, { mimetype: 'image/jpeg' })
Groups
// Create
const group = await sock.groupCreate('Name', ['[email protected]'])
// Add / Remove / Promote / Demote
await sock.groupParticipantsUpdate(jid, ['[email protected]'], 'add') // add | remove | promote | demote
// Change name
await sock.groupUpdateSubject(jid, 'New Name')
// Change description
await sock.groupUpdateDescription(jid, 'Description')
// Change settings
await sock.groupSettingUpdate(jid, 'announcement') // announcement | not_announcement | locked | unlocked
// Leave
await sock.groupLeave(jid)
// Invite link
const code = await sock.groupInviteCode(jid)
await sock.groupRevokeInvite(jid)
await sock.groupAcceptInvite(code)
// Metadata (now also returns memberShareHistoryMode, memberLinkMode, limitSharing)
const meta = await sock.groupMetadata(jid)
// Join requests
const requests = await sock.groupRequestParticipantsList(jid)
await sock.groupRequestParticipantsUpdate(jid, ['[email protected]'], 'approve') // approve | reject
// All groups
const all = await sock.groupFetchAllParticipating()
// Ephemeral
await sock.groupToggleEphemeral(jid, 86400) // seconds, 0 = off
// Acknowledge a group
await sock.groupAcknowledge(jid)
// Communities — linked/sub-group participants, join a sub-group, batch profile pictures
const linkedParts = await sock.groupGetLinkedParticipants(communityJid)
await sock.groupJoinLinked(communityJid, subGroupJid)
const pics = await sock.getGroupProfilePictures([jid1, jid2], 'preview')
Privacy
// Block / Unblock
await sock.updateBlockStatus(jid, 'block') // block | unblock
// Get settings
const privacy = await sock.fetchPrivacySettings()
// { last: 'all', online: 'all', profile: 'contacts', groupadd: 'all', calladd: 'all', ... }
// Force fresh fetch (bypass cache)
const fresh = await sock.fetchPrivacySettings(true)
// Get blocklist
const list = await sock.fetchBlocklist()
// Update individual settings (IQ-based, lowercase values, works on all accounts)
await sock.updateLastSeenPrivacy('contacts') // all | contacts | contact_blacklist | none
await sock.updateOnlinePrivacy('all')
await sock.updateProfilePicturePrivacy('contacts')
await sock.updateStatusPrivacy('contacts')
await sock.updateReadReceiptsPrivacy('all')
await sock.updateGroupsAddPrivacy('contacts')
await sock.updateCallPrivacy('all')
await sock.updateDefaultDisappearingMode(86400) // seconds, 0 = off
// Set via MEX GraphQL (UPPERCASE values required)
await sock.setPrivacySetting('LAST_SEEN', 'CONTACTS')
await sock.setPrivacySetting('GROUPS', 'CONTACT_BLACKLIST')
await sock.setPrivacySetting('CALLS', 'NONE')
// Manage contact lists for CONTACT_BLACKLIST / CONTACTS settings
await sock.updatePrivacyContactList('groupadd', 'contact_blacklist', [jid1, jid2])
const current = await sock.getPrivacyContactList('groupadd', 'contact_blacklist')
// "Block messages from unknown accounts" toggle (WA Web w:comms:chat)
const blockStatus = await sock.getChatBlockingStatus() // 'blocked' | 'unblocked'
await sock.updateChatBlockingStatus('block') // block | unblock
// Pending TOS disclosures · feature opt-out list · push config
const notices = await sock.getUserDisclosures()
const optOut = await sock.getOptOutList()
const push = await sock.getPushConfig()
See MEX.md for full MEX usage and error handling.
User Queries
// Check if number exists on WA
const results = await sock.onWhatsApp('49123456789')
// results[0] === { jid: '[email protected]', exists: true }
// Profile picture
const ppUrl = await sock.profilePictureUrl(jid, 'image')
// Status text (legacy)
const status = await sock.fetchStatus(jid)
// About text (MEX)
const abouts = await sock.getTextStatusList([jid])
// [{ jid, text: 'Hey there!', emoji: '👋', timestamp: 1234567890 }]
// Business profile
const biz = await sock.getBusinessProfile(jid)
// Presence (typing/online)
await sock.subscribePresence(jid)
sock.ev.on('presence.update', ({ id, presences }) => {})
// Chat history
await sock.fetchMessageHistory(50, oldestMsg.key, oldestMsg.messageTimestamp)
// Find user by @username
const user = await sock.findUserByUsername('someusername')
// { jid: '[email protected]', contact: false } or null
// Verify a JID before opening a chat
const integrity = await sock.contactIntegrityQuery([jid])
Change Profile
// Status
await sock.updateProfileStatus('My status')
// Name
await sock.updateProfileName('New Name')
// Picture
await sock.updateProfilePicture(jid, { url: './photo.jpg' })
// Remove picture
await sock.removeProfilePicture(jid)
Chat Modifiers
// Archive
await sock.chatModify({ archive: true, lastMessages: [msg] }, jid)
// Mute (ms timestamp)
await sock.chatModify({ mute: Date.now() + 8 * 60 * 60 * 1000 }, jid)
// Mark read/unread
await sock.chatModify({ markRead: false, lastMessages: [msg] }, jid)
// Delete message for me
await sock.chatModify({ clear: { messages: [{ id: msg.key.id, fromMe: msg.key.fromMe }] } }, jid)
// Delete chat
await sock.chatModify({ delete: true, lastMessages: [msg] }, jid)
// Star / Unstar
await sock.chatModify({ star: { messages: [{ id: msg.key.id, fromMe: msg.key.fromMe }], star: true } }, jid)
// Disappearing messages
await sock.sendMessage(jid, { disappearingMessagesInChat: 86400 })
Writing Custom Functionality
// Enable debug logs
const sock = makeWASocket({ logger: pino({ level: 'debug' }) })
// Raw websocket events
sock.ws.on('CB:message', node => console.log(node))
// Register callback for specific WA nodes
sock.ws.on('CB:iq,,result', node => {})
Rust WASM Bridge
The native module lives at 7ucg/whatsapp-rust-bridge.
Pre-built and bundled — no Rust toolchain needed to use this package.
Functions offloaded to Rust:
| Function | Description |
|---|---|
decodeNode |
WABinary protocol decoding |
NoiseSession |
Noise_XX_25519_AESGCM_SHA256 handshake + framing |
hkdf |
HKDF key derivation |
hmacSign |
HMAC-SHA256 signing |
sha256 |
SHA-256 hashing |
aesEncrypt / aesDecrypt |
AES-256-CBC |
aesEncryptGCM / aesDecryptGCM |
AES-256-GCM |
aesEncryptCTR / aesDecryptCTR |
AES-256-CTR |
License
MIT