open-wa v5 is alpha. Use v4.76.0 for mature production systems unless you are validating v5.
The Client APIAPI ExplorerLicensing

Messages and message events

Send, receive, reply to, and monitor WhatsApp messages.

Message Wally

Messages and message events

Use this guide for the common message flows: receiving messages, sending replies, attaching media, and reacting to message metadata.

For chat ID formats such as 447700000000@c.us, group IDs, and LID IDs, read ChatId primer first.

Receive messages

client.onMessage((message) => {
  console.log(message.body);
});

client.onAnyMessage((message) => {
  console.log(message.body);
});

Use onMessage for incoming traffic only and onAnyMessage when you need both directions.

Message object shape

Incoming message objects include the message text, sender details, chat details, media flags, and quote metadata. WhatsApp may add extra fields, so treat the object as extensible.

client.onMessage((message) => {
  console.log(message.id);
  console.log(message.from);
  console.log(message.body);
  console.log(message.type);
});
FieldDescription
idThe message ID. Pass this to reply, forwardMessages, or lookup methods.
bodyText content for text messages. For media messages, this may be empty.
typeWhatsApp message type, such as chat, image, video, document, ptt, location, buttons_response, or list_response.
fromThe chat that sent the message. In direct chats this is the contact ID. In groups this is the group chat ID.
toThe chat or account that received the message.
chatIdThe chat ID for the conversation.
senderContact details for the sender.
senderIdSender contact ID when available. Useful in groups.
authorThe group participant that sent the message. Present on many group messages.
fromMetrue when the current session sent the message.
selfDirection marker, usually in or out.
timestamp / tUnix timestamp values from WhatsApp.
isGroupMsgtrue when the message came from a group.
isMedia / isMMSMedia flags. Use these before downloading or processing attachments.
captionCaption for image, video, or document messages.
mentionedJidListContact IDs mentioned in the message.
ackDelivery state for outgoing messages. Read onAck for updates.
quotedMsg / quotedMsgObjQuoted message payload when WhatsApp makes it available.
isQuotedMsgAvailableWhether quote data can be read from the payload.

Send messages

await client.sendText(chatId, 'Hello');
await client.sendTextWithMentions(chatId, 'Hello @447700000000');
await client.reply(chatId, 'Hello', messageId);
await client.sendReplyWithMentions(chatId, 'Hello @447700000000', messageId);

Always await message operations so failures are visible.

Formatting

WhatsApp uses inline formatting markers in text messages. Send the markers as part of the message body.

await client.sendText(chatId, '*bold*');
await client.sendText(chatId, '_italic_');
await client.sendText(chatId, '~strikethrough~');
await client.sendText(chatId, '```monospace```');

You can combine formatting with normal text.

await client.sendText(chatId, 'Order *confirmed* for _today_.');

Attachments vs text

Text messages only need a chat ID and a string body. Attachment messages include a file payload, a filename, and often a caption.

await client.sendText(chatId, 'Here is the receipt.');

await client.sendImage(
  chatId,
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...',
  'receipt.png',
  'Receipt attached'
);

await client.sendFile(
  chatId,
  'data:application/pdf;base64,JVBERi0xLjQK...',
  'receipt.pdf',
  'PDF receipt'
);

Use sendText for plain conversation updates. Use sendImage, sendFile, sendAudio, sendPtt, or sendVideoAsGif when the payload is media. Captions belong to the attachment message, not a separate text message.

Quoted replies

Use reply when your response should quote an existing message. Pass the destination chat, the reply body, and the original message ID.

client.onMessage(async (message) => {
  if (message.body === '!status') {
    await client.reply(message.from, 'Still working on it.', message.id);
  }
});

For replies that also mention users, use sendReplyWithMentions.

await client.sendReplyWithMentions(
  groupId,
  'Thanks @447700000000',
  messageId,
  false,
  ['447700000000@c.us']
);

Mentions

