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

innovators-bot2

v2.0.1

Published

WhatsApp API

Readme

INNOVATORS SOFT WhatsApp Bot 2

A powerful WhatsApp client library that provides seamless integration between Baileys and WhatsApp-web.js style APIs. This library makes it easy to create WhatsApp bots and automation tools with a familiar interface.

Features

  • 🚀 Easy to use, familiar WhatsApp-web.js style API
  • 📱 Multi-device support (Baileys v7.x.x)
  • 💬 Send and receive messages
  • � Message reactions (add/remove emoji reactions)
  • �📸 Media handling (images, videos, documents)
  • 👥 Group management
  • 💾 Message history and chat management
  • 🔄 Auto-reconnect functionality
  • 📝 Read receipts
  • 🔐 LID (Local Identifier) support for enhanced privacy
  • 🗂️ Signal repository store for LID/PN mapping

Installation

npm install innovators-bot2

Quick Start With Qr Code

const { WhatsAppClient } = require('innovators-bot2')
const qrcode = require('qrcode-terminal')

// Create client instance
const client = new WhatsAppClient({ sessionName: ".Sessions" });

// Handle QR Code
client.on('qr', qr => {
    qrcode.generate(qr, { small: true })
})

// Handle ready event
client.on('connected', () => {
    console.log('Client is ready!')
})

// Connect to WhatsApp
client.connect()

Quick Start With Pairing code

const { WhatsAppClient } = require('innovators-bot2')
const qrcode = require('qrcode-terminal')
const config = require('./config.json');

// Get authmethod from config file (default to 'qr' if not specified)
const authMethod =  (config.whatsapp && config.whatsapp.authMethod) || 'qr';

const client = new WhatsAppClient({
    sessionName: ".Sessions",
    authmethod: authMethod
});

// Handle ready event
client.on('connected', () => {
    console.log('Client is ready!')
})

// Connect to WhatsApp
client.connect()

Usage Examples

1. Basic Messaging

// Send a text message
await client.sendMessage('[email protected]', 'Hello world!')

// Send a reply
await client.reply('[email protected]', 'This is a reply', {
    quoted: originalMessage
})

// Send with mentions
await client.sendMessage('[email protected]', {
    type: 'text',
    text: 'Hey @user!',
    mentions: ['[email protected]']
})

2. Media Handling

// Send an image
await client.sendMedia('[email protected]', './image.jpg', {
    caption: 'Check out this image!'
})

// Send a document
await client.sendDocument('[email protected]', './document.pdf', 
    'Check out this document!'
)

3. Sticker Management

Create stickers easily from any image buffer with automatic conversion and metadata support.

const fs = require('fs');

// Send a sticker from an image or video buffer
const buffer = fs.readFileSync('./image.jpg');
await client.sendSticker('[email protected]', buffer, {
    packName: 'Innovators',
    author: 'Innovators Bot',
    type: 'full', // 'full' or 'crop'
    quality: 50
});

4. Anti-Delete System

The library includes a built-in Anti-Delete system that tracks deleted messages in real-time.

// Listen for deleted messages
client.on('message-deleted', async (data) => {
    console.log(`User ${data.jid} deleted a message!`);
    
    // Content of the deleted message
    const original = data.originalMessage;
    
    // Reply to the chat with the deleted content
    await client.sendMessage(data.jid, 'I saw that! 😉', { 
        quoted: original 
    });
});

5. Group Management

// Get all groups
const groups = await client.getAllGroups()

// Get group metadata (participants, name, description...)
const metadata = await client.getGroupMetadata(groupId)
console.log(metadata.id, metadata.subject, metadata.desc)

// Create a new group
const newGroup = await client.createGroup('Group Name', ['[email protected]'])
console.log('Created group:', newGroup.id)

// Change group subject (name)
await client.changeGroupSubject(groupId, 'New Group Name')

// Change group description
await client.changeGroupDescription(groupId, 'New description for the group')

// Change group settings
// Options: 'announcement' (only admins send), 'not_announcement' (everyone sends),
//          'locked' (only admins edit info), 'unlocked' (everyone edits info)
await client.changeGroupSettings(groupId, 'announcement')

// Get group invite code
const code = await client.getGroupInviteCode(groupId)
console.log('Invite link: https://chat.whatsapp.com/' + code)

// Revoke invite code (generates a new one)
const newCode = await client.revokeGroupInviteCode(groupId)
console.log('New invite link: https://chat.whatsapp.com/' + newCode)

