npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

whalib

v1.2.1

Published

JavaScript / Node.js WhatsApp Web API Client — connect to WhatsApp Multi-Device, send messages, manage groups, handle media, and more

Readme

whalib

JavaScript / Node.js WhatsApp Web API Client

A lightweight, dependency-minimal WhatsApp Web API client for Node.js. Connect to WhatsApp Multi-Device, send and receive messages, manage groups, handle media, and much more — all from your own backend.

npm version License: MIT Node.js


Features

  • Full WhatsApp Multi-Device protocol support
  • QR Code and Pairing Code authentication
  • Send and receive text, images, videos, audio, documents, stickers, locations, contacts, polls, and more
  • End-to-end encryption via the Signal protocol (built-in implementation)
  • Group management (create, update, participants, invites)
  • Newsletter/Channel support
  • Community management
  • Business profile and catalog support
  • Presence updates (typing, online/offline)
  • Message receipts (delivered, read)
  • Message editing, deletion, reactions, and pinning
  • Disappearing messages
  • Link preview generation
  • Media upload and download with encryption
  • Persistent session storage via filesystem
  • Minimal dependencies, no native modules required

Table of Contents


Installation

npm install whalib

Requirements: Node.js 18 or higher.


Quick Start

const { makeSocket, useMultiFileAuthState, Browsers } = require('whalib');

async function start() {
    const { state, saveCreds } = await useMultiFileAuthState('./auth_session');

    const sock = makeSocket({
        auth: state,
        browser: Browsers.ubuntu('Chrome')
    });

    sock.ev.on('creds.update', saveCreds);

    sock.ev.on('connection.update', (update) => {
        const { connection, lastDisconnect, qr } = update;

        if (qr) {
            console.log('Scan this QR code with WhatsApp:');
            // Use a library like 'qrcode-terminal' to display in console
        }

        if (connection === 'open') {
            console.log('Connected to WhatsApp!');
        }

        if (connection === 'close') {
            const statusCode = lastDisconnect?.error?.statusCode;
            if (statusCode !== 401) {
                // Reconnect on non-logout disconnections
                setTimeout(start, 3000);
            } else {
                console.log('Logged out.');
            }
        }
    });

    sock.ev.on('messages.upsert', ({ messages, type }) => {
        for (const msg of messages) {
            if (!msg.key.fromMe && type === 'notify') {
                console.log('New message from', msg.key.remoteJid);
                console.log('Content:', msg.message);
            }
        }
    });
}

start();

Authentication

whalib supports two methods to link your application as a companion device: QR Code and Pairing Code.

QR Code

The default authentication method. When no existing session is found, whalib emits a qr string through the connection.update event. Display this QR code and scan it with WhatsApp on your phone (Linked Devices > Link a Device).

const qrcode = require('qrcode-terminal');
const { makeSocket, useMultiFileAuthState, Browsers } = require('whalib');

async function connectWithQR() {
    const { state, saveCreds } = await useMultiFileAuthState('./auth_session');

    const sock = makeSocket({
        auth: state,
        browser: Browsers.ubuntu('Chrome')
    });

    sock.ev.on('creds.update', saveCreds);

    sock.ev.on('connection.update', (update) => {
        if (update.qr) {
            qrcode.generate(update.qr, { small: true });
            console.log('Scan the QR code above with WhatsApp');
        }
        if (update.connection === 'open') {
            console.log('Successfully connected!');
        }
    });
}

connectWithQR();

Pairing Code

Link your device using an 8-character code instead of scanning a QR code. This is useful for server environments without display access.

const { makeSocket, useMultiFileAuthState, Browsers } = require('whalib');
const readline = require('readline');

async function connectWithPairingCode() {
    const { state, saveCreds } = await useMultiFileAuthState('./auth_session');

    const sock = makeSocket({
        auth: state,
        browser: Browsers.ubuntu('Chrome')
    });

    sock.ev.on('creds.update', saveCreds);

    sock.ev.on('connection.update', async (update) => {
        if (update.connection === 'connecting' && !state.creds.me) {
            // Request a pairing code for your phone number (with country code, no +)
            const code = await sock.requestPairingCode('1234567890');
            console.log('Enter this code on your phone:', code);
        }
        if (update.connection === 'open') {
            console.log('Paired successfully!');
        }
    });
}

connectWithPairingCode();

