Tutorial: create a WhatsApp bot using Node.js and Puppeteer
Tags: bot, puppeteer, node, javascript
Published: 2022-03-31 15:40:04

![Bot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovd2ey3jswm53txtwf63.png)

   
Hi there! Today you are going to be learning how to create a WhatsApp chat messenger with Node.js and Puppeteer. Awesome stuff, right? Yeah!


## Introduction

So recently, I decided to spam my girlfriend with 200 unsolicited "I love you" WhatsApp messages. I know spamming someone is bad, forgive me! 
Yeah, you can guess her reaction. Initially, it was sweet (that's because I wrote a delay in the code) until it became persistent and almost never ending (but hey! It was just 500 messages or should I say spams 😉)  then she yelled in a chat "stop spamming my phone"

I am not about to teach you to spam people. This tutorial is aimed at teaching you how to use Puppeteer to create a bot - a WhatsApp messenger bot in this case. 

Now let's get right into it.

## *Requirement*

* You should have [Node](https://nodejs.org) installed locally on your computer.
* Have a working knowledge of JavaScript


## What is Puppeteer

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.

Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. You can actually skip the download if you want to. Revert to the Puppeteer docs to see how to do it


## Let's proceed

Let's create an Express app to begin with

```
npx express-generator whatsapp-bot
```

After which you should run `npm install` to install the necessary dependencies.

Also, let's install Puppeteer because this is like the main thing we need in this tutorial.

```
npm install puppeteer
```

Now that puppeteer is installed, let's get our hands dirty writing some codes.

ooooooooh!

Let's create a file called `bot.js` inside the route directory. This is where we are going to be writing all our wonderful codes. yeeeeeah!

Remember to configure the route for `bot.js` inside the `app.js` file. I'm sure you know how to do that. 

No worries if you don't just look at the below codes


```
const bot = require("./routes/bot");

//now add bot to the list of middlewares

app.use("/bot", bot)

```

Okay, I know you are wondering why we wrote this above lines of code. Why didn't we just build our stuff inside `app.js`? why did we even give it a `/bot`? 

Hey calm down! Okay? I'm on your side here. I'm sorry I put you into the stress of doing that. I did that so you can have a well organized file structure incase the tutorial gets interesting and you want to build something big. 

Now that I have been able to make you see that I'm actually your friend, let's continue.

oh yeaaah!

Navigate into `bot.js` and let's begin

```

const express = require("express")
const puppeteer = require("puppeteer")

const bot = express.Router()

bot.get("/", (req, res) =>{


})

module.exports = bot;

```
Just some basic import and export thingy above. Let's continue.


```
const express = require("express")
const puppeteer = require("puppeteer")

const bot = express.Router()

bot.get("/", async (req, res) =>{

 try{
   const browser = await puppeteer.launch({ headless: false });
   const page = await browser.newPage();

 }  

})

module.exports = bot;

```
The above line of code is to help us launch Puppeteer and open a new browser page. We set `headless: false` so that we can actually see what is taking place in the browser. Love that right? Yeah, I know you do. 
NB: remember to do `headless: true` before deploying online

So now let's tell Puppeteer to open WhatsApp

```
const express = require("express")
const puppeteer = require("puppeteer")

const bot = express.Router()

bot.get("/", async (req, res) =>{

 try{
   const browser = await puppeteer.launch({ headless: false });
   const page = await browser.newPage();
    
    await page.goto("https://web.whatsapp.com/");
        await page.setDefaultTimeout(0);
        await page.waitForSelector('[data-testid="search"]')
        .then(()=>  page.click('[data-testid="search"]', {
          delay: 3000
        }))

 }  

})

module.exports = bot;

```

We did a few things above. We instructed Puppeteer to go to the provided URL - WhatsApp's URL. Of course we added `await` because it's an asynchronous call and we don't know how long it will take to get a response.
`setDefaultTimeout(0)` is to ensure that Puppeteer does not snap out of the page because it's taking too much time to load or open.

Oh, before I forget. You have to scan the QR code on the WhatsApp web before you login. Don't worry Puppeteer will wait for you to do that, thanks to `setDefaultTimeout(0)`

### *What did we do next?*


We waited for the search button selector to load. `data-testid="search"` is the selector I chose to use. Well, you could use the classname, id or just any dynamic identifier you find inside the particular html tag. Use the DevTool inspect to get this. Got it?

No?

Yes!

Oh, yes! That' great. I'm sorry I didn't hear you correctly at first. eeeeh!

Let's proceed.
After selector is loaded, `.then()` we instructed Puppeteer to `.click` on the search button (so that we can search out the person we will be sending our message to. 

We added a `delay(3000)` to cause some little delay. We don't want to be too fast so that WhatsApp won't detected we are using a bot. Smart, right?

Let's keep going 
```
//...
  await page.type("._13NKt", "EmmanuelTheCoder");
        delay(2000)
        await page.keyboard.press("Enter")
        delay(2000)
        
        let messageAmount = 5;
        
        for(let i = 0; i<messageAmount; i++){
          delay(2000)

          await page.type(".p3_M1", "Hi, how are you, I hope you 
          are good!");
          delay(2000)
          await page.keyboard.press("Enter");


        }

 
        res.send("done")
      } catch (e) {
        console.error("error mine", e);
      }
//...
```

Did you just scream whooooooooooooooooooooa what the hell are these codes above?

Take a deep breathe. It's alright, it's alright. I'm going to take them away right now(*whispers*: I'll take them away by explaining:));

`await page.type("._13NKt", "EmmanuelTheCoder")` this line of code tells Puppeteer to type in `EmmanuelTheCoder` inside the the search box with the class name `._13NKt`.

NB: replace "EmmanuelTheCoder" with the contact you wish to send a message to.

You already know what `delay` does. 

`await page.keyboard.press("Enter")` after typing in the name, we press the "Enter" key.

we set `messageAmount` to be 5. That's because we want to send our chat 5 times to EmmanuelTheCoder (*I just hope he won't be annoyed with that*)