Mentions work in group messages when the body contains @ text and the mentioned contact IDs are passed to the send method.

await client.sendTextWithMentions(
  groupId,
  'Hello @447700000000, can you check this?',
  false,
  ['447700000000@c.us']
);

Set hideTags to true when you want WhatsApp to notify the users without showing the mention tags in the rendered text.

Buttons, lists, and polls

Interactive messages let users choose from fixed options. Availability can depend on the WhatsApp account, client version, and message type.

await client.sendButtons(
  chatId,
  'Choose an option',
  [
    { id: 'yes', text: 'Yes' },
    { id: 'no', text: 'No' },
  ],
  'Confirmation',
  'Reply with one tap'
);

await client.sendListMessage(
  chatId,
  [
    {
      title: 'Main menu',
      rows: [
        { id: 'orders', title: 'Orders' },
        { id: 'support', title: 'Support' },
      ],
    },
  ],
  'Menu',
  'Pick a topic',
  'Open menu'
);

await client.sendPoll(
  chatId,
  'Which day works best?',
  ['Monday', 'Tuesday', 'Wednesday'],
  1
);

Button and list replies arrive as message events with types such as buttons_response or list_response. Poll updates arrive through WhatsApp message events when supported by the session.

Forward messages

await client.forwardMessages('1234567890@c.us', [messageId], true);

Read receipts and typing state

client.onAck((ack) => {
  console.log(ack);
});

await client.simulateTyping(chatId, true);
await client.simulateTyping(chatId, false);

Location messages

await client.sendLocation(chatId, latitude, longitude, 'London');

When receiving a location message, read fields such as lat, lng, and loc from the incoming message payload.

Errors

Message sends can fail because the session is not ready, the chat ID is invalid, the target user cannot be reached, the media payload is too large or malformed, or WhatsApp rejects the action.

try {
  const result = await client.sendText(chatId, 'Hello');

  if (!result) {
    console.warn('Message send returned no message ID');
  }
} catch (error) {
  console.error('Could not send message', error);
}

Common checks:

Error caseWhat to check
Invalid chat IDConfirm the value matches a contact, group, or LID format. See ChatId primer.
Session not readyWait for authentication and connection before sending.
Media rejectedCheck the MIME type, base64 data URL, filename, and file size.
Message not deliveredWatch onAck and retry only when it is safe for your workflow.
Temporary WhatsApp blockSlow down sends and review automation volume.

Rate limits

WhatsApp can limit or block accounts that send too many messages, repeat the same content, or contact users without consent. Keep sends paced, avoid bulk blasts, and handle failures without tight retry loops.

Read Rate limits before running production automation.

Full bot example

This example receives messages, sends formatted text, sends a quoted reply, mentions a group participant, sends an image, and sends a poll.

import { createClient } from '@open-wa/wa-automate';

async function start() {
  const client = await createClient({
    sessionId: 'messages-guide',
  });

  client.onMessage(async (message) => {
    try {
      if (message.body === '!help') {
        await client.reply(
          message.from,
          '*Commands*\n!image\n!poll\n!mention',
          message.id
        );

        return;
      }

      if (message.body === '!image') {
        await client.sendImage(
          message.from,
          'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...',
          'example.png',
          'Here is an example image.'
        );

        return;
      }

      if (message.body === '!poll') {
        await client.sendPoll(
          message.from,
          'What should we do next?',
          ['Send update', 'Wait', 'Ask support'],
          1
        );

        return;
      }

      if (message.body === '!mention' && message.isGroupMsg && message.author) {
        const contactId = message.author;
        const phone = contactId.replace('@c.us', '');

        await client.sendTextWithMentions(
          message.from,
          `Thanks @${phone}`,
          false,
          [contactId]
        );
      }
    } catch (error) {
      console.error('Message handler failed', error);
    }
  });
}

start().catch(console.error);
Wally the Walrus typing

Was this helpful?

Wally and his cute companion coffee mug are coding day and night to keep this up-to-date!

On this page