
How to Send Stickers on WhatsApp with Node.js
Stickers in WhatsApp are WebP images sent with a stickerMessage proto shape. whatsmeow-node handles the upload and encryption — you just provide the file and dimensions.
Prerequisites
- A paired whatsmeow-node session (How to Pair)
- A sticker image in WebP format, ideally 512x512 pixels
Step 1: Upload the Sticker File
Stickers use the same upload flow as images. The uploadMedia method encrypts and uploads the file to WhatsApp's servers:
const media = await client.uploadMedia("/path/to/sticker.webp", "image");
The returned object contains the encrypted media metadata you'll need for sending.
Step 2: Send the Sticker Message
await client.sendRawMessage(jid, {
stickerMessage: {
URL: media.URL,
directPath: media.directPath,
mediaKey: media.mediaKey,
fileEncSHA256: media.fileEncSHA256,
fileSHA256: media.fileSHA256,
fileLength: String(media.fileLength),
mimetype: "image/webp",
width: 512,
height: 512,
// isAnimated: true, // for animated stickers
},
});
width and height are required. Without them, WhatsApp may display the sticker as a generic file attachment instead of rendering it inline. Standard sticker size is 512x512.
Step 3: Download Incoming Stickers
Listen for messages and use downloadAny() to save incoming stickers to disk:
client.on("message", async ({ info, message }) => {
const sticker = message.stickerMessage;
if (!sticker) return;
// downloadAny() detects the media type automatically
// and saves to a temp file
const filePath = await client.downloadAny(message);
console.log(`Sticker from ${info.pushName} saved to: ${filePath}`);
});
downloadAny() saves to a temporary file. If you need to keep the sticker permanently, copy it to a stable location with fs.copyFile(). See How to Download Media for details.
Complete Example
A bot that echoes stickers back and saves incoming ones:
import { createClient } from "@whatsmeow-node/whatsmeow-node";
import { copyFile, mkdir } from "node:fs/promises";
import path from "node:path";
const client = createClient({ store: "session.db" });
const SAVE_DIR = "./stickers";
client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;
const sticker = message.stickerMessage;
if (!sticker) return;
console.log(`Sticker from ${info.pushName}`);
// Download the incoming sticker
const tempPath = await client.downloadAny(message);
// Save permanently
await mkdir(SAVE_DIR, { recursive: true });
const dest = path.join(SAVE_DIR, `${info.id}.webp`);
await copyFile(tempPath, dest);
console.log(`Saved to ${dest}`);
// Echo it back
const media = await client.uploadMedia(tempPath, "image");
await client.sendRawMessage(info.chat, {
stickerMessage: {
URL: media.URL,
directPath: media.directPath,
mediaKey: media.mediaKey,
fileEncSHA256: media.fileEncSHA256,
fileSHA256: media.fileSHA256,
fileLength: String(media.fileLength),
mimetype: "image/webp",
width: 512,
height: 512,
},
});
});
async function main() {
const { jid } = await client.init();
if (!jid) {
console.error("Not paired! See: How to Pair WhatsApp");
process.exit(1);
}
await client.connect();
console.log("Listening for stickers...");
}
main().catch(console.error);
Common Pitfalls
Upload response fields use exact protobuf casing: URL, fileSHA256, fileEncSHA256 — not url, fileSha256. Using wrong casing will silently fail and the sticker won't be delivered.
Always use "image/webp" for stickers. Sending a PNG or JPEG as a sticker will either fail or display as a regular image.
Use "image" as the media type when calling uploadMedia(), even though it's a sticker. The encryption is handled the same way.