Now we loop through. Everytime `i < messageAmount` we type in our message inside `.p3_M1` - the class name for the WhatsApp message box. No! I didn't get that by divination. I only used the browser DevTool.

And then we press enter to send

We are catch-ing just incase there is an error.

Oh yeah, I did `res.send("done")` to signify that the message have been sent successfully. Since it's an "I did" and not a "we did", you are free to omit that code. I was only being selfish.

There is one more thing to include. I deliberately skipped that in the code above and I'm sneaking it here. That's why you should always endeavor to read a tutorial to the end.

that is......... `browser.close()`

Yes, you really want to close the browser when you are done. So go back and include that in the code.


You have the complete code below. Feel free to comment if you find anything difficult. 

Kindly share this!

```
//full code
const express = require("express")
const puppeteer = require("puppeteer")

const bot = express.Router()

bot.get("/", async (req, res) =>{

 try{
   const browser = await puppeteer.launch({ headless: false });
   const page = await browser.newPage();
    
    await page.goto("https://web.whatsapp.com/");
        await page.setDefaultTimeout(0);
        await page.waitForSelector('[data-testid="search"]')
        .then(()=>  page.click('[data-testid="search"]', {
          delay: 3000
        }))
       await page.type("._13NKt", "EmmanuelTheCoder");
        delay(2000)
        await page.keyboard.press("Enter")
        delay(2000)
        
        let messageAmount = 5;
        
        for(let i = 0; i<messageAmount; i++){
          delay(2000)

          await page.type(".p3_M1", "Hi, how are you, I hope you 
          are good!");
          delay(2000)
          await page.keyboard.press("Enter");
        }
        res.send("done")
      } catch (e) {
        console.error("error mine", e);
      }

 }  

})

module.exports = bot;
```


## Conclusion
In conclusion, building a WhatsApp bot with Puppeteer and Node.js opens up a world of possibilities for developers seeking to automate interactions and streamline processes on the popular messaging platform. The integration of Puppeteer, a powerful headless browser automation library, with the versatility of Node.js provides a robust framework for creating intelligent and responsive WhatsApp bots.

Throughout this tutorial, we've explored the essential steps, from setting up the project and installing dependencies to crafting interactions with the WhatsApp web interface. Leveraging Puppeteer's capabilities, developers can navigate, manipulate DOM elements, and send messages programmatically, enabling the creation of sophisticated bots tailored to diverse use cases.

As with any automation tool, it's crucial to adhere to ethical guidelines, privacy policies, and terms of service when deploying WhatsApp bots. Respecting user consent and ensuring compliance with platform regulations contribute to a positive and responsible development environment.

The combination of Puppeteer and Node.js empowers developers to build efficient and reliable WhatsApp bots, offering endless possibilities for automation, notification systems, and personalized user experiences. As technology continues to evolve, embracing such innovative approaches becomes instrumental in staying at the forefront of interactive and automated communication.