Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/wppconnect-team/wa-js/llms.txt

Use this file to discover all available pages before exploring further.

WA-JS uses an event emitter (backed by EventEmitter2) to surface real-time updates from WhatsApp Web’s internals. Feature modules register listeners on WhatsApp’s internal stores and models, then re-emit normalized events through a single global bus. Your code subscribes to that bus using the WPP.* event methods, without touching any WhatsApp internals directly.

Global event API

All event methods are available directly on window.WPP:
MethodDescription
WPP.on(event, listener)Subscribe to an event. Calls listener each time the event fires.
WPP.off(event, listener)Unsubscribe a previously registered listener.
WPP.once(event, listener)Subscribe for exactly one invocation, then auto-remove.
WPP.onAny(listener)Subscribe to every event. The first argument to listener is the event name.
WPP.waitFor(event, options?)Returns a Promise that resolves the next time the event fires.
WPP.many(event, n, listener)Subscribe for exactly n invocations, then auto-remove.
WPP.listenerCount(event)Return the number of listeners for an event.
WPP.removeAllListeners(event?)Remove all listeners for an event (or all events if omitted).

Connection events

Connection events are emitted on the conn.* namespace and reflect WhatsApp Web’s internal stream state. They fire immediately with the current value when you subscribe, and again whenever the value changes.

conn.stream_mode_changed

Fired when the high-level connection mode changes. The callback receives a StreamMode string.
WPP.on('conn.stream_mode_changed', function (mode) {
  console.log('Stream mode:', mode);
});
ModeWhen it appears
QRQR code is displayed, waiting for phone scan
MAINMain interface loaded; authenticated and ready
SYNCINGSyncing messages and data after login
OFFLINEConnection is offline
CONFLICTLogin conflict detected (same account opened elsewhere)
PROXYBLOCKConnection blocked by a proxy
TOS_BLOCKAccount blocked for Terms of Service violation
SMB_TOS_BLOCKBusiness account blocked for Terms of Service violation
DEPRECATED_VERSIONThe running WhatsApp Web version is no longer supported

conn.stream_info_changed

Fired when the low-level connection state changes. The callback receives a StreamInfo string.
WPP.on('conn.stream_info_changed', function (info) {
  console.log('Stream info:', info);
});
InfoMeaning
OFFLINENo network connection
OPENINGTCP/WebSocket connection being established
PAIRINGPairing handshake in progress
SYNCINGDownloading message history
RESUMINGResuming a previous session
CONNECTINGConnecting to the WhatsApp server
NORMALFully connected and operational

Other connection events

EventPayloadDescription
conn.authenticatedundefinedFired after a successful QR code scan
conn.logoutundefinedFired when the session is logged out
conn.logout_reasonLogoutReasonReason code for the logout
conn.main_initundefinedInterface is beginning to boot
conn.main_loadedundefinedMain interface loaded but still syncing
conn.main_readyundefinedAuthenticated and ready to send messages
conn.onlinebooleantrue when online, false when offline
conn.require_authundefinedAuthentication is required (QR scan)
conn.qrcode_idleundefinedQR code timed out without a scan
conn.needs_updateundefinedWhatsApp Web version update required

Chat events

Chat events are emitted on the chat.* namespace whenever messages, reactions, or read state changes occur.

chat.new_message

Fired whenever a new message is added to any chat. The payload is a MsgModel instance.
WPP.on('chat.new_message', function (msg) {
  console.log('From:', msg.from.toString());
  console.log('Body:', msg.body);
  console.log('Is group:', msg.isGroupMsg);
  console.log('Is from me:', msg.id.fromMe);
});

Other chat events

EventPayloadDescription
chat.new_chatChatModelA new chat was created
chat.active_chatChatModel | nullThe currently open chat changed
chat.msg_revoke{ id, refId, from, to, type }A message was deleted (revoke, sender_revoke, or admin_revoke)
chat.msg_ack_change{ ack, ids, chat, sender? }Message delivery/read acknowledgement changed
chat.msg_edited{ chat, id, msg }A message was edited
chat.new_reaction{ id, msgId, reactionText, sender, … }A reaction was added or removed
chat.unread_count_changed{ chat, unreadCount, previousUnreadCount }Unread count updated
chat.presence_change{ id, isOnline, state, … }Contact typing/online presence changed
chat.poll_response{ msgId, chatId, selectedOptions, sender }A poll vote was received
chat.update_label{ chat, ids, labels, type }Labels added or removed from a chat

Code examples

WPP.loader.onReady(function () {
  // Check the current mode immediately
  const data = WPP.conn.getStreamData();

  if (data.mode === 'MAIN') {
    startMyBot();
  } else {
    // React when it changes
    WPP.once('conn.stream_mode_changed', function (mode) {
      if (mode === 'MAIN') {
        startMyBot();
      }
    });
  }
});

function startMyBot() {
  WPP.on('chat.new_message', function (msg) {
    if (!msg.id.fromMe && msg.body === 'ping') {
      WPP.chat.sendTextMessage(msg.from.toString(), 'pong');
    }
  });
}

Key events reference

EventPayload typeWhen it fires
conn.stream_mode_changedStreamMode stringConnection mode changes (QR, MAIN, OFFLINE, …)
conn.stream_info_changedStreamInfo stringLow-level socket state changes
conn.authenticatedundefinedSuccessful QR scan
conn.main_readyundefinedFully authenticated and ready to send
conn.onlinebooleanNetwork connectivity changes
conn.logoutundefinedSession logged out
chat.new_messageMsgModelAny new incoming or outgoing message
chat.msg_revokeobjectMessage deleted by sender or admin
chat.new_reactionobjectReaction added or removed from a message
chat.presence_changeobjectContact typing indicator or online status
Use WPP.waitFor(event) when you need a one-time async pattern — for example, waiting for the first authenticated event before proceeding. It returns a Promise that resolves with the event payload, so you can await it directly without managing listener cleanup yourself:
WPP.loader.onReady(async function () {
  if (!WPP.conn.isAuthenticated()) {
    // Block until QR is scanned
    await WPP.waitFor('conn.authenticated');
  }
  console.log('Session is authenticated');
});

Build docs developers (and LLMs) love