Venom is a high-performance system developed with JavaScript to create a bot for WhatsApp, support for creating any interaction, such as customer service, media sending, sentence recognition based on artificial intelligence and all types of design architecture for WhatsApp.
Automatic QR Refresh | ✔ |
Send text, image, video, audio and docs | ✔ |
Get contacts, chats, groups, group members, Block List | ✔ |
Send contacts | ✔ |
Send stickers | ✔ |
Send stickers GIF | ✔ |
Multiple Sessions | ✔ |
Forward Messages | ✔ |
Receive message | ✔ |
insert user section | ✔ |
📍 Send location!! | ✔ |
🕸🕸 and much more | ✔ |
> npm i --save venom-bot
// Supports ES6
// import { create, Whatsapp } from 'venom-bot';
const venom = require('venom-bot');
venom
.create()
.then((client) => start(client))
.catch((erro) => {
console.log(erro);
});
function start(client) {
client.onMessage((message) => {
if (message.body === 'Hi' && message.isGroupMsg === false) {
client
.sendText(message.from, 'Welcome Venom 🕷')
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
}
});
}
After executing create()
function, venom will create an instance of whatsapp web. If you are not logged in, it will print a QR code in the terminal. Scan it with your phone and you are ready to go!
// Init sales whatsapp bot
venom.create('sales').then((salesClient) => {...});
// Init support whatsapp bot
venom.create('support').then((supportClient) => {...});
Venom create()
method third parameter can have the following optional parameters:
const venom = require('venom-bot');
venom
.create(
//session
'sessionName', //Pass the name of the client you want to start the bot
//catchQR
(base64Qrimg, asciiQR, attempts) => {
console.log('Numero de tentativas para ler o qrcode: ', attempts);
console.log('Terminal qrcode: ', asciiQR);
console.log('base64 image string qrcode: ', base64Qrimg);
},
// statusFind
(statusSession) => {
console.log('Status Session: ', statusSession); //return isLogged || notLogged || browserClose || qrReadSuccess || qrReadFail || autocloseCalled || desconnectedMobile
//Create session wss return "serverClose" case server for close
},
// options
{
folderNameToken: 'tokens', //folder name when saving tokens
mkdirFolderToken: '', //folder directory tokens, just inside the venom folder, example: { mkdirFolderToken: '/node_modules', } //will save the tokens folder in the node_modules directory
headless: true, // Headless chrome
devtools: false, // Open devtools by default
useChrome: true, // If false will use Chromium instance
debug: false, // Opens a debug session
logQR: true, // Logs QR automatically in terminal
browserWS: '', // If u want to use browserWSEndpoint
browserArgs: [''], // Parameters to be added into the chrome browser instance
disableSpins: true, // Will disable Spinnies animation, useful for containers (docker) for a better log
disableWelcome: true, // Will disable the welcoming message which appears in the beginning
updatesLog: true, // Logs info updates automatically in terminal
autoClose: 60000, // Automatically closes the venom-bot only when scanning the QR code (default 60 seconds, if you want to turn it off, assign 0 or false)
createPathFileToken: false, //creates a folder when inserting an object in the client's browser, to work it is necessary to pass the parameters in the function create browserSessionToken
},
// BrowserSessionToken
// To receive the client's token use the function await clinet.getSessionTokenBrowser()
{
WABrowserId: '"UnXjH....."',
WASecretBundle:
'{"key":"+i/nRgWJ....","encKey":"kGdMR5t....","macKey":"+i/nRgW...."}',
WAToken1: '"0i8...."',
WAToken2: '"1@lPpzwC...."',
}
)
.then((client) => {
start(client);
})
.catch((erro) => {
console.log(erro);
});
Gets the return if the session is isLogged
or notLogged
or browserClose
or qrReadSuccess
or qrReadFail
or autocloseCalled
or desconnectedMobile
or Create session wss return "serverClose" case server for close
notLogged: When the user is not connected to the browser, it is necessary to scan the QR code through the cell phone in the option WharsApp Web
.
qrReadSuccess: if the user is not logged in, the QR code is passed on the terminal a callback is returned. After the correct reading by cell phone this parameter is returned
.
const venom = require('venom-bot');
venom
.create(
'sessionName',
undefined,
(statusSession) => {
console.log('Status Session: ', statusSession);
//return isLogged || notLogged || browserClose || qrReadSuccess || qrReadFail || autocloseCalled || desconnectedMobile
//Create session wss return "serverClose" case server for close
},
undefined
)
.then((client) => {
start(client);
})
.catch((erro) => {
console.log(erro);
});
By default QR code will appear on the terminal. If you need to pass the QR somewhere else heres how:
const fs = require('fs');
const venom = require('venom-bot');
venom
.create(
'sessionName',
(base64Qr, asciiQR) => {
console.log(asciiQR); // Optional to log the QR in the terminal
var matches = base64Qr.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/),
response = {};
if (matches.length !== 3) {
return new Error('Invalid input string');
}
response.type = matches[1];
response.data = new Buffer.from(matches[2], 'base64');
var imageBuffer = response;
require('fs').writeFile(
'out.png',
imageBuffer['data'],
'binary',
function (err) {
if (err != null) {
console.log(err);
}
}
);
},
undefined,
{ logQR: false }
)
.then((client) => {
start(client);
})
.catch((erro) => {
console.log(erro);
});
Puppeteer takes care of the file downloading. The decryption is being done as fast as possible (outruns native methods). Supports big files!
import fs = require('fs');
import mime = require('mime-types');
client.onMessage( async (message) => {
if (message.isMedia === true || message.isMMS === true) {
const buffer = await client.decryptFile(message);
// At this point you can do whatever you want with the buffer
// Most likely you want to write it into a file
const fileName = `some-file-name.${mime.extension(message.mimetype)}`;
await fs.writeFile(fileName, buffer, (err) => {
...
});
}
});
Not every available function is listed, for further look, every function available can be found in here and here
// Send contact
await client
.sendContactVcard('000000000000@c.us', '111111111111@c.us', 'Name of contact')
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Send a list of contact cards
await client
.sendContactVcardList('000000000000@c.us', [
'111111111111@c.us',
'222222222222@c.us',
])
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Send basic text
await client
.sendText('000000000000@c.us', '👋 Hello from venom!')
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Send location
await client
.sendLocation('000000000000@c.us', '-13.6561589', '-69.7309264', 'Brasil')
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Automatically sends a link with the auto generated link preview. You can also add a custom message to be added.
await client
.sendLinkPreview(
'000000000000@c.us',
'https://www.youtube.com/watch?v=V1bFr2SWP1I',
'Kamakawiwo ole'
)
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Send image (you can also upload an image using a valid HTTP protocol)
await client
.sendImage(
'000000000000@c.us',
'path/to/img.jpg',
'image-name',
'Caption text'
)
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Send file (venom will take care of mime types, just need the path)
// you can also upload an image using a valid HTTP protocol
await client
.sendFile(
'000000000000@c.us',
'path/to/file.pdf',
'file_name',
'See my file in pdf'
)
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Sends file
// base64 parameter should have mime type already defined
await client
.sendFileFromBase64(
'000000000000@c.us',
base64PDF,
'file_name.pdf',
'See my file in pdf'
)
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Generates sticker from the provided animated gif image and sends it (Send image as animated sticker)
// image path imageBase64 A valid gif image is required. You can also send via http/https (http://www.website.com/img.gif)
await client
.sendImageAsStickerGif('000000000000@c.us', './image.gif')
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Generates sticker from given image and sends it (Send Image As Sticker)
// image path imageBase64 A valid png, jpg and webp image is required. You can also send via http/https (http://www.website.com/img.jpg)
await client
.sendImageAsSticker('000000000000@c.us', './image.jpg')
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Send @tagged message
await client.sendMentioned(
'000000000000@c.us',
'Hello @5218113130740 and @5218243160777!',
['5218113130740', '5218243160777']
);
// Reply to a message
await client.reply(
'000000000000@c.us',
'This is a reply!',
message.id.toString()
);
// Reply to a message with mention
await client.reply(
'000000000000@c.us',
'Hello @5218113130740 and @5218243160777! This is a reply with mention!',
message.id.toString(),
['5218113130740', '5218243160777']
);
// Send gif
await client.sendVideoAsGif(
'000000000000@c.us',
'path/to/video.mp4',
'video.gif',
'Gif image file'
);
// Forwards messages
await client.forwardMessages(
'000000000000@c.us',
[message.id.toString()],
true
);
// Send seen ✔️✔️
await client.sendSeen('000000000000@c.us');
// Start typing...
await client.startTyping('000000000000@c.us');
// Stop typing
await client.stopTyping('000000000000@c.us');
// Set chat state (0: Typing, 1: Recording, 2: Paused)
await client.setChatState('000000000000@c.us', 0 | 1 | 2);
// Retrieve the browser session token
const browserSessionToken = await client.getSessionTokenBrowser();
// Calls your list of blocked contacts (returns an array)
const getBlockList = await client.getBlockList();
// Retrieve contacts
const contacts = await client.getAllContacts();
// Retrieve messages in chat
const Messages = await client.getAllMessagesInChat('000000000000@c.us');
// Retrieve more chat message
const moreMessages = await client.loadEarlierMessages('000000000000@c.us');
// Retrieve all messages in chat
const allMessages = await client.loadAndGetAllMessagesInChat(
'000000000000@c.us'
);
// Retrieve contact status
const status = await client.getStatus('000000000000@c.us');
// Retrieve user profile
const user = await client.getNumberProfile('000000000000@c.us');
// Retrieve all unread message
const messages = await client.getAllUnreadMessages();
// Retrieve all chats
const chats = await client.getAllChats();
// Retrieve all groups
const chats = await client.getAllGroups();
// Retrieve profile fic (as url)
const url = await client.getProfilePicFromServer('000000000000@c.us');
// Retrieve chat/conversation
const chat = await client.getChat('000000000000@c.us');
// Check if the number exists
const chat = await client.checkNumberStatus('000000000000@c.us');
// groupId or chatId: leaveGroup 52123123-323235@g.us
// Leave group
await client.leaveGroup('00000000-000000@g.us');
// Get group members
await client.getGroupMembers('00000000-000000@g.us');
// Get group members ids
await client.getGroupMembersIds('00000000-000000@g.us');
// Generate group invite url link
await client.getGroupInviteLink('00000000-000000@g.us');
// Create group (title, participants to add)
await client.createGroup('Group name', [
'111111111111@c.us',
'222222222222@c.us',
]);
// Remove participant
await client.removeParticipant('00000000-000000@g.us', '111111111111@c.us');
// Add participant
await client.addParticipant('00000000-000000@g.us', '111111111111@c.us');
// Promote participant (Give admin privileges)
await client.promoteParticipant('00000000-000000@g.us', '111111111111@c.us');
// Demote particiapnt (Revoke admin privileges)
await client.demoteParticipant('00000000-000000@g.us', '111111111111@c.us');
// Get group admins
await client.getGroupAdmins('00000000-000000@g.us');
// Return the group status, jid, description from it's invite link
await client.getGroupInfoFromInviteLink(InviteCode);
// Join a group using the group invite code
await client.joinGroup(InviteCode);
// Set client status
await client.setProfileStatus('On vacations! ✈️');
// Set client profile name
await client.setProfileName('Venom bot');
// Set client profile photo
await client.setProfilePic('path/to/image.jpg');
// Delete the Service Worker
await client.killServiceWorker();
// Load the service again
await client.restartService();
// Get device info
await client.getHostDevice();
// Get connection state
await client.getConnectionState();
// Get battery level
await client.getBatteryLevel();
// Is connected
await client.isConnected();
// Get whatsapp web version
await client.getWAVersion();
// Listen to messages
client.onMessage(message => {
...
})
// Listen to state changes
client.onStateChange(state => {
...
});
// Listen to ack's
// See the status of the message when sent.
// When receiving the confirmation object, "ack" may return: "INACTIVE", "CONTENT_UNUPLOADABLE", "CONTENT_TOO_BIG", "CONTENT_GONE", "EXPIRED", "FAILED", "CLOCK", "SENT", "RECEIVED", "RECEIVED", "READ" or "PLAYED".
client.onAck(ack => {
...
});
// Listen to live location
// chatId: 'phone@c.us'
client.onLiveLocation("000000000000@c.us", (liveLocation) => {
...
});
// chatId looks like this: '5518156745634-1516512045@g.us'
// Event interface is in here: https://github.com/s2click/venom/blob/master/src/api/model/participant-event.ts
client.onParticipantsChanged("000000000000@c.us", (event) => {
...
});
// Listen when client has been added to a group
client.onAddedToGroup(chatEvent => {
...
});
// Pin chat and Unpin chat messages with true or false
// Pin chat, non-existent (optional)
await client
.pinChat(chatId, true, false)
.then((result) => {
console.log('Result: ', result); //return object success
})
.catch((erro) => {
console.error('Error when sending: ', erro); //return object error
});
// Change the theme
// string types "dark" or "light"
await client.setTheme('dark');
// Receive the current theme
// returns string light or dark
await client.getTheme();
// Delete chat
await client.deleteChat('000000000000@c.us');
// Clear chat messages
await client.clearChat('000000000000@c.us');
// Archive and unarchive chat messages with true or false
await client.archiveChat(chatId, true);
// Delete message (last parameter: delete only locally)
await client.deleteMessage('000000000000@c.us', message.id.toString(), false);
// Mark chat as not seen (returns true if it works)
await client.markUnseenMessage('000000000000@c.us');
// Blocks a user (returns true if it works)
await client.blockContact('000000000000@c.us');
// Unlocks contacts (returns true if it works)
await client.unblockContact('000000000000@c.us');
// Retrieve a number profile / check if contact is a valid whatsapp number
const profile = await client.getNumberProfile('000000000000@c.us');
There are some tricks for a better usage of venom.
// In case of being logged out of whatsapp web
// Force it to keep the current session
// State change
// Detect a logout
// Possible state values:
// CONFLICT
// CONNECTED
// DEPRECATED_VERSION
// OPENING
// PAIRING
// PROXYBLOCK
// SMB_TOS_BLOCK
// TIMEOUT
// TOS_BLOCK
// UNLAUNCHED
// UNPAIRED
// UNPAIRED_IDLE
client.onStateChange((state) => {
console.log('State changed: ', state);
const conflits = [
venom.SocketState.CONFLICT,
venom.SocketState.UNPAIRED,
venom.SocketState.UNLAUNCHED,
];
if (conflits.includes(state)) {
client.useHere();
// Detect a logout
if (state === 'UNPAIRED') console.log('Client logout!');
}
});
If you need to run multiple sessions at once just pass a session name to
create()
method, not use hyphen for name of sessions.
async () => {
const marketingClient = await venom.create('marketing');
const salesClient = await venom.create('sales');
const supportClient = await venom.create('support');
};
Close the session properly to ensure the session is saved for the next time you log in (So it won't ask for QR scan again). So instead of CTRL+C,
// Catch ctrl+C
process.on('SIGINT', function() {
client.close();
});
// Try-catch close
try {
...
} catch (error) {
client.close();
}
The auto close is enabled by default and the timeout is set to 60 sec. Receives the time in milliseconds to countdown until paired.
Use "autoClose: 0 | false" to disable auto closing.
Building venom is really simple altough it contains 3 main projects inside
- Wapi project
> npm run build:wapi
- Middleware
> npm run build:middleware
> npm run build:jsQR
- Venom
> npm run build:venom
To build the entire project just run
> npm run build
Maintainers are needed, I cannot keep with all the updates by myself. If you are interested please open a Pull Request.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.