How to Use ChatGPT on WhatsApp (Self-Hosted Guide)
Run ChatGPT or Claude on WhatsApp with Baileys. Complete self-hosted setup guide with code examples and deployment options.
Molted Team
Molted.cloud
ChatGPT on WhatsApp sounds like a dream: ask questions, get instant AI responses, all within the app you already use daily. The official Meta AI integration exists but it is limited. Self-hosting gives you full control over the model, conversation history, and privacy.
This guide shows two paths: build it yourself with Baileys and Node.js, or deploy OpenClaw which handles the WhatsApp integration out of the box.
Why self-host ChatGPT on WhatsApp?
- Privacy - Your conversations stay on your server, not Meta's
- Model choice - Use Claude, GPT-4, Llama, or any model you prefer
- No limits - No rate limits imposed by third-party services
- Custom behavior - Add system prompts, tools, memory
- Cost control - Use your existing API subscription
Option 1: Build with Baileys
Baileys is the most popular WhatsApp Web library for Node.js. It connects to WhatsApp via the web protocol, no official API needed.
Prerequisites
- Node.js 18+
- A WhatsApp account (will be paired via QR code)
- OpenAI or Anthropic API key
Project setup
mkdir whatsapp-ai
cd whatsapp-ai
npm init -y
npm install @whiskeysockets/baileys @anthropic-ai/sdk qrcode-terminalCreate .env:
ANTHROPIC_API_KEY=your-key-hereBasic bot code
require('dotenv').config();
const { default: makeWASocket, useMultiFileAuthState, DisconnectReason } = require('@whiskeysockets/baileys');
const Anthropic = require('@anthropic-ai/sdk');
const qrcode = require('qrcode-terminal');
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
// Store conversation history per chat
const conversations = new Map();
async function connectToWhatsApp() {
const { state, saveCreds } = await useMultiFileAuthState('auth_info');
const sock = makeWASocket({
auth: state,
printQRInTerminal: false,
});
sock.ev.on('connection.update', async (update) => {
const { connection, lastDisconnect, qr } = update;
if (qr) {
qrcode.generate(qr, { small: true });
console.log('Scan the QR code above with WhatsApp');
}
if (connection === 'close') {
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
if (shouldReconnect) {
connectToWhatsApp();
}
} else if (connection === 'open') {
console.log('Connected to WhatsApp');
}
});
sock.ev.on('creds.update', saveCreds);
sock.ev.on('messages.upsert', async ({ messages }) => {
const msg = messages[0];
if (!msg.message || msg.key.fromMe) return;
const chatId = msg.key.remoteJid;
const text = msg.message.conversation ||
msg.message.extendedTextMessage?.text || '';
if (!text) return;
// Get or create conversation history
if (!conversations.has(chatId)) {
conversations.set(chatId, []);
}
const history = conversations.get(chatId);
// Add user message
history.push({ role: 'user', content: text });
// Keep last 20 messages
if (history.length > 20) {
history.splice(0, history.length - 20);
}
try {
// Send typing indicator
await sock.sendPresenceUpdate('composing', chatId);
// Call Claude
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: 'You are a helpful WhatsApp assistant. Keep responses concise for mobile reading.',
messages: history,
});
const reply = response.content[0].text;
// Add to history
history.push({ role: 'assistant', content: reply });
// Send response
await sock.sendMessage(chatId, { text: reply });
} catch (error) {
console.error('Error:', error);
await sock.sendMessage(chatId, { text: 'Sorry, I encountered an error.' });
}
});
}
connectToWhatsApp();Run it
node index.jsScan the QR code with WhatsApp (Settings → Linked Devices → Link a Device). Once connected, any message sent to this WhatsApp number will get an AI response.
Option 2: Use OpenAI instead of Claude
npm install openaiconst OpenAI = require('openai');
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// Replace the Claude call with:
const response = await openai.chat.completions.create({
model: 'gpt-4o',
max_tokens: 1024,
messages: [
{ role: 'system', content: 'You are a helpful WhatsApp assistant.' },
...history,
],
});
const reply = response.choices[0].message.content;Handling media messages
WhatsApp supports images, voice notes, and documents. To handle images with vision models:
sock.ev.on('messages.upsert', async ({ messages }) => {
const msg = messages[0];
if (!msg.message) return;
const chatId = msg.key.remoteJid;
// Handle image messages
if (msg.message.imageMessage) {
const buffer = await downloadMediaMessage(msg, 'buffer', {});
const base64 = buffer.toString('base64');
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{
role: 'user',
content: [
{
type: 'image',
source: {
type: 'base64',
media_type: 'image/jpeg',
data: base64,
},
},
{
type: 'text',
text: msg.message.imageMessage.caption || 'What is in this image?',
},
],
}],
});
await sock.sendMessage(chatId, { text: response.content[0].text });
}
});Persistence and reliability
For production, add proper error handling and session persistence:
// Use PM2 for process management
// pm2 start index.js --name whatsapp-ai
// Add reconnection logic
let reconnectAttempts = 0;
const MAX_RECONNECTS = 5;
sock.ev.on('connection.update', async (update) => {
const { connection, lastDisconnect } = update;
if (connection === 'close') {
const statusCode = lastDisconnect?.error?.output?.statusCode;
if (statusCode === DisconnectReason.loggedOut) {
console.log('Logged out. Delete auth_info folder and restart.');
return;
}
if (reconnectAttempts < MAX_RECONNECTS) {
reconnectAttempts++;
console.log(`Reconnecting... attempt ${reconnectAttempts}`);
setTimeout(connectToWhatsApp, 5000 * reconnectAttempts);
}
} else if (connection === 'open') {
reconnectAttempts = 0;
console.log('Connected');
}
});Security considerations
- Allowlist - Only respond to specific phone numbers
- Rate limiting - Prevent abuse and API cost spikes
- Content filtering - Block harmful requests
const ALLOWED_NUMBERS = [
'1234567890@s.whatsapp.net',
'0987654321@s.whatsapp.net',
];
sock.ev.on('messages.upsert', async ({ messages }) => {
const msg = messages[0];
const chatId = msg.key.remoteJid;
// Only respond to allowed numbers
if (!ALLOWED_NUMBERS.includes(chatId)) {
return;
}
// ... rest of handler
});Skip the code entirely
Molted deploys OpenClaw with WhatsApp ready. QR pairing from a web UI, no coding.
Option 3: Deploy OpenClaw
If you want WhatsApp AI without maintaining code, OpenClaw (formerly MoltBot) includes WhatsApp integration. The setup is:
- Deploy OpenClaw instance on Molted (or self-host)
- Go to Channels → WhatsApp
- Scan QR code from the web UI
- Done. Messages flow through instantly.
OpenClaw handles reconnection, session persistence, and multi-device sync automatically. You can switch between Claude, GPT-4, or other models from the config without touching code.
Cost comparison
| Approach | Monthly cost | Effort |
|---|---|---|
| DIY Baileys + API | $5-50 (API usage) | High (code + maintain) |
| OpenClaw on VPS | $5-10 (hosting) + API | Medium (deploy + configure) |
| OpenClaw on Molted | $5-10/month | Low (click + scan) |
The DIY approach is great for learning and full customization. OpenClaw makes sense when you want it working reliably without ongoing maintenance.
Related guides
- Discord Bot with AI - Similar setup for Discord
- Telegram AI Bot Guide - Build for Telegram with grammY
- Self-Hosted AI Assistant Guide - Overview of all channel options
WhatsApp AI in 60 seconds
OpenClaw on Molted includes WhatsApp integration. Scan QR, start chatting.
24-hour free trial · No credit card required · Cancel anytime