메인 콘텐츠로 건너뛰기

WhatsApp (Web channel)

상태: WhatsApp Web (Baileys) 기반으로 production-ready입니다. Gateway가 연결된 session을 소유합니다.

빠른 설정

1

WhatsApp 접근 정책 설정

{
  channels: {
    whatsapp: {
      dmPolicy: "pairing",
      allowFrom: ["+15551234567"],
      groupPolicy: "allowlist",
      groupAllowFrom: ["+15551234567"],
    },
  },
}
2

WhatsApp 연결 (QR)

openclaw channels login --channel whatsapp
특정 account에 연결할 때:
openclaw channels login --channel whatsapp --account work
3

gateway 시작

openclaw gateway
4

첫 pairing 요청 승인 (pairing mode 사용 시)

openclaw pairing list whatsapp
openclaw pairing approve whatsapp <CODE>
Pairing 요청은 1시간 후 만료됩니다. pending request는 채널당 최대 3개입니다.
가능하면 OpenClaw용 WhatsApp은 별도 번호로 운영하는 것이 좋습니다. 채널 metadata와 onboarding 흐름은 그 구성을 기준으로 최적화되어 있지만, 개인 번호 구성도 지원합니다.

배포 패턴

가장 깔끔한 운영 방식입니다.
  • OpenClaw 전용 WhatsApp identity 사용
  • 더 명확한 DM allowlist와 routing 경계
  • self-chat 혼동 가능성 감소
최소 정책 예시:
{
  channels: {
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+15551234567"],
    },
  },
}
Onboarding은 개인 번호 모드를 지원하며 self-chat에 안전한 기본 구성을 기록합니다.
  • dmPolicy: "allowlist"
  • allowFrom에 개인 번호 포함
  • selfChatMode: true
런타임에서는 연결된 self number와 allowFrom을 기준으로 self-chat 보호가 동작합니다.
현재 OpenClaw 채널 아키텍처에서 이 메시징 플랫폼 채널은 WhatsApp Web 기반(Baileys)입니다.내장 chat-channel registry에는 별도의 Twilio WhatsApp messaging channel이 없습니다.

런타임 모델

  • Gateway가 WhatsApp socket과 reconnect loop를 소유합니다.
  • outbound send는 대상 account에 active WhatsApp listener가 있어야 합니다.
  • status chat과 broadcast chat은 무시됩니다. (@status, @broadcast)
  • direct chat은 DM session 규칙을 사용합니다. (session.dmScope; 기본 main은 DM을 agent main session으로 합침)
  • group session은 분리됩니다. (agent:<agentId>:whatsapp:group:<jid>)

접근 제어와 활성화

channels.whatsapp.dmPolicy는 direct chat 접근을 제어합니다.
  • pairing (기본값)
  • allowlist
  • open (allowFrom"*"가 있어야 함)
  • disabled
allowFrom은 E.164 형식 번호를 받으며, 내부적으로 정규화됩니다.멀티 계정 override: channels.whatsapp.accounts.<id>.dmPolicyallowFrom이 해당 account의 채널 기본값보다 우선합니다.런타임 동작:
  • pairing은 채널 allow-store에 저장되며 설정된 allowFrom과 병합됩니다.
  • allowlist가 비어 있으면 연결된 self number가 기본적으로 허용됩니다.
  • outbound fromMe DM은 자동 pairing되지 않습니다.

개인 번호와 self-chat 동작

연결된 self number가 allowFrom에도 포함되어 있으면 WhatsApp self-chat 보호가 활성화됩니다.
  • self-chat turn에서는 read receipt를 생략
  • 자기 자신을 다시 ping하게 되는 mention-JID auto-trigger 동작을 무시
  • messages.responsePrefix가 unset이면 self-chat reply의 기본 prefix는 [{identity.name}] 또는 [openclaw]

메시지 정규화와 컨텍스트

들어오는 WhatsApp 메시지는 공용 inbound envelope으로 래핑됩니다.quoted reply가 있으면 다음 형식으로 컨텍스트가 추가됩니다.
[Replying to <sender> id:<stanzaId>]
<quoted body or media placeholder>
[/Replying]
가능할 때는 reply metadata 필드도 채워집니다. (ReplyToId, ReplyToBody, ReplyToSender, sender JID/E.164)
media-only inbound message는 다음과 같은 placeholder로 정규화됩니다.
  • <media:image>
  • <media:video>
  • <media:audio>
  • <media:document>
  • <media:sticker>
Location 및 contact payload는 라우팅 전에 텍스트 컨텍스트로 정규화됩니다.
그룹에서는, 처리되지 않은 메시지를 버퍼링했다가 bot이 실제로 트리거될 때 컨텍스트로 주입할 수 있습니다.
  • 기본 limit: 50
  • config: channels.whatsapp.historyLimit
  • fallback: messages.groupChat.historyLimit
  • 0이면 비활성화
주입 마커:
  • [Chat messages since your last reply - for context]
  • [Current message - respond to this]