// Join group by invite code
const joinedGroupId = await client.joinGroupByInviteCode('AbCdEfGhIjK')
// Also accepts full URL - it strips the prefix automatically
await client.joinGroupByInviteCode('https://chat.whatsapp.com/AbCdEfGhIjK')

// Get group info by invite code (without joining)
const groupInfo = await client.getGroupInfoByInviteCode('AbCdEfGhIjK')
console.log('Group name:', groupInfo.subject)

// Leave a group
await client.leaveGroup(groupId)

// Add participant to group
// Note: If adding fails due to user's privacy settings (403), 
// an invitation link is automatically sent to the user instead.
const result = await client.changeGroupParticipants(groupId, ['[email protected]'], 'add')

if (result[0].status === 403 && result[0].invitationSent) {
    console.log('User has privacy settings enabled. Invitation link sent!')
}

// Send a manual group invitation link
await client.sendGroupInvitation(groupId, '[email protected]', 'Join my group!')

// Remove participant
await client.changeGroupParticipants(groupId, ['[email protected]'], 'remove')

// Promote to admin
await client.changeGroupParticipants(groupId, ['[email protected]'], 'promote')

// Demote admin
await client.changeGroupParticipants(groupId, ['[email protected]'], 'demote')

// Get pending join requests
const requests = await client.getGroupJoinRequests(groupId)
console.log('Pending requests:', requests)

// Approve/Reject join requests
await client.handleGroupJoinRequest(groupId, ['[email protected]'], 'approve')
await client.handleGroupJoinRequest(groupId, ['[email protected]'], 'reject')

// Toggle ephemeral (disappearing) messages
// Options: 0 (off), 86400 (24h), 604800 (7d), 7776000 (90d)
await client.toggleGroupEphemeral(groupId, 86400)

// Change who can add members
// Options: 'all_member_add' or 'admin_add'
await client.changeGroupAddMode(groupId, 'admin_add')

6. Privacy Management

// Block a user
await client.blockUser('[email protected]')

// Unblock a user
await client.unblockUser('[email protected]')

// Get all privacy settings
const settings = await client.getPrivacySettings()
console.log('Privacy settings:', settings)

// Get blocked contacts list
const blocklist = await client.getBlockList()
console.log('Blocked users:', blocklist)

// Update last seen privacy
// Options: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateLastSeenPrivacy('contacts')

// Update online status privacy
// Options: 'all' | 'match_last_seen'
await client.updateOnlinePrivacy('match_last_seen')

// Update profile picture privacy
// Options: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateProfilePicturePrivacy('contacts')

// Update status privacy
// Options: 'all' | 'contacts' | 'contact_blacklist' | 'none'
await client.updateStatusPrivacy('contacts')

// Update read receipts privacy
// Options: 'all' | 'none'
await client.updateReadReceiptsPrivacy('all')

// Update who can add you to groups
// Options: 'all' | 'contacts' | 'contact_blacklist'
await client.updateGroupsAddPrivacy('contacts')

// Update default disappearing mode for new chats
// Options: 0 (off), 86400 (24h), 604800 (7d), 7776000 (90d)
await client.updateDefaultDisappearingMode(604800)

7. Interactive Messages

Buttons

// Send interactive buttons
await client.sendButtons('[email protected]', {
    text: 'Do you like this bot?',
    title: 'Feedback',
    subtitle: 'Let us know!',
    footer: 'Powered by Baileys',
    interactiveButtons: [
        {
            name: 'quick_reply',
            buttonParamsJson: JSON.stringify({
                display_text: '✅ Yes',
                id: 'text_yes'
            })
        },
        {
            name: 'quick_reply',
            buttonParamsJson: JSON.stringify({
                display_text: '❌ No',
                id: 'text_no'
            })
        }
    ]
});

List Messages

// Send interactive list
await client.SendList('[email protected]', {
    text: 'Please select an option:',
    title: 'Main Menu',
    buttonText: 'View Options',
    footer: 'Scroll to see more options',
    sections: [
        {
            title: 'Account',
            rows: [
                { title: 'Profile', id: 'profile', description: 'View your profile' },
                { title: 'Settings', id: 'settings', description: 'Account settings' }
            ]
        },
        {
            title: 'Help',
            rows: [
                { title: 'Support', id: 'support', description: 'Contact support' },
                { title: 'About', id: 'about', description: 'About this bot' }
            ]
        }
    ]
});

8. Message History

// Get chat history
const messages = await client.loadMessages(chatId, 50)

// Get specific message
const message = await client.loadMessage(chatId, messageId)

More Examples and Information