Open WhatsApp on your phone, go to Linked Devices > Link a Device > Link with Phone Number, and enter the code displayed in your console.

Session Persistence

whalib stores session data in a folder you specify. As long as the folder exists and contains valid session files, subsequent connections will restore the session automatically without needing to scan a QR code or enter a pairing code again.

// Session is saved in ./auth_session/
const { state, saveCreds } = await useMultiFileAuthState('./auth_session');

// Always save credential updates
sock.ev.on('creds.update', saveCreds);

To log out and remove the session:

// This deregisters the companion device from WhatsApp
await sock.logout();

// Optionally delete the session folder
const fs = require('fs');
fs.rmSync('./auth_session', { recursive: true, force: true });

Handling Events

whalib uses an event-based architecture. Subscribe to events using sock.ev.on(eventName, handler).

// New messages
sock.ev.on('messages.upsert', ({ messages, type }) => {
    for (const msg of messages) {
        console.log('Message:', msg.key.id, 'Type:', type);
    }
});

// Message status updates (delivery, read receipts)
sock.ev.on('messages.update', (updates) => {
    for (const update of updates) {
        console.log('Message', update.key.id, 'status:', update.update?.status);
    }
});

// Connection state changes
sock.ev.on('connection.update', (update) => {
    console.log('Connection:', update.connection);
});

// Credential updates (always handle this to persist session)
sock.ev.on('creds.update', saveCreds);

// Presence updates
sock.ev.on('presence.update', ({ id, presences }) => {
    console.log(id, 'is', presences);
});

// Group updates
sock.ev.on('groups.update', (updates) => {
    for (const group of updates) {
        console.log('Group updated:', group.id, group.subject);
    }
});

// Group participants changed
sock.ev.on('group-participants.update', ({ id, participants, action }) => {
    console.log('Group', id, ':', action, participants);
});

Sending Messages

Text Messages

// Simple text
await sock.sendMessage('[email protected]', {
    text: 'Hello from whalib!'
});

// Text with mentions
await sock.sendMessage('[email protected]', {
    text: '@User1 @User2 check this out',
    mentions: ['[email protected]', '[email protected]']
});

Images

const fs = require('fs');

// From file buffer
await sock.sendMessage('[email protected]', {
    image: fs.readFileSync('./photo.jpg'),
    caption: 'Check out this photo!',
    mimetype: 'image/jpeg'
});

// From URL
await sock.sendMessage('[email protected]', {
    image: { url: 'https://example.com/photo.jpg' },
    caption: 'Image from URL'
});

Videos

// Video with caption
await sock.sendMessage('[email protected]', {
    video: fs.readFileSync('./video.mp4'),
    caption: 'Watch this!',
    mimetype: 'video/mp4'
});

// GIF (set gifPlayback to true)
await sock.sendMessage('[email protected]', {
    video: fs.readFileSync('./animation.mp4'),
    gifPlayback: true,
    mimetype: 'video/mp4'
});

// PTV (circular video message)
await sock.sendMessage('[email protected]', {
    video: fs.readFileSync('./clip.mp4'),
    ptv: true,
    mimetype: 'video/mp4'
});

Audio and Voice Notes

// Audio file
await sock.sendMessage('[email protected]', {
    audio: fs.readFileSync('./song.mp3'),
    mimetype: 'audio/mpeg'
});

// Voice note (push-to-talk)
await sock.sendMessage('[email protected]', {
    audio: fs.readFileSync('./voice.ogg'),
    mimetype: 'audio/ogg; codecs=opus',
    ptt: true
});

Documents

await sock.sendMessage('[email protected]', {
    document: fs.readFileSync('./report.pdf'),
    mimetype: 'application/pdf',
    fileName: 'Monthly Report.pdf',
    caption: 'Here is the report'
});

Stickers

await sock.sendMessage('[email protected]', {
    sticker: fs.readFileSync('./sticker.webp'),
    mimetype: 'image/webp'
});

Location

await sock.sendMessage('[email protected]', {
    location: {
        degreesLatitude: 48.8584,
        degreesLongitude: 2.2945,
        name: 'Eiffel Tower',
        address: 'Champ de Mars, Paris, France'
    }
});

Contacts

// Single contact
const vcard = `BEGIN:VCARD
VERSION:3.0
FN:John Doe
TEL;type=CELL;type=VOICE:+1234567890
END:VCARD`;

