Skip to main content

Understanding the Message Class

Every incoming message in WAPI is represented by the Message class, which provides a structured way to access message content, sender information, and chat details.
The Message class is automatically instantiated when your bot receives a message. In middleware functions, you’ll work with the Context class, which extends Message with additional functionality.

Message Properties

The Message class exposes several key properties for working with incoming messages:

Message Content

Access the text content, media type, and metadata

Sender Info

Get information about who sent the message

Chat Details

Determine if it’s a private chat or group

Rich Data

Parse mentions, links, and quoted messages

Basic Message Information

bot.use(async (ctx, next) => {
  // Message ID and timestamp
  console.log(ctx.id);        // Message ID
  console.log(ctx.timestamp); // Unix timestamp
  
  // Message content
  console.log(ctx.text);      // Text content
  console.log(ctx.type);      // Message type (e.g., "conversation", "imageMessage")
  console.log(ctx.size);      // Content size in bytes or characters
  
  await next();
});

Sender Information

The from property contains details about the message sender:
bot.use(async (ctx, next) => {
  // Sender details
  console.log(ctx.from.jid);  // WhatsApp LID (lid format)
  console.log(ctx.from.pn);   // Phone number (s.whatsapp.net format)
  console.log(ctx.from.name); // Display name
  
  // Check if message is from the bot itself
  const isFromMe = ctx.from.jid === ctx.bot.account.jid;
  
  await next();
});

Chat Information

The chat property tells you where the message was sent:
bot.use(async (ctx, next) => {
  // Chat identification
  console.log(ctx.chat.jid);   // Chat identifier
  console.log(ctx.chat.type);  // "private" or "group"
  console.log(ctx.chat.name);  // Chat display name
  
  // Addressing mode
  console.log(ctx.chat.addressing); // "pn" or "lid"
  
  // Check chat type
  if (ctx.chat.type === "private") {
    console.log("This is a private chat");
    console.log(ctx.chat.pn); // Phone number (only in private chats)
  } else if (ctx.chat.type === "group") {
    console.log("This is a group chat");
  }
  
  await next();
});

Message Types

WAPI supports various WhatsApp message types. You can detect the type using the type property:
bot.use(async (ctx, next) => {
  if (ctx.type === "conversation" || ctx.type === "extendedTextMessage") {
    console.log("Text message:", ctx.text);
  }
  await next();
});

Parsing Mentions

WAPI automatically parses mentions from message text using the parseMentions method. Parsed mentions are available in the mentions array:
bot.use(async (ctx, next) => {
  if (ctx.mentions.length > 0) {
    console.log("Message mentions:", ctx.mentions);
    
    // Mentions are in JID format: "[email protected]" or "1234567890@lid"
    ctx.mentions.forEach(jid => {
      console.log("Mentioned user:", jid);
    });
    
    // Reply mentioning the same users
    await ctx.reply("Thanks for the mention!", {
      mentions: ctx.mentions
    });
  }
  
  await next();
});
The parseMentions method (from bot.ts:261-275) uses a regex pattern to extract mentions in the format @1234567890 and converts them to proper WhatsApp JID format based on the addressing mode.

Manual Mention Parsing

