Polls¶
Polls in WhatsApp are end-to-end encrypted: each vote is encrypted on the voter's device and only the poll creator (and @arcaelas/whatsapp running on their session) can decrypt the tally. The library handles key derivation and decryption transparently — you only deal with content, options and count.
Encryption is automatic
The library derives the per-poll HMAC key, decrypts incoming pollUpdateMessage payloads and merges them into the original Poll instance. You never need to touch raw bytes or vote signatures.
Setup¶
import { WhatsApp } from '@arcaelas/whatsapp';
import { FileSystemEngine } from '@arcaelas/whatsapp/engines';
export const wa = new WhatsApp({
engine: new FileSystemEngine(__dirname),
phone: 14155551234,
});
await wa.connect((auth) => {
if (typeof auth === 'string') {
console.log('Pair code:', auth);
}
});
Creating a poll¶
wa.Message.poll(cid, { content, options }) posts a single-choice poll. content is the question; each entry in options is an object with a content string.
import { wa } from './client';
const GROUP_CID = '120363025912345678@g.us';
await wa.Message.poll(GROUP_CID, {
content: 'What should we order for lunch?',
options: [
{ content: 'Pizza' },
{ content: 'Sushi' },
{ content: 'Tacos' },
],
});
Receiving votes¶
Vote tallies arrive as message:updated events on the original poll. Detect with instanceof wa.Message.Poll, then read options (each entry is { content, count }) and the multiple flag.
import { wa } from './client';
wa.on('message:updated', (msg, chat) => {
if (!(msg instanceof wa.Message.Poll)) {
return;
}
console.log(`[${chat.name}] ${msg.caption}`);
console.log(`Mode: ${msg.multiple ? 'multi-select' : 'single-select'}`);
for (const option of msg.options) {
console.log(` ${option.content}: ${option.count}`);
}
});
Per-message subscription
If you only care about a specific poll, use poll.watch(handler) after creating it — the library returns an unsubscribe function and only fires for that exact message.
Voting programmatically¶
Call poll.select(index) to cast a single-choice vote, or poll.select([i, j]) for multi-select polls. Indices map to the order of options in the original PollOptions.
import { wa } from './client';
const POLL_CID = '120363025912345678@g.us';
const POLL_MID = '3EB0C7689C2E0F5A4F4E';
const poll = await wa.Message.get(POLL_CID, POLL_MID);
if (poll instanceof wa.Message.Poll) {
if (poll.multiple) {
await poll.select([0, 2]); // first and third option
} else {
await poll.select(1); // second option
}
}
Auto-vote bot (test helper)¶
Useful for integration tests: whenever a poll arrives in a watched chat, the bot picks a random valid option and votes. Demonstrates create + receive + vote in a single example.
import { wa } from './client';
const TEST_GROUP = '120363025912345678@g.us';
wa.on('message:created', async (msg) => {
if (!(msg instanceof wa.Message.Poll)) {
return;
}
if (msg.cid !== TEST_GROUP || msg.me) {
return;
}
const total_options = msg.options.length;
if (total_options === 0) {
return;
}
if (msg.multiple) {
// Pick a random non-empty subset.
const picks: number[] = [];
for (let i = 0; i < total_options; i++) {
if (Math.random() < 0.5) {
picks.push(i);
}
}
if (picks.length === 0) {
picks.push(Math.floor(Math.random() * total_options));
}
await msg.select(picks);
} else {
const choice = Math.floor(Math.random() * total_options);
await msg.select(choice);
}
console.log(`Auto-voted on "${msg.caption}"`);
});
Quoting a poll in a reply¶
Like every Message subclass, Poll inherits text(), image(), etc. — replying to a poll quotes it automatically.