허용된 inbound WhatsApp message에는 기본적으로 read receipt를 보냅니다.전역 비활성화:
{
  channels: {
    whatsapp: {
      sendReadReceipts: false,
    },
  },
}
account별 override:
{
  channels: {
    whatsapp: {
      accounts: {
        work: {
          sendReadReceipts: false,
        },
      },
    },
  },
}
self-chat turn에서는 전역 설정이 켜져 있어도 read receipt를 보내지 않습니다.

전달, 청킹, 미디어

  • 기본 chunk limit: channels.whatsapp.textChunkLimit = 4000
  • channels.whatsapp.chunkMode = "length" | "newline"
  • newline 모드는 빈 줄 기준 문단 경계를 우선 사용하고, 불가능하면 길이 기준 청킹으로 fallback합니다.
  • image, video, audio (PTT voice-note), document payload 지원
  • audio/ogg는 voice-note 호환성을 위해 audio/ogg; codecs=opus로 재작성
  • animated GIF 재생은 video 전송 시 gifPlayback: true로 지원
  • multi-media reply payload에서는 caption이 첫 번째 media item에 적용됨
  • media source는 HTTP(S), file://, 로컬 경로를 지원
  • inbound media 저장 제한: channels.whatsapp.mediaMaxMb (기본 50)
  • outbound media 전송 제한: channels.whatsapp.mediaMaxMb (기본 50)
  • account별 override: channels.whatsapp.accounts.<accountId>.mediaMaxMb
  • 이미지는 제한에 맞도록 자동 최적화됩니다. (resize/quality sweep)
  • media 전송 실패 시, 첫 항목 fallback은 응답을 조용히 버리지 않고 경고 텍스트를 전송합니다.

Acknowledgment reactions

WhatsApp은 channels.whatsapp.ackReaction으로 inbound 수신 직후 즉시 ack reaction을 보낼 수 있습니다.
{
  channels: {
    whatsapp: {
      ackReaction: {
        emoji: "👀",
        direct: true,
        group: "mentions", // always | mentions | never
      },
    },
  },
}
동작 참고:
  • inbound가 수락되면 reply 전에 즉시 전송
  • 실패해도 로그만 남기고 일반 reply delivery는 막지 않음
  • group mode mentions는 mention-triggered turn에서만 reaction을 보냄. group activation always는 이 검사를 우회하는 역할을 함
  • WhatsApp은 channels.whatsapp.ackReaction을 사용합니다. (messages.ackReaction legacy 키는 여기서 사용되지 않음)

멀티 계정과 자격 증명

  • account id는 channels.whatsapp.accounts에서 옴
  • 기본 account 선택: default가 있으면 그것을 사용, 없으면 정렬된 첫 account id를 사용
  • account id는 내부 조회를 위해 정규화됩니다.
  • 현재 auth 경로: ~/.openclaw/credentials/whatsapp/<accountId>/creds.json
  • backup 파일: creds.json.bak
  • ~/.openclaw/credentials/에 있던 legacy default auth도 default-account 흐름에서 인식되고 migration됩니다.
openclaw channels logout --channel whatsapp [--account <id>]는 해당 account의 WhatsApp auth state를 지웁니다.legacy auth directory에서는 oauth.json은 보존하고 Baileys auth 파일만 제거합니다.

도구, actions, config writes

  • Agent tool은 WhatsApp reaction action(react)을 지원합니다.
  • Action gate:
    • channels.whatsapp.actions.reactions
    • channels.whatsapp.actions.polls
  • 채널에서 시작된 config write는 기본적으로 허용됩니다. (channels.whatsapp.configWrites=false로 비활성화)

문제 해결

증상: channel status가 not linked를 보고함해결:
openclaw channels login --channel whatsapp
openclaw channels status
증상: linked account인데 반복적인 disconnect 또는 reconnect 시도 발생해결:
openclaw doctor
openclaw logs --follow
필요하면 channels login으로 다시 연결하세요.
대상 account에 active gateway listener가 없으면 outbound send는 즉시 실패합니다.gateway가 실행 중이고 해당 account가 linked 상태인지 확인하세요.
다음 순서로 확인하세요.
  • groupPolicy
  • groupAllowFrom / allowFrom
  • groups allowlist 항목
  • mention gating (requireMention + mention patterns)
  • openclaw.json의 duplicate key (JSON5): 뒤에 오는 값이 앞의 값을 덮어쓰므로, scope별 groupPolicy는 하나만 유지하세요.
WhatsApp gateway runtime은 Node를 사용해야 합니다. Bun은 안정적인 WhatsApp/Telegram gateway 운영과 호환되지 않는 것으로 간주됩니다.

설정 레퍼런스 포인터

기본 레퍼런스: 주요 WhatsApp 필드:
  • access: dmPolicy, allowFrom, groupPolicy, groupAllowFrom, groups
  • delivery: textChunkLimit, chunkMode, mediaMaxMb, sendReadReceipts, ackReaction
  • multi-account: accounts.<id>.enabled, accounts.<id>.authDir, account-level overrides
  • operations: configWrites, debounceMs, web.enabled, web.heartbeatSeconds, web.reconnect.*
  • session behavior: session.dmScope, historyLimit, dmHistoryLimit, dms.<id>.historyLimit

관련 문서