For a complete working example with message handling, group management, and error handling, check out our example.js file. This example includes:

  • 🔄 Connection handling and QR code generation
  • 📨 Message handling with commands
  • 👥 Group management examples
  • ⚡ Event listeners for various scenarios
  • 🛠️ Error handling and logging

Feel free to use this example as a starting point for your WhatsApp bot implementation.

Bot Commands

The library includes example bot commands that you can use:

Basic Commands

  • !ping - Check if bot is alive
  • !echo <text> - Echo back your text
  • !help - Show all available commands

Messaging

  • !mention - Mention you in a message
  • !reply - Reply to your message
  • !react - React to your message with ❤️
  • !read - Mark messages as read
  • !typing - Show typing indicator
  • !recording - Show recording indicator
  • !paused - Clear typing or recording indicator

Media & Content

  • !media - Send an example image
  • !doc - Send an example document
  • !location - Send a location
  • !contact - Send a contact card
  • !sticker - Create a sticker from an image
  • !ad - Send an ad reply message

Group Management

  • !groups - List all your groups
  • !add <number> - Add participant to group
  • !remove <number> - Remove participant from group
  • !promote <number> - Promote participant to admin
  • !demote <number> - Demote admin to participant
  • !invite <number> - Send group invite link to user
  • !creategroup <name> - Create a new group
  • !groupsubject <name> - Change group name
  • !groupdesc <text> - Change group description
  • !groupsetting <setting> - Change group settings (announcement/not_announcement/locked/unlocked)
  • !invitecode - Get group invite code/link
  • !revokeinvite - Revoke current invite code and generate new one
  • !leavegroup - Leave the current group
  • !joingroup <code> - Join a group by invite code
  • !groupinfo <code> - Get group info by invite code without joining
  • !joinrequests - List pending join requests
  • !approvejoin <number> - Approve a join request
  • !rejectjoin <number> - Reject a join request
  • !ephemeral <seconds> - Toggle disappearing messages (0/86400/604800/7776000)
  • !addmode <mode> - Change who can add members (all_member_add/admin_add)

🔒 Privacy

  • !block <number> - Block a user
  • !unblock <number> - Unblock a user
  • !privacy - View all privacy settings
  • !blocklist - List all blocked contacts
  • !lastseenprivacy <value> - Update last seen privacy (all/contacts/contact_blacklist/none)
  • !onlineprivacy <value> - Update online privacy (all/match_last_seen)
  • !pfpprivacy <value> - Update profile picture privacy (all/contacts/contact_blacklist/none)
  • !statusprivacy <value> - Update status privacy (all/contacts/contact_blacklist/none)
  • !readreceiptprivacy <value> - Update read receipts privacy (all/none)
  • !groupaddprivacy <value> - Update who can add you to groups (all/contacts/contact_blacklist)
  • !disappearing <seconds> - Update default disappearing mode (0/86400/604800/7776000)

Interactive Messages

  • !buttons - Show interactive buttons
  • !list - Display a scrollable list
  • !logout - Logout from current session

🛡️ Protection

  • Anti-Delete - Automatically tracks and emits events for deleted messages

🔐 JID & LID/PN Management (v7.x.x)

  • !lid - Get your LID (Local Identifier)
  • !pn <lid> - Get phone number from a LID
  • !parse <jid> - Parse detailed JID information
  • !normalize <number> - Normalize a number to JID format

Connection Events

// When QR code is generated
client.on('qr', qr => {
    qrcode.generate(qr, { small: true })
})

// When connection is established
client.on('connected', () => {
    console.log('Client is ready!')
})

// When connection is in progress
client.on('connecting', (message) => {
    console.log('Connection status:', message)
})

// When disconnected
client.on('disconnected', (error) => {
    console.log('Client disconnected:', error)
})

Message Events

// When a new message is received
client.on('message', async msg => {
    console.log('Message from:', msg.from)
    console.log('Message content:', msg.body)
    
    // Mark message as read
    await client.readMessage(msg.raw.key)
    
    // Handle different message types
    if (msg.hasMedia) {
        console.log('Message contains media')
        // Handle media message
    }
})

Message Reaction Events

Listen for when users add or remove reactions (emojis) from messages:

// When a message receives a reaction
client.on('message-reaction', async (reaction) => {
    console.log('Reaction received!')
    console.log('Chat:', reaction.from)
    console.log('Sender:', reaction.sender)
    console.log('Emoji:', reaction.emoji)
    console.log('Is removed:', reaction.isRemoved)
    
    // Check if reaction was added or removed
    if (reaction.isRemoved) {
        console.log('User removed their reaction')
    } else {
        console.log(`User reacted with: ${reaction.emoji}`)
    }
    
    // Access the message key that was reacted to
    console.log('Message ID:', reaction.messageKey.id)
    
    // For group messages, get the participant who reacted
    if (reaction.from.endsWith('@g.us')) {
        console.log('Participant who reacted:', reaction.sender)
    }
})

Reaction Event Data Structure

The message-reaction event provides the following data:

| Property | Type | Description | |----------|------|-------------| | from | string | Chat JID where the reaction occurred (prefers PN over LID) | | sender | string | JID of the user who reacted (in groups, this is the participant) | | participant | string\|null | Original participant JID (could be LID or PN) | | participantAlt | string\|null | Alternate participant JID format | | emoji | string\|null | The emoji used for the reaction (null if removed) | | isRemoved | boolean | true if the reaction was removed, false if added | | messageKey | object | The message key object that was reacted to | | timestamp | Date | When the reaction event was processed | | raw | object | Raw reaction data from Baileys |

Sending Reactions

You can also send reactions to messages programmatically:

// React to a message
await client.sendMessage(chatId, {
    type: 'reaction',
    emoji: '❤️',
    messageKey: messageToReactTo.key
})

// Remove a reaction (send empty emoji)
await client.sendMessage(chatId, {
    type: 'reaction',
    emoji: '',
    messageKey: messageToReactTo.key
})

LID Mapping Events

// Listen for LID/PN mapping updates
client.on('lid-mapping-update', (update) => {
    console.log('New LID/PN mappings received:', update)
    // Handle new mappings as needed
})

Error Handling

// Global error handler
client.on('error', error => {
    console.error('Client Error:', error)
    // Handle specific error types
    if (error.message.includes('Connection Closed')) {
        console.log('Attempting to reconnect...')
        client.connect()
    }
})

// Example with try-catch
try {
    await client.sendMessage(to, message)
} catch (error) {
    console.error('Error sending message:', error)
    if (error.message.includes('Not connected')) {
        console.log('Reconnecting...')
        await client.connect()
    }
}

Baileys v7.x.x LID Store Implementation

Overview

This library fully supports Baileys v7.x.x LID (Local Identifier) system for enhanced privacy and WhatsApp's transition to username-based identification.

| Feature | Description | |---------|-------------| | LID Support | Full support for Local Identifiers alongside Phone Numbers | | Store Access | Automatic initialization via client.sock.signalRepository.lidMapping | | Helper Methods | getLIDForPN(), getPNForLID(), getLIDsForPNs() | | Event Handling | lid-mapping-update event for real-time mapping updates | | Message Handling | Automatic preference for PN over LID with fallback support | | Compatibility | Backward compatible with v6.x code patterns |

What are LIDs?

LID (Local Identifier) is WhatsApp's privacy feature that replaces phone numbers in large groups. Key points:

  • Unique per user (not per group)
  • Ensures user anonymity in large groups
  • Allows messaging users via either LID or PN (Phone Number)
  • Part of WhatsApp's transition to username system (@username)

JID Format Changes

Accessing the Store

The store is automatically initialized when you create a WhatsAppClient and is accessible via the internal socket:

const client = new WhatsAppClient({ sessionName: ".Sessions" });
await client.connect();

// Store is available internally as client.store
// Access via: client.sock.signalRepository.lidMapping

Available Methods

The WhatsAppClient provides convenient methods to work with LID/PN mappings:

Quick Reference

// Get LID from Phone Number
const lid = await client.getLIDForPN('[email protected]');

// Get Phone Number from LID
const pn = await client.getPNForLID('123456@lid');

// Get multiple LIDs
const lids = await client.getLIDsForPNs(['[email protected]', '[email protected]']);

Detailed Examples

// Get LID from Phone Number
const lid = await client.getLIDForPN('[email protected]');
console.log('LID:', lid);

// Get Phone Number from LID
const pn = await client.getPNForLID('123456@lid');
console.log('Phone Number:', pn);

// Get multiple LIDs from multiple PNs
const lids = await client.getLIDsForPNs([
    '[email protected]',
    '[email protected]'
]);
console.log('LIDs:', lids);

Message Handling with LID Support

The library automatically handles both LID and PN formats in messages:

client.on('message', async msg => {
    // msg.from will prefer PN over LID when available
    console.log('Message from:', msg.from);
    
    // Access raw message key for both formats
    const remoteJid = msg.raw.key.remoteJid;        // Primary JID
    const remoteJidAlt = msg.raw.key.remoteJidAlt; // Alternate JID
    
    // For group messages
    const participant = msg.raw.key.participant;       // Could be LID or PN
    const participantAlt = msg.raw.key.participantAlt; // Alternate format
    
    // Convert LID to PN if needed
    if (remoteJid.endsWith('@lid')) {
        const phoneNumber = await client.getPNForLID(remoteJid);
        console.log('Phone number:', phoneNumber);
    }
});

Best Practices

1. Prefer PN over LID for Compatibility

const getPreferredJid = (messageKey) => {
    if (messageKey.remoteJidAlt?.endsWith('@s.whatsapp.net')) {
        return messageKey.remoteJidAlt; // Use PN
    }
    return messageKey.remoteJid; // Fallback to primary JID
};

2. Convert LID to PN When Needed

const convertToPN = async (jid) => {
    if (jid.endsWith('@lid')) {
        const pn = await client.getPNForLID(jid);
        return pn || jid; // Return PN if found, otherwise return LID
    }
    return jid;
};

3. Handle Both Formats Gracefully

// Always handle undefined returns
const lid = await client.getLIDForPN(phoneNumber);
if (lid) {
    console.log('LID found:', lid);
} else {
    console.log('No LID mapping available, using PN');
}

Common Use Cases

Getting User's LID

client.on('message', async msg => {
    if (msg.body === '!myid') {
        const lid = await client.getLIDForPN(msg.from);
        if (lid) {
            await msg.reply(`Your LID: ${lid}\nYour PN: ${msg.from}`);
        } else {
            await msg.reply('No LID found. You may be using a PN-only session.');
        }
    }
});

Resolving LID to Phone Number

client.on('message', async msg => {
    if (msg.body.startsWith('!lookup ')) {
        const lid = msg.body.split(' ')[1];
        const phoneNumber = await client.getPNForLID(lid);
        
        if (phoneNumber) {
            await msg.reply(`Phone number: ${phoneNumber}`);
        } else {
            await msg.reply('No phone number found for that LID.');
        }
    }
});

Handling Group Messages with LIDs

client.on('message', async msg => {
    if (msg.isGroup) {
        const participant = msg.raw.key.participant;
        const participantAlt = msg.raw.key.participantAlt;
        
        // Use alternate (PN) if available, otherwise use primary
        const senderJid = participantAlt || participant;
        
        console.log('Group message from:', senderJid);
        
        // Get LID if sender is using PN
        if (senderJid.endsWith('@s.whatsapp.net')) {
            const lid = await client.getLIDForPN(senderJid);
            console.log('Sender LID:', lid);
        }
    }
});

Helper Functions

// Check if JID is a Phone Number
const isPnUser = (jid) => {
    return jid?.endsWith('@s.whatsapp.net');
};

// Check if JID is a LID
const isLidUser = (jid) => {
    return jid?.endsWith('@lid');
};

// Get preferred JID format
const getPreferredFormat = async (jid, client) => {
    if (isLidUser(jid)) {
        const pn = await client.getPNForLID(jid);
        return pn || jid;
    }
    return jid;
};

Authentication State Requirements

⚠️ Important: Your authentication state must support these keys:

  • lid-mapping - Stores LID/PN mappings
  • device-list - Manages linked devices
  • tctoken - Token for communications

The library handles this automatically with useMultiFileAuthState.

Migration from v6.x to v7.x

If you're upgrading from Baileys v6.x:

  1. Store access changed: Access via sock.signalRepository.lidMapping instead of separate store parameter
  2. New message key fields: Check for remoteJidAlt and participantAlt
  3. Event listener: Add handler for lid-mapping-update event
  4. Function naming: isJidUser() replaced with isPnUser()
  5. Automatic handling: The WhatsAppClient already implements these changes

Troubleshooting

Store is undefined

Problem: Cannot access LID store methods

Solution: Ensure client is connected before accessing store:

await client.connect();
// Wait for 'connected' event
client.on('connected', async () => {
    // Now store methods are available
    const lid = await client.getLIDForPN(phoneNumber);
});

No LID found for PN

Problem: getLIDForPN() returns undefined

Possible causes:

  • User hasn't migrated to LID system yet
  • No LID/PN mapping received from WhatsApp server
  • Using old session that doesn't support LIDs

Solution: Always handle undefined returns gracefully

Additional Resources

For more detailed information about the LID system implementation, see:

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Credits

Developed by Innovators Soft. Based on the @itsukichan/baileys library.