Skip to main content

Getting Started

Quick Start

import { createClient } from "@whatsmeow-node/whatsmeow-node";

const client = createClient({ store: "session.db" });

client.on("qr", ({ code }) => console.log("Scan this QR:", code));
client.on("connected", ({ jid }) => console.log("Connected as", jid));
client.on("message", ({ info, message }) => {
console.log(`${info.pushName}: ${message.conversation ?? JSON.stringify(message)}`);
});

async function main() {
const { jid } = await client.init();
if (!jid) {
await client.getQRChannel();
}
await client.connect();
}
main();

Client Options

OptionTypeDefaultDescription
storestringrequiredSQLite path (session.db) or Postgres URL (postgres://...)
binaryPathstringautoPath to the Go binary (auto-resolved from platform package)
commandTimeoutnumber30000IPC command timeout in milliseconds

Sending Messages

Text message:

await client.sendMessage("5512345678@s.whatsapp.net", {
conversation: "Hello!",
});

Reply to a message:

await client.sendMessage(jid, {
extendedTextMessage: {
text: "This is a reply",
contextInfo: {
stanzaId: originalMessageId,
participant: originalSenderJid,
quotedMessage: { conversation: "the original text" },
},
},
});

Image, location, contact card — use sendRawMessage for any proto shape:

// Upload then send an image
const media = await client.uploadMedia("/path/to/photo.jpg", "image");
await client.sendRawMessage(jid, {
imageMessage: {
URL: media.URL,
directPath: media.directPath,
mediaKey: media.mediaKey,
fileEncSHA256: media.fileEncSHA256,
fileSHA256: media.fileSHA256,
fileLength: String(media.fileLength),
mimetype: "image/jpeg",
caption: "Check this out",
},
});

// Send a location
await client.sendRawMessage(jid, {
locationMessage: {
degreesLatitude: -34.9011,
degreesLongitude: -56.1645,
name: "Montevideo",
},
});

// Send a contact card
await client.sendRawMessage(jid, {
contactMessage: {
displayName: "John Doe",
vcard: "BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nTEL:+1234567890\nEND:VCARD",
},
});

sendRawMessage accepts any Record<string, unknown> matching the whatsmeow waE2E.Message proto schema.

Downloading Media

When you receive a message with media, download it to a temp file:

client.on("message", async ({ info, message }) => {
// downloadAny auto-detects the media type
if (message.imageMessage || message.videoMessage || message.audioMessage || message.documentMessage) {
const filePath = await client.downloadAny(message);
console.log("Media saved to:", filePath);
}
});

For more control, use downloadMediaWithPath with explicit keys:

const filePath = await client.downloadMediaWithPath({
directPath: msg.imageMessage.directPath,
mediaKey: msg.imageMessage.mediaKey,
fileHash: msg.imageMessage.fileSHA256,
encFileHash: msg.imageMessage.fileEncSHA256,
fileLength: msg.imageMessage.fileLength,
mediaType: "image",
});
Field naming

When receiving messages, field names follow proto casing (fileSHA256, fileEncSHA256). When passing arguments to download methods, use the method's own parameter names (fileHash, encFileHash). See Troubleshooting for details.

Close Cleanly

await client.disconnect();
client.close();