Skip to main content
Run OpenClaw in a Hyperbrowser sandbox and connect it to WhatsApp. Your agent receives and responds to WhatsApp messages through the built-in WhatsApp Web / Baileys channel.

How It Works

  1. Create a sandbox from the openclaw base image.
  2. Configure OpenClaw with your model provider and the WhatsApp channel.
  3. Link a WhatsApp account by scanning a QR code.
  4. Start the OpenClaw gateway and message your agent.

Prerequisites

Quick Start

Create a sandbox, configure the WhatsApp channel with an allowlisted phone number, and start the gateway:
import { Hyperbrowser } from "@hyperbrowser/sdk";
import { config } from "dotenv";
import { StringDecoder } from "node:string_decoder";

config();

const client = new Hyperbrowser({
  apiKey: process.env.HYPERBROWSER_API_KEY,
});

// 1. Create a sandbox from the openclaw image
const sandbox = await client.sandboxes.create({
  imageName: "openclaw",
  timeoutMinutes: 60,
});

console.log("Sandbox ID:", sandbox.id);
console.log("Session URL:", sandbox.sessionUrl);

// 2. Set the default model
await sandbox.exec(
  'openclaw config set agents.defaults.model.primary "openai/gpt-5.2"'
);

// 3. Install the WhatsApp plugin
await sandbox.exec("openclaw plugins install @openclaw/whatsapp");

const gatewayToken = process.env.OPENCLAW_APP_TOKEN ?? crypto.randomUUID();
const gatewayPort = Number(process.env.GATEWAY_PORT ?? 18789);

await sandbox.exec("openclaw config set gateway.mode local");

// 4. Configure the WhatsApp channel (dedicated-number allowlist)
const ownerNumber = "+15551234567"; // replace with the phone number allowed to DM the bot

await sandbox.exec(
  [
    "openclaw config set channels.whatsapp.dmPolicy allowlist",
    `openclaw config set channels.whatsapp.allowFrom '["${ownerNumber}"]' --strict-json`,
    "openclaw config set channels.whatsapp.groupPolicy disabled",
  ].join(" && ")
);

// 5. Link WhatsApp in a PTY terminal so the QR renders correctly
console.log("\nScan the QR code below with your WhatsApp app:\n");

const login = await sandbox.terminal.create({
  command: "bash",
  args: ["-lc", "openclaw channels login --channel whatsapp"],
  rows: 40,
  cols: 120,
});

const loginConnection = await login.attach();
const loginDecoder = new StringDecoder("utf8");

for await (const event of loginConnection.events()) {
  if (event.type === "output") {
    process.stdout.write(loginDecoder.write(event.raw));
    continue;
  }

  break;
}

process.stdout.write(loginDecoder.end());
await loginConnection.close();

console.log("\nWhatsApp linked successfully.");

// 6. Start the gateway
const gateway = await sandbox.processes.start(
  `openclaw gateway --bind lan --port ${gatewayPort} --auth token --token "${gatewayToken}"`,
  { env: { OPENAI_API_KEY: process.env.OPENAI_API_KEY! } }
);

// 7. Wait for the gateway to become ready
for (let i = 0; i < 15; i++) {
  const check = await sandbox.exec("openclaw gateway status --require-rpc");
  if (check.exitCode === 0) break;
  await new Promise((r) => setTimeout(r, 2000));
}

console.log("Gateway started. You can now message your agent on WhatsApp.");

Verify the Setup

After linking, verify everything is running from the sandbox terminal or via the SDK:
const status = await sandbox.exec("openclaw gateway status --require-rpc");
console.log(status.stdout);

const channels = await sandbox.exec("openclaw channels list");
console.log(channels.stdout);

const probe = await sandbox.exec("openclaw channels status --probe");
console.log(probe.stdout);

const deep = await sandbox.exec("openclaw status --deep");
console.log(deep.stdout);
Send a WhatsApp message from the allowed phone number to the linked WhatsApp number. With dmPolicy=allowlist, no pairing approval step is needed.

Personal Number Setup

If you want to use your own WhatsApp number instead of a dedicated one, enable selfChatMode. Replace step 4 in the quick start with:
const myNumber = "+15551234567"; // your personal WhatsApp number

await sandbox.exec(
  [
    "openclaw config set channels.whatsapp.dmPolicy allowlist",
    `openclaw config set channels.whatsapp.allowFrom '["${myNumber}"]' --strict-json`,
    "openclaw config set channels.whatsapp.selfChatMode true --strict-json",
  ].join(" && ")
);
With selfChatMode enabled, send a message in your own WhatsApp chat (“Message yourself”) and OpenClaw responds there.

Adding Group Chats

To let your agent respond in group chats when mentioned, add this configuration after the initial setup:
const ownerNumber = "+15551234567";

await sandbox.exec(
  [
    "openclaw config set channels.whatsapp.groupPolicy allowlist",
    `openclaw config set channels.whatsapp.groupAllowFrom '["${ownerNumber}"]' --strict-json`,
    `openclaw config set channels.whatsapp.groups '{"*":{"requireMention":true}}' --strict-json`,
    "openclaw config validate",
  ].join(" && ")
);
This means:
  • Only allowlisted senders can control the agent in groups.
  • The agent only responds when mentioned.

Pairing Mode

If you want new DM senders to require explicit approval instead of an allowlist, switch to pairing mode:
await sandbox.exec(
  [
    "openclaw config set channels.whatsapp.dmPolicy pairing",
    "openclaw config unset channels.whatsapp.allowFrom",
    "openclaw config validate",
  ].join(" && ")
);

// After an unknown sender messages the bot:
const pairings = await sandbox.exec("openclaw pairing list whatsapp");
console.log(pairings.stdout);

// Approve a specific pairing code
await sandbox.exec("openclaw pairing approve whatsapp CODE_HERE");
If you keep allowFrom populated alongside dmPolicy=pairing, allowlisted numbers bypass the pairing step.

Troubleshooting

  • WhatsApp link lost after restart — The WhatsApp session lives in ~/.openclaw. Use a volume to persist it across sandbox restarts.
  • Messages not delivered — Verify the channel is connected with openclaw channels status --probe. Check that allowFrom includes the correct E.164 phone number (for example +15551234567).
  • QR code expired — Run openclaw channels login --channel whatsapp again to generate a new QR code.
  • Gateway bind errors — If you only need access from inside the sandbox (not from the host), set gateway.bind to loopback instead of lan.

Next Steps

Sandbox Processes

Run and manage processes inside your sandbox.

Sandbox Snapshots

Save sandbox state and restore it later.

Volumes

Persist WhatsApp sessions and data across restarts.

Base Images

See all available base images.