Skip to main content

How to Connect WhatsApp to ChatGPT (OpenAI) How to Connect WhatsApp to ChatGPT (OpenAI)

How to Connect WhatsApp to ChatGPT (OpenAI)

Combine whatsmeow-node with the OpenAI SDK to build a WhatsApp chatbot powered by GPT-4.1. Messages come in via WhatsApp, get sent to OpenAI for a response, and the reply goes back to the user — with typing indicators while the model thinks.

Prerequisites

  • A paired whatsmeow-node session (How to Pair)
  • An OpenAI API key (set as OPENAI_API_KEY environment variable)
  • The OpenAI SDK: npm install openai

Step 1: Set Up Both Clients

import { createClient } from "@whatsmeow-node/whatsmeow-node";
import OpenAI from "openai";

const client = createClient({ store: "session.db" });
const openai = new OpenAI(); // reads OPENAI_API_KEY from env

const SYSTEM_PROMPT = "You are a helpful WhatsApp assistant. Keep responses concise — under 500 characters when possible, since this is a chat interface.";

Step 2: Handle Incoming Messages

client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;

const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
if (!text) return;

await client.sendChatPresence(info.chat, "composing");

const reply = await askChatGPT(info.sender, text);
await client.sendMessage(info.chat, { conversation: reply });
});

Step 3: Send to ChatGPT

async function askChatGPT(userJid: string, userMessage: string): Promise<string> {
const response = await openai.chat.completions.create({
model: "gpt-4.1",
messages: [
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: userMessage },
],
});

return response.choices[0].message.content ?? "I couldn't generate a response.";
}

Step 4: Add Conversation History

For multi-turn conversations, store message history per user:

import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";

const conversations = new Map<string, ChatCompletionMessageParam[]>();
const MAX_HISTORY = 20;

async function askChatGPT(userJid: string, userMessage: string): Promise<string> {
const history = conversations.get(userJid) ?? [];
history.push({ role: "user", content: userMessage });

if (history.length > MAX_HISTORY) {
history.splice(0, history.length - MAX_HISTORY);
}

const response = await openai.chat.completions.create({
model: "gpt-4.1",
messages: [{ role: "system", content: SYSTEM_PROMPT }, ...history],
});

const reply = response.choices[0].message.content ?? "I couldn't generate a response.";

history.push({ role: "assistant", content: reply });
conversations.set(userJid, history);

return reply;
}

Complete Example

import { createClient } from "@whatsmeow-node/whatsmeow-node";
import OpenAI from "openai";
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";

const client = createClient({ store: "session.db" });
const openai = new OpenAI();

const SYSTEM_PROMPT =
"You are a helpful WhatsApp assistant. Keep responses concise — under 500 characters when possible, since this is a chat interface.";

const conversations = new Map<string, ChatCompletionMessageParam[]>();
const MAX_HISTORY = 20;

async function askChatGPT(userJid: string, userMessage: string): Promise<string> {
const history = conversations.get(userJid) ?? [];
history.push({ role: "user", content: userMessage });

if (history.length > MAX_HISTORY) {
history.splice(0, history.length - MAX_HISTORY);
}

const response = await openai.chat.completions.create({
model: "gpt-4.1",
messages: [{ role: "system", content: SYSTEM_PROMPT }, ...history],
});

const reply = response.choices[0].message.content ?? "I couldn't generate a response.";

history.push({ role: "assistant", content: reply });
conversations.set(userJid, history);

return reply;
}

client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;

const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
if (!text) return;

console.log(`${info.pushName}: ${text}`);
await client.sendChatPresence(info.chat, "composing");

try {
const reply = await askChatGPT(info.sender, text);
await client.sendMessage(info.chat, { conversation: reply });
console.log(`${reply.slice(0, 80)}...`);
} catch (err) {
console.error("OpenAI API error:", err);
await client.sendMessage(info.chat, {
conversation: "Sorry, I'm having trouble right now. Try again in a moment.",
});
}
});

client.on("logged_out", ({ reason }) => {
console.error(`Logged out: ${reason}`);
client.close();
process.exit(1);
});

async function main() {
const { jid } = await client.init();
if (!jid) {
console.error("Not paired! See: How to Pair WhatsApp");
process.exit(1);
}
await client.connect();
await client.sendPresence("available");
console.log("ChatGPT bot is online!");

process.on("SIGINT", async () => {
await client.sendPresence("unavailable");
await client.disconnect();
client.close();
process.exit(0);
});
}

main().catch(console.error);

Common Pitfalls

Echo loops

Always check info.isFromMe first. Without this, the bot sends a message, sees its own message, sends it to ChatGPT, and replies again — forever.

API key exposure

Never hardcode your API key in the source. Use environment variables (OPENAI_API_KEY) or a .env file (added to .gitignore).

Rate limits on both sides

Both the OpenAI API and WhatsApp have rate limits. For the OpenAI API, handle 429 errors with exponential backoff. For WhatsApp, avoid sending too many messages too quickly — see Rate Limiting.