await sock.sendMessage('[email protected]', {
    contacts: {
        displayName: 'John Doe',
        contacts: [{ displayName: 'John Doe', vcard }]
    }
});

Reactions

// React to a message
await sock.sendMessage('[email protected]', {
    react: {
        text: '👍',
        key: message.key  // The key of the message to react to
    }
});

// Remove reaction
await sock.sendMessage('[email protected]', {
    react: {
        text: '',  // Empty string removes the reaction
        key: message.key
    }
});

Polls

await sock.sendMessage('[email protected]', {
    poll: {
        name: 'What should we eat?',
        values: ['Pizza', 'Sushi', 'Tacos', 'Burgers'],
        selectableCount: 1  // Single choice (0 or undefined = multiple choice)
    }
});

Buttons and Lists

// Buttons
await sock.sendMessage('[email protected]', {
    buttons: {
        text: 'Choose an option:',
        footer: 'Powered by whalib',
        buttons: [
            { buttonId: 'btn1', displayText: 'Option 1' },
            { buttonId: 'btn2', displayText: 'Option 2' },
            { buttonId: 'btn3', displayText: 'Option 3' }
        ]
    }
});

// List
await sock.sendMessage('[email protected]', {
    listMessage: {
        title: 'Menu',
        description: 'Select from the list below',
        buttonText: 'View Menu',
        footerText: 'whalib',
        sections: [
            {
                title: 'Main Dishes',
                rows: [
                    { title: 'Pizza', description: 'Classic Margherita', rowId: 'pizza' },
                    { title: 'Pasta', description: 'Carbonara', rowId: 'pasta' }
                ]
            },
            {
                title: 'Drinks',
                rows: [
                    { title: 'Water', rowId: 'water' },
                    { title: 'Coffee', rowId: 'coffee' }
                ]
            }
        ]
    }
});

Template Buttons

await sock.sendMessage('[email protected]', {
    templateButtons: {
        text: 'Visit us!',
        footer: 'whalib',
        buttons: [
            { urlButton: { displayText: 'Visit Website', url: 'https://example.com' } },
            { callButton: { displayText: 'Call Us', phoneNumber: '+1234567890' } },
            { quickReplyButton: { displayText: 'Quick Reply', id: 'reply-1' } }
        ]
    }
});

Events

await sock.sendMessage('[email protected]', {
    event: {
        name: 'Team Meeting',
        description: 'Weekly sync-up call',
        startDate: new Date('2026-04-01T14:00:00Z'),
        location: 'Conference Room A'
    }
});

Replying and Quoting

Quote a message by passing it in the quoted option:

sock.ev.on('messages.upsert', async ({ messages }) => {
    const msg = messages[0];
    if (!msg.key.fromMe && msg.message?.conversation) {
        await sock.sendMessage(msg.key.remoteJid, {
            text: 'Thanks for your message!'
        }, {
            quoted: msg
        });
    }
});

Editing Messages

Edit a previously sent message:

const sent = await sock.sendMessage('[email protected]', {
    text: 'Hello!'
});

// Edit it later
await sock.sendMessage('[email protected]', {
    edit: sent.key,
    text: 'Hello! (edited)'
});

Deleting Messages

Delete a message for everyone:

await sock.sendMessage('[email protected]', {
    delete: message.key
});

Forwarding Messages

Forward a message to another chat:

await sock.sendMessage('[email protected]', {
    forward: originalMessage
});

View Once Messages

Send a photo or video that can only be viewed once:

await sock.sendMessage('[email protected]', {
    image: fs.readFileSync('./secret.jpg'),
    caption: 'This will disappear after viewing',
    viewOnce: true
});

Disappearing Messages

Enable or disable disappearing messages for a chat:

// Enable (24 hours)
await sock.sendMessage('[email protected]', {
    disappearingMessagesInChat: 86400
});

// Disable
await sock.sendMessage('[email protected]', {
    disappearingMessagesInChat: false
});

Media Download

Download media from a received message:

const { downloadMediaMessage } = require('whalib');

sock.ev.on('messages.upsert', async ({ messages }) => {
    const msg = messages[0];
    if (msg.message?.imageMessage) {
        const buffer = await downloadMediaMessage(msg, 'buffer', {});
        fs.writeFileSync('./downloaded.jpg', buffer);
        console.log('Image saved!');
    }
});

Presence Updates

Let contacts know when you are typing or recording:

