Baileys 2.0 - Typescript/Javascript WhatsApp Web API
Baileys does not require Selenium or any other browser to be interface with WhatsApp Web, it does so directly using a WebSocket. Not running Selenium or Chromimum saves you like half a gig of ram :/
Thank you to @Sigalor for writing the guide to reverse engineering WhatsApp Web and thanks to @Rhymen for the go implementation.
Baileys is type-safe, extensible and simple to use. If you require more functionality than provided, it'll super easy for you to write an extension. More on this here.
If you're interested in building a WhatsApp bot, you may wanna check out WhatsAppInfoBot and an actual bot built with it, Messcat.
Example
Do check out & run example.ts to see example usage of the library. The script covers most common use cases. To run the example script, download or clone the repo and then type the following in terminal:
cd path/to/Baileys
npm install
npm run example
Unit Tests
Baileys also comes with a unit test suite. Simply cd into the Baileys directory & run npm test
.
You will require a phone with WhatsApp to test, and a second WhatsApp number to send messages to.
Set the phone number you can randomly send messages to in a .env
file with TEST_JID=1234@s.whatsapp.net
Install
Create and cd to your NPM project directory and then in terminal, write:
- stable:
npm install @adiwajshing/baileys
- stabl-ish (but quicker fixes):
npm install github:adiwajshing/baileys
Then import in your code using:
Connecting
client.connect.then.catch console.log"unexpected error: " + err
If the connection is successful, you will see a QR code printed on your terminal screen, scan it with WhatsApp on your phone and you'll be logged in!
If you don't want to wait for WhatsApp to send all your chats while connecting, you can use the following function:
client.connectSlim // does not wait for chats & contacts.then.catch console.log"unexpected error: " + err
Saving & Restoring Sessions
You obviously don't want to keep scanning the QR code every time you want to connect.
So, do the following the first time you connect:
client.connectSlim // connect first.then
Then, to restore a session:
client.connectSlim'./auth_info.json' // will load JSON credentials from file.then
Optionally, you can load the credentials yourself from somewhere & pass in the JSON object as well.
Handling Events
Implement the following callbacks in your code:
- Called when you have a pending unread message or recieve a new message// set first param to `true` if you want to receive outgoing messages that may be sent from your phoneclient.setOnUnreadMessage false,
- Called when you recieve an update on someone's presence, they went offline or onlineclient.setOnPresenceUpdate console.logjson.id + " presence is " + json.type
- Called when your message gets delivered or readclient.setOnMessageStatusChange
- Called when the connection gets disconnected (either the server loses internet or the phone gets unpaired)client.setOnUnexpectedDisconnect console.log "disconnected unexpectedly: " + err
Sending Messages
Send like, all types of messages with a single function:
// send a simple text!client.sendMessage id, 'oh hello there', MessageType.text// send a location!client.sendMessageid, , MessageType.location// send a contact!+ 'VERSION:3.0\n'+ 'FN:Jeff Singh\n' // full name+ 'ORG:Ashoka Uni;\n' // the organization of the contact+ 'TEL;type=CELL;type=VOICE;waid=911234567890:+91 12345 67890\n' // WhatsApp ID + phone number+ 'END:VCARD'client.sendMessageid, , MessageType.contact// send a gifclient.sendMessageid, buffer, MessageType.video, options
To note:
id
is the WhatsApp ID of the person or group you're sending the message to.- It must be in the format
[country code][phone number]@s.whatsapp.net
, for example+19999999999@s.whatsapp.net
for people. For groups, it must be in the format123456789-123345@g.us
. - Do not attach
@c.us
for individual people IDs, It won't work.
- It must be in the format
- For media messages, the thumbnail can be generated automatically for images & stickers. Thumbnails for videos can also be generated automatically, though, you need to have
ffmpeg
installed on your system. - MessageOptions: some extra info about the message. It can have the following optional values:
Sending Read Receipts
client.sendReadReceiptid, messageID
The id is in the same format as mentioned earlier. The message ID is the unique identifier of the message that you are marking as read. On a WAMessage
, it can be accessed using messageID = message.key.id
.
Update Presence
client.updatePresenceid, WhatsAppWeb.Presence.available
This lets the person/group with id
know whether you're online, offline, typing etc. where presence
can be one of the following:
// call: import { Presence } from '@adiwajshing/baileys'
Decoding Media
If you want to save & process some images, videos, documents or stickers you received
client.setOnUnreadMessage false,
Querying
- To check if a given ID is on WhatsAppconsole.log ` on WhatsApp`
- To query chat history on a group or with someone
You can also load the entire conversation history if you want// query the last 25 messages (replace 25 with the number of messages you want to query)console.log"got back " + messages.length + " messages"await client.loadEntireConversation "xyz@c.us", console.log"Loaded message with ID: " + message.key.idconsole.log"queried all messages" // promise resolves once all messages are retreived - To get the status of some personconsole.log"status: " + status
- To get the display picture of some person/groupconsole.log"download profile picture from: " + ppUrl
- To get someone's presence (if they're typing, online)// the presence update is fetched and called hereclient.setOnPresenceUpdate console.logjson.id + " presence is " + json.typeawait client.requestPresenceUpdate "xyz@c.us"
Of course, replace xyz
with an actual ID.
Also, append @s.whatsapp.net
for individuals & @g.us
for groups.
Groups
- To query the metadata of a groupconsole.logjson.id + ", title: " + json.subject + ", description: " + json.desc
- To create a group// title & participantsconsole.log "created group with id: " + group.gidclient.sendTextMessagegroup.gid, "hello everyone" // say hello to everyone on the group
- To add people to a group// id & people to add to the groupconsole.log"added successfully: " + response.status===200
- To make someone admin on a groupconsole.log"made admin successfully: " + response.status===200
- To leave a groupconsole.log"left group successfully: " + response.status===200
- To get the invite code for a groupconsole.log"group code: " + code
Writing Custom Functionality
Baileys is written, keeping in mind, that you may require other custom functionality. Hence, instead of having to fork the project & re-write the internals, you can simply write extensions in your own code.
First, enable the logging of unhandled messages from WhatsApp by setting
client.logLevel = MessageLogLevel.unhandled // set to MessageLogLevel.all to see all messages received
This will enable you to see all sorts of messages WhatsApp sends in the console. Some examples:
-
Functionality to track of the battery percentage of your phone. You enable logging and you'll see a message about your battery pop up in the console:
[Baileys] [Unhandled] s22, ["action",null,[["battery",{"live":"false","value":"52"},null]]]
You now know what a battery update looks like. It'll have the following characteristics.
- Given
const bMessage = ["action",null,[["battery",{"live":"false","value":"52"},null]]]
bMessage[0]
is always"action"
bMessage[1]
is alwaysnull
bMessage[2][0][0]
is always"battery"
Hence, you can register a callback for an event using the following:
client.registerCallback ,This callback will be fired any time a message is received matching the following criteria:
message [0] === "action" && message [1] === null && message[2][0][0] === "battery"
- Given
-
Functionality to keep track of the pushname changes on your phone. You enable logging and you'll see an unhandled message about your pushanme pop up like this:
[Baileys] [Unhandled] s24, ["Conn",{"pushname":"adiwajshing"}]
You now know what a pushname update looks like. It'll have the following characteristics.
- Given
const pMessage = ["Conn",{"pushname":"adiwajshing"}]
pMessage[0]
is always"Conn"
pMessage[1]
always has the key"pushname"
pMessage[2]
is alwaysundefined
Following this, one can implement the following callback:
client.registerCallback ,This callback will be fired any time a message is received matching the following criteria:
message [0] === "Conn" && message [1].pushname
- Given
A little more testing will reveal that almost all WhatsApp messages are in the format illustrated above.
Note: except for the first parameter (in the above cases, "action"
or "Conn"
), all the other parameters are optional.
Note
This library is in no way affiliated with WhatsApp. Use at your own discretion. Do not spam people with this.