Building a WhatsApp Bot in My Homelab

Building a WhatsApp Bot in My Homelab

Getting Curious

One of the things I enjoy most about my homelab is that it gives me the freedom to tinker with random ideas. Not every project has to be serious or production-grade. Sometimes I just follow my curiosity to see where it leads. This time, that curiosity took me into the world of WhatsApp automation.

The API Rabbit Hole

Naturally, the first step was to look into the official WhatsApp APIs. That didn’t last long. They come with two dealbreakers:

  1. It costs money to send messages. Running a homelab already has its expenses—I wasn’t about to add more.
  2. You need Facebook approval. And honestly, I hate restrictions like that.

So, the official APIs were out. I started digging into workarounds, and that’s when I discovered whatsapp-web.js.

For context:

  • whatsapp-web.js is a Node.js library that automates WhatsApp Web using Puppeteer (a headless browser automation tool).
  • It basically simulates a browser session of WhatsApp Web, letting you send/receive messages programmatically.

This meant I could build my own APIs on top of it without worrying about Facebook’s hoops. The only risk: if I abuse it, I could get my number banned.

whatsapp-web-js.png

Standing on Other People’s Shoulders

Whenever I try something new, part of my research always involves seeing if someone else has already done something similar. You can’t be the only person out of 8 billion with the same idea—you ain’t that special.

That search led me to this repo: tictic-dev/whatsapp. It already has most of the features I needed and came with instructions. The only problem was that it is focused on sending messages only. Receiving messages isn't supported.

So I forked it and started hacking away:

  • Removed parts I didn’t need.
  • Added the missing core feature: receive a message and respond to it—basically, the essence of a bot.

You can find my fork here.

Making It Talk Back

To make the setup more flexible and easier to integrate with other tools, I added webhook registration for each instance. This meant I could point a webhook at an n8n workflow. Every time a message is received, the workflow gets triggered.

For context:

  • n8n is a self-hosted workflow automation tool (kind of like Zapier but without the SaaS lock-in).
  • I already run it in my homelab, so it was the perfect testing ground.

My n8n workflow looked like this:

  1. Receive incoming WhatsApp message.
  2. Send the text to a self-hosted LLM for response generation.
  3. Take the LLM’s output and call the “send message” API.

Screenshot from 2025-09-08 01-11-28.png

At first, it worked beautifully—until it didn’t.

When the AI Started Talking to Itself

During testing, I realized I had overlooked a key scenario: the bot started replying to its own messages.

So picture this:

  • Bot sends a message.
  • LLM receives it as if it’s from me.
  • LLM responds.
  • Bot sends it again.
  • Repeat infinitely.

Basically, I recreated the AI Dinesh vs. AI Gilfoyle moment from Silicon Valley.

It was hilarious, but not very useful.

Fixing the Loop and Adding Memory

To fix this, I added a way to distinguish between my messages and the bot’s own messages. Once I stopped it from talking to itself, I also added memory to the LLM agent. Now it can remember the context of a conversation instead of treating each message in isolation.

Right now, I’m using a separate WhatsApp number for the bot, so don’t worry—if you text me on my personal number, it’s still me responding. (At least for now. I can’t promise the same tomorrow 😅.)

Where Things Stand

This is still very much a work in progress. But I’ve got the first part done:

  • Messages come in.
  • They’re processed by the bot.
  • I get a response back.

It’s rough, but it works.

Reflection

This little experiment reminded me that sometimes you don’t need a big end goal. A spark of curiosity is often enough to kick off something fun and unexpected.