// Show "typing..."
await sock.sendPresenceUpdate('composing', '[email protected]');

// Show "recording audio..."
await sock.sendPresenceUpdate('recording', '[email protected]');

// Clear typing indicator
await sock.sendPresenceUpdate('paused', '[email protected]');

// Set yourself as online/offline
await sock.sendPresenceUpdate('available');
await sock.sendPresenceUpdate('unavailable');

Read Receipts

Mark messages as read:

// Mark a single message as read
await sock.sendReceipt(
    '[email protected]',
    undefined,
    ['MESSAGE_ID'],
    'read'
);

// Mark multiple messages as read
await sock.sendReceipt(
    '[email protected]',
    undefined,
    ['MSG_ID_1', 'MSG_ID_2', 'MSG_ID_3'],
    'read'
);

// Mark group message as read (requires participant)
await sock.sendReceipt(
    '[email protected]',
    '[email protected]',
    ['MESSAGE_ID'],
    'read'
);

Profile

// Update your display name
await sock.updateProfileName('My Bot');

// Update profile picture (for yourself or a group)
await sock.updateProfilePicture('[email protected]', {
    url: './avatar.jpg'
});

// Check if a phone number is on WhatsApp
const [result] = await sock.onWhatsApp('1234567890');
if (result?.exists) {
    console.log('User is on WhatsApp:', result.jid);
}

Group Management

// Create a group
const group = await sock.groupCreate('My Group', [
    '[email protected]',
    '[email protected]'
]);
console.log('Group created:', group.id);

// Update group subject
await sock.groupUpdateSubject(group.id, 'New Group Name');

// Update group description
await sock.groupUpdateDescription(group.id, 'This is our group');

// Add participants
await sock.groupParticipantsUpdate(group.id, [
    '[email protected]'
], 'add');

// Remove participants
await sock.groupParticipantsUpdate(group.id, [
    '[email protected]'
], 'remove');

// Promote to admin
await sock.groupParticipantsUpdate(group.id, [
    '[email protected]'
], 'promote');

// Demote from admin
await sock.groupParticipantsUpdate(group.id, [
    '[email protected]'
], 'demote');

// Get invite code
const code = await sock.groupInviteCode(group.id);
console.log('Invite link: https://chat.whatsapp.com/' + code);

// Revoke invite code
await sock.groupRevokeInvite(group.id);

// Leave group
await sock.groupLeave(group.id);

// Get group metadata
const metadata = await sock.groupMetadata(group.id);
console.log('Members:', metadata.participants.length);

WhatsApp IDs (JIDs)

WhatsApp uses JIDs (Jabber IDs) to identify users, groups, and other entities:

| Type | Format | Example | |------|--------|---------| | User | [country code][number]@s.whatsapp.net | [email protected] | | Group | [timestamp]-[creator]@g.us | [email protected] | | Broadcast | status@broadcast | status@broadcast | | Newsletter | [id]@newsletter | 120363012345@newsletter |

Utility functions for working with JIDs:

const { jidDecode, jidEncode, jidNormalizedUser, isJidGroup } = require('whalib');

// Decode a JID
const decoded = jidDecode('1234567890:[email protected]');
// { user: '1234567890', device: 5, server: 's.whatsapp.net' }

// Normalize (remove device part)
const normalized = jidNormalizedUser('1234567890:[email protected]');
// '[email protected]'

// Check type
isJidGroup('[email protected]');  // true

Socket Configuration

The makeSocket function accepts a configuration object:

const sock = makeSocket({
    auth: state,                          // Required. Auth state from useMultiFileAuthState
    browser: Browsers.ubuntu('Chrome'),   // Browser identity
    version: [2, 3000, 1034762614],       // WhatsApp Web version (auto-fetched if omitted)
    logger: pinoLogger,                   // Custom logger (pino recommended)
    connectTimeoutMs: 20000,              // Connection timeout (default: 20s)
    keepAliveIntervalMs: 30000,           // Heartbeat interval (default: 30s)
    defaultQueryTimeoutMs: 60000,         // Query timeout (default: 60s)
    syncFullHistory: false,               // Request full chat history on first connect
    maxMsgRetryCount: 5,                  // Max message retry attempts
    markOnlineOnConnect: true,            // Automatically set presence to online
    fireInitQueries: true,               // Run initialization queries on connect
    emitOwnEvents: true,                 // Emit events for your own sent messages
});

