Skip to content
Projects

7ucg/baron-baileys-v2

View on GitHub

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.

How these counts are measured

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 & Apps

README.md

Original

baron-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


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