Skip to main content
The Context class represents an incoming message with its metadata and provides convenient methods for replying. It extends the Message class and is passed to all middleware functions.

Import

import type { Context } from 'wapi';
Context objects are automatically created by the Bot and passed to your middleware. You typically don’t instantiate them directly.

Properties

Bot Reference

bot
Bot
Reference to the parent Bot instance
bot.command('ping', async (ctx) => {
  // Access bot properties through ctx
  await ctx.reply(`Latency: ${ctx.bot.ping}ms`);
});

Command Information

prefixUsed
string
The prefix character used to invoke the command (e.g., "!" or "/"). Empty string if not a command.
commandName
string
The command name in lowercase (without prefix). Empty string if not a command.
args
string[]
Array of command arguments (space-separated words after the command name)
bot.command('calc', async (ctx) => {
  // User sent: "!calc 10 + 20"
  console.log(ctx.prefixUsed);   // "!"
  console.log(ctx.commandName);  // "calc"
  console.log(ctx.args);         // ["10", "+", "20"]
  
  const [a, op, b] = ctx.args;
  // Perform calculation...
});

Message Properties (from Message class)

message
WAMessage
Raw Baileys message object
chat
IChat
Chat information:
from
IFrom
Sender information:
type
keyof proto.IMessage
Message type: "conversation", "imageMessage", "videoMessage", "audioMessage", "documentMessage", "stickerMessage", etc.
id
string
Unique message ID
timestamp
number
Message timestamp (Unix epoch in milliseconds)
hash
string
File SHA256 hash (for media messages)
mimetype
string
MIME type (for media messages)
text
string
Message text content (or caption for media)
size
number
File size in bytes (for media) or text length
mentions
string[]
Array of mentioned user JIDs
Array of URLs, emails, and phone numbers found in the message
quoted
Message | undefined
Quoted/replied message object (if this is a reply)
bot.use(async (ctx, next) => {
  console.log(`From: ${ctx.from.name}`);
  console.log(`Chat: ${ctx.chat.name} (${ctx.chat.type})`);
  console.log(`Type: ${ctx.type}`);
  console.log(`Text: ${ctx.text}`);
  console.log(`Time: ${new Date(ctx.timestamp)}`);
  
  if (ctx.mentions.length > 0) {
    console.log(`Mentions: ${ctx.mentions.join(', ')}`);
  }
  
  if (ctx.quoted) {
    console.log(`Replying to: ${ctx.quoted.text}`);
  }
  
  await next();
});

Methods

reply()

Sends a text reply to the message.
await ctx.reply(text: string, options?: IReplyOptions): Promise<Context>
text
string
required
Reply text content
options
IReplyOptions
Optional reply options:
returns
Promise<Context>
Context object for the sent reply
bot.command('hello', async (ctx) => {
  await ctx.reply('Hello there! 👋');
});

replyWithImage()

Sends an image reply to the message.
await ctx.replyWithImage(
  image: string | Buffer,
  options?: IReplyWithImageOptions
): Promise<Context>
image
string | Buffer
required
Image data as Buffer or URL string
options
IReplyWithImageOptions
returns
Promise<Context>
Context object for the sent image
bot.command('cat', async (ctx) => {
  await ctx.replyWithImage(
    'https://cataas.com/cat',
    { caption: 'Here\'s a random cat! 🐱' }
  );
});

replyWithVideo()

Sends a video reply to the message.
await ctx.replyWithVideo(
  video: string | Buffer,
  options?: IReplyWithVideoOptions
): Promise<Context>
video
string | Buffer
required
Video data as Buffer or URL string
options
IReplyWithVideoOptions
returns
Promise<Context>
Context object for the sent video
bot.command('tutorial', async (ctx) => {
  await ctx.replyWithVideo(
    'https://example.com/tutorial.mp4',
    { caption: 'Watch this tutorial' }
  );
});

replyWithAudio()

Sends an audio reply to the message.
await ctx.replyWithAudio(
  audio: string | Buffer,
  options?: IReplyWithAudioOptions
): Promise<Context>
audio
string | Buffer
required
Audio data as Buffer or URL string
options
IReplyWithAudioOptions
returns
Promise<Context>
Context object for the sent audio
bot.command('song', async (ctx) => {
  await ctx.replyWithAudio(
    'https://example.com/song.mp3'
  );
});

replyWithSticker()

Sends a sticker reply to the message.
await ctx.replyWithSticker(
  sticker: Buffer,
  options?: IReplyOptions
): Promise<Context>
sticker
Buffer
required
Sticker data as WebP Buffer
options
IReplyOptions
Optional reply options (mentions, contextInfo)
returns
Promise<Context>
Context object for the sent sticker
Stickers must be in WebP format. Use a library like sharp to convert images to WebP.
import sharp from 'sharp';