You can also manually parse mentions from text:
bot.use(async (ctx, next) => {
  const text = "Hello @1234567890 and @9876543210!";
  
  // Parse mentions for standard WhatsApp format
  const mentions = ctx.bot.parseMentions(text, "s.whatsapp.net");
  // Returns: ["[email protected]", "[email protected]"]
  
  // Parse mentions for LID format (new addressing)
  const lidMentions = ctx.bot.parseMentions(text, "lid");
  // Returns: ["1234567890@lid", "9876543210@lid"]
  
  await next();
});
WAPI automatically extracts links from messages using the parseLinks method:
bot.use(async (ctx, next) => {
  if (ctx.links.length > 0) {
    console.log("Message contains links:", ctx.links);
    
    ctx.links.forEach(link => {
      console.log("Found link:", link);
      
      // Check if it's a specific domain
      if (link.includes("github.com")) {
        console.log("GitHub link detected!");
      }
    });
  }
  
  await next();
});
The parseLinks method (from bot.ts:277-306) uses the Autolinker library to detect URLs, email addresses, and phone numbers in text. It supports both explicit URLs with schemes and TLD-based matching.
The link parser detects:
  • URLs with schemes (http://, https://)
  • Domain names with TLDs (example.com)
  • Email addresses ([email protected])
  • Phone numbers
  • External ad reply links from message context
bot.command("links", async (ctx) => {
  if (ctx.links.length === 0) {
    await ctx.reply("No links found in your message.");
    return;
  }
  
  const linkList = ctx.links
    .map((link, index) => `${index + 1}. ${link}`)
    .join("\n");
  
  await ctx.reply(`Found ${ctx.links.length} link(s):\n${linkList}`);
});

Handling Quoted Messages

When a user replies to a message, you can access the quoted message:
bot.use(async (ctx, next) => {
  if (ctx.quoted) {
    console.log("This message quotes another message");
    console.log("Quoted text:", ctx.quoted.text);
    console.log("Quoted type:", ctx.quoted.type);
    console.log("Quoted sender:", ctx.quoted.from.name);
    
    // Reply to the quoted message
    await ctx.reply(`You quoted: "${ctx.quoted.text}"`);
  }
  
  await next();
});
The quoted property is automatically parsed from the message’s context info (see message.ts:142-154). Nested quotes are removed to prevent infinite recursion.

Practical Examples

1

Echo Bot

Create a bot that repeats what users say:
bot.command("echo", async (ctx) => {
  const text = ctx.args.join(" ");
  if (!text) {
    await ctx.reply("Please provide text to echo.");
    return;
  }
  await ctx.reply(text);
});
2

Message Info Command

Display detailed information about the current message:
bot.command("info", async (ctx) => {
  const info = [
    `*Message Information*`,
    `ID: ${ctx.id}`,
    `Type: ${ctx.type}`,
    `From: ${ctx.from.name} (${ctx.from.pn})`,
    `Chat: ${ctx.chat.name} (${ctx.chat.type})`,
    `Size: ${ctx.size} bytes`,
    `Mentions: ${ctx.mentions.length}`,
    `Links: ${ctx.links.length}`,
    `Has quote: ${ctx.quoted ? 'Yes' : 'No'}`
  ].join("\n");
  
  await ctx.reply(info);
});
3

Link Extractor

Extract and validate all links from messages:
bot.use(async (ctx, next) => {
  if (ctx.links.length > 0) {
    console.log(`[${ctx.chat.name}] ${ctx.from.name} shared ${ctx.links.length} link(s)`);
    
    // Filter for specific domains
    const githubLinks = ctx.links.filter(link => 
      link.includes("github.com")
    );
    
    if (githubLinks.length > 0) {
      await ctx.reply(`Thanks for sharing GitHub links!`);
    }
  }
  await next();
});
4

Mention Notifier

Notify when someone mentions specific users:
const ADMIN_JID = "[email protected]";

bot.use(async (ctx, next) => {
  if (ctx.mentions.includes(ADMIN_JID)) {
    console.log(`Admin was mentioned in ${ctx.chat.name}`);
    // Could send notification or log to database
  }
  await next();
});

Message Flow

Here’s how WAPI processes incoming messages:

Best Practices

Always verify the message type before attempting to access type-specific properties:
bot.use(async (ctx, next) => {
  if (ctx.type === "imageMessage") {
    // Safe to access image-specific properties
    console.log(ctx.mimetype);
    console.log(ctx.hash);
  }
  await next();
});
Some message types may have empty text content:
bot.use(async (ctx, next) => {
  if (ctx.text && ctx.text.trim()) {
    // Process text content
    console.log("Message text:", ctx.text);
  }
  await next();
});
Respect the chat’s addressing mode when parsing mentions:
bot.use(async (ctx, next) => {
  const server = ctx.chat.addressing === "lid" 
    ? "lid" 
    : "s.whatsapp.net";
  
  const mentions = ctx.bot.parseMentions(ctx.text, server);
  await next();
});
Keep track of critical message types for debugging:
bot.use(async (ctx, next) => {
  if (ctx.type !== "conversation" && 
      ctx.type !== "extendedTextMessage") {
    console.log(`Special message type: ${ctx.type} from ${ctx.from.name}`);
  }
  await next();
});

Next Steps

Media Messages

Learn how to send and receive images, videos, and audio

Groups

Work with group chats and group metadata

Advanced Features

Explore advanced bot patterns and utilities

API Reference

Full API documentation for the Context class

Build docs developers (and LLMs) love