Browser & Platform Configuration

whalib supports a wide range of operating systems and browsers for your WhatsApp Web client identity. You can use any combination — whatever you pass in the browser config will be sent to WhatsApp during pairing.

OS Presets

Each preset is a function that takes a browser name and returns a [os, browser, version] tuple:

const { Browsers } = require('whalib');

// Linux distributions
Browsers.ubuntu('Chrome')      // ['Ubuntu', 'Chrome', '22.04.4']
Browsers.linux('Firefox')      // ['Linux', 'Firefox', '6.5.0']
Browsers.fedora('Firefox')     // ['Fedora', 'Firefox', '39']
Browsers.debian('Chrome')      // ['Debian', 'Chrome', '12.5']
Browsers.arch('Firefox')       // ['Arch', 'Firefox', '2024.03.01']
Browsers.centOS('Chrome')      // ['CentOS', 'Chrome', '9']
Browsers.redHat('Firefox')     // ['Red Hat', 'Firefox', '9.3']
Browsers.mint('Firefox')       // ['Mint', 'Firefox', '21.3']
Browsers.manjaro('Firefox')    // ['Manjaro', 'Firefox', '23.1']
Browsers.kali('Firefox')       // ['Kali', 'Firefox', '2024.1']
Browsers.openSUSE('Chrome')    // ['openSUSE', 'Chrome', '15.5']

// Desktop OS
Browsers.macOS('Safari')       // ['Mac OS', 'Safari', '14.4.1']
Browsers.windows('Edge')       // ['Windows', 'Edge', '10.0.22631']
Browsers.chromeOS('Chrome')    // ['Chrome OS', 'Chrome', '120.0']

// BSD / Unix
Browsers.freeBSD('Firefox')    // ['FreeBSD', 'Firefox', '14.0']
Browsers.openBSD('Firefox')    // ['OpenBSD', 'Firefox', '7.5']
Browsers.solaris('Firefox')    // ['Solaris', 'Firefox', '11.4']
Browsers.aix('Firefox')        // ['AIX', 'Firefox', '7.3']
Browsers.haiku('Epiphany')     // ['Haiku', 'Epiphany', 'R1/beta5']

// Mobile
Browsers.android('Chrome')     // ['Android', 'Chrome', '14.0']
Browsers.iOS('Safari')         // ['iOS', 'Safari', '17.4.1']

// Other
Browsers.tizen('Samsung Internet') // ['Tizen', 'Samsung Internet', '8.0']
Browsers.harmonyOS('Chrome')   // ['HarmonyOS', 'Chrome', '4.0']
Browsers.kaiOS('Firefox')      // ['KaiOS', 'Firefox', '3.1']
Browsers.sailfish('Firefox')   // ['Sailfish', 'Firefox', '4.5']
Browsers.fuchsia('Chrome')     // ['Fuchsia', 'Chrome', '1.0']

// Special
Browsers.whalib('Chrome')      // ['Ubuntu', 'Chrome', '22.04.4'] (library default)
Browsers.appropriate('Chrome')  // Auto-detects your OS and uses its version

Supported Browsers

Any of these browsers can be passed to any OS preset:

| Browser | Platform Type | Browser | Platform Type | |---------|--------------|---------|--------------| | Chrome | Chrome | Brave | Chrome | | Firefox | Firefox | Vivaldi | Chrome | | Safari | Safari | Arc | Chrome | | Edge | Edge | Chromium | Chrome | | Opera | Opera | Tor | Firefox | | IE | IE | Waterfox | Firefox | | DuckDuckGo | Chrome | LibreWolf | Firefox | | Samsung Internet | Chrome | Pale Moon | Firefox | | UC Browser | Chrome | Midori | Chrome | | Yandex | Chrome | Epiphany | Chrome | | Silk | Chrome | Konqueror | Chrome | | Maxthon | Chrome | Falkon | Chrome | | Whale | Chrome | Lynx | Chrome | | Orion | Safari | Ungoogled Chromium | Chrome |

Custom Browser Identity

You can create a fully custom browser identity:

const { Browsers } = require('whalib');

// Using Browsers.custom(osName, browserName, osVersion)
const sock = makeSocket({
    auth: state,
    browser: Browsers.custom('Gentoo', 'Brave', '2024.01')
});

Auto-Detect Platform

Use Browsers.appropriate() to automatically detect your OS:

const sock = makeSocket({
    auth: state,
    browser: Browsers.appropriate('Chrome')  // Detects your OS automatically
});

Helper Functions

const {
    getPlatformId,
    getBrowserVersion,
    getOSVersion,
    listSupportedBrowsers,
    listSupportedPlatforms
} = require('whalib');

getPlatformId('Firefox')         // '2' — WhatsApp platform type ID
getBrowserVersion('Chrome')      // '131.0.6778.86'
getOSVersion('Ubuntu')           // '22.04.4'
listSupportedBrowsers()          // ['Chrome', 'Firefox', 'Safari', ...]
listSupportedPlatforms()         // ['Ubuntu', 'Linux', 'Mac OS', ...]

Events Reference

| Event | Payload | Description | |-------|---------|-------------| | connection.update | { connection, qr, lastDisconnect } | Connection state changes | | creds.update | Partial<AuthenticationCreds> | Credentials updated (must save) | | messages.upsert | { messages, type } | New messages received or sent | | messages.update | MessageUpdate[] | Message status changes | | presence.update | { id, presences } | Contact presence updates | | groups.upsert | GroupMetadata[] | New groups added | | groups.update | Partial<GroupMetadata>[] | Group info changed | | group-participants.update | { id, participants, action } | Group members changed | | messaging-history.set | { chats, contacts, messages } | History sync data | | call | WACallEvent[] | Incoming/outgoing calls |


Error Handling and Reconnection

whalib provides disconnect reason codes to help you decide whether to reconnect:

const { makeSocket, useMultiFileAuthState, DISCONNECT_REASON, Browsers } = require('whalib');

async function connect() {
    const { state, saveCreds } = await useMultiFileAuthState('./auth_session');

    const sock = makeSocket({
        auth: state,
        browser: Browsers.ubuntu('Chrome')
    });

    sock.ev.on('creds.update', saveCreds);

    sock.ev.on('connection.update', (update) => {
        const { connection, lastDisconnect } = update;

        if (connection === 'close') {
            const statusCode = lastDisconnect?.error?.statusCode
                || lastDisconnect?.error?.output?.statusCode;
            const reason = lastDisconnect?.error?.message || 'Unknown';

            console.log(`Disconnected: ${reason} (code: ${statusCode})`);

            if (statusCode === DISCONNECT_REASON.loggedOut) {
                console.log('Session expired. Please re-authenticate.');
            } else if (statusCode === DISCONNECT_REASON.restartRequired) {
                console.log('Restart required. Reconnecting...');
                setTimeout(connect, 1000);
            } else {
                console.log('Reconnecting in 3 seconds...');
                setTimeout(connect, 3000);
            }
        }

        if (connection === 'open') {
            console.log('Connected!');
        }
    });
}

connect();

Full Example: Echo Bot

A complete example that echoes back any text message it receives:

const { makeSocket, useMultiFileAuthState, Browsers } = require('whalib');
const qrcode = require('qrcode-terminal');

async function startEchoBot() {
    const { state, saveCreds } = await useMultiFileAuthState('./echo_bot_session');

    const sock = makeSocket({
        auth: state,
        browser: Browsers.ubuntu('Chrome')
    });

    sock.ev.on('creds.update', saveCreds);

    sock.ev.on('connection.update', (update) => {
        if (update.qr) {
            qrcode.generate(update.qr, { small: true });
        }
        if (update.connection === 'open') {
            console.log('Echo bot is online!');
        }
        if (update.connection === 'close') {
            console.log('Disconnected. Reconnecting...');
            setTimeout(startEchoBot, 3000);
        }
    });

    sock.ev.on('messages.upsert', async ({ messages, type }) => {
        if (type !== 'notify') return;

        for (const msg of messages) {
            if (msg.key.fromMe) continue;

            const text = msg.message?.conversation
                || msg.message?.extendedTextMessage?.text;

            if (text) {
                await sock.sendMessage(msg.key.remoteJid, {
                    text: `Echo: ${text}`
                }, {
                    quoted: msg
                });
            }
        }
    });
}

startEchoBot();

Disclaimer

This project is not affiliated with, associated with, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or affiliates. The official WhatsApp website can be found at https://whatsapp.com. "WhatsApp" and related names, marks, emblems and images are registered trademarks of their respective owners. Use at your own risk.


License

MIT License - see LICENSE for details.