bot.command('sticker', async (ctx) => {
  if (ctx.type !== 'imageMessage') {
    await ctx.reply('❌ Please send an image');
    return;
  }
  
  // Download the image
  const imageBuffer = await ctx.download();
  
  // Convert to WebP sticker
  const stickerBuffer = await sharp(imageBuffer)
    .resize(512, 512, { fit: 'contain' })
    .webp()
    .toBuffer();
  
  await ctx.replyWithSticker(stickerBuffer);
});

del()

Deletes the message.
await ctx.del(): Promise<void>
Only works for messages sent by the bot (where message.key.fromMe === true) or messages in groups where the bot is an admin.
bot.use(async (ctx, next) => {
  if (containsSpam(ctx.text)) {
    await ctx.del();
    await ctx.bot.sendMessage(
      ctx.chat.jid,
      { text: '⚠️ Spam message deleted' }
    );
    return; // Don't call next()
  }
  await next();
});

edit()

Edits a message sent by the bot.
await ctx.edit(text: string): Promise<Context>
text
string
required
New message text
returns
Promise<Context>
Context object for the edited message
Only messages sent by the bot (message.key.fromMe === true) can be edited.
bot.command('countdown', async (ctx) => {
  const msg = await ctx.reply('Starting in 3...');
  
  await new Promise(r => setTimeout(r, 1000));
  await msg.edit('Starting in 2...');
  
  await new Promise(r => setTimeout(r, 1000));
  await msg.edit('Starting in 1...');
  
  await new Promise(r => setTimeout(r, 1000));
  await msg.edit('🚀 Go!');
});

download()

Downloads media content from the message.
await ctx.download(): Promise<Buffer>
returns
Promise<Buffer>
Media content as Buffer
Only works for media messages (images, videos, audio, documents, stickers).
bot.use(async (ctx, next) => {
  if (ctx.type === 'imageMessage') {
    try {
      const buffer = await ctx.download();
      console.log(`Downloaded image: ${buffer.length} bytes`);
      
      // Process the image...
      // await processImage(buffer);
      
    } catch (error) {
      await ctx.reply('❌ Failed to download image');
    }
  }
  await next();
});

Complete Example

import { Bot } from 'wapi';
import { MessageBuilder } from 'wapi';

const bot = new Bot(/* ... */);

// Logging middleware
bot.use(async (ctx, next) => {
  console.log(`[${ctx.chat.type}] ${ctx.from.name}: ${ctx.text}`);
  await next();
});

// Anti-spam middleware
bot.use(async (ctx, next) => {
  if (ctx.text.toLowerCase().includes('spam')) {
    await ctx.reply('⚠️ Please don\'t spam');
    await ctx.del();
    return;
  }
  await next();
});

// Info command
bot.command('info', async (ctx) => {
  const info = new MessageBuilder()
    .addTitle('MESSAGE INFO')
    .addBlankLine()
    .addDescription(`ID: ${ctx.id}`)
    .addDescription(`Type: ${ctx.type}`)
    .addDescription(`From: ${ctx.from.name}`)
    .addDescription(`Chat: ${ctx.chat.name}`)
    .addDescription(`Time: ${new Date(ctx.timestamp).toLocaleString()}`)
    .addBlankLine()
    .addDescription(`Size: ${ctx.size} bytes`)
    .addDescription(`Mentions: ${ctx.mentions.length}`)
    .addDescription(`Links: ${ctx.links.length}`)
    .build();
  
  await ctx.reply(info);
});

// Echo command
bot.command('echo', async (ctx) => {
  const text = ctx.args.join(' ');
  if (!text) {
    await ctx.reply('Usage: !echo <message>');
    return;
  }
  await ctx.reply(text);
});

// Mention command
bot.command('mention', async (ctx) => {
  if (ctx.chat.type !== 'group') {
    await ctx.reply('❌ This command only works in groups');
    return;
  }
  
  await ctx.reply(
    `Hello @${ctx.from.pn}! 👋`,
    { mentions: [ctx.from.jid] }
  );
});

// Download media
bot.use(async (ctx, next) => {
  if (ctx.type === 'imageMessage' && ctx.text.includes('#download')) {
    const buffer = await ctx.download();
    await ctx.reply(`✅ Downloaded ${buffer.length} bytes`);
    return;
  }
  await next();
});

await bot.login('qr');

See Also

Bot

Learn about the Bot class

Message Builder

Build formatted messages

Build docs developers (and LLMs) love