Mainstream messaging
Google Chat
Google Chat runs as the official @openclaw/googlechat plugin: DMs and spaces through Google Chat API webhooks (HTTP endpoint only, no Pub/Sub).
Install
openclaw plugins install @openclaw/googlechatLocal checkout (when running from a git repo):
openclaw plugins install ./path/to/local/googlechat-pluginQuick setup (beginner)
- Create a Google Cloud project and enable the Google Chat API.
- Go to: Google Chat API Credentials
- Enable the API if it is not already enabled.
- Create a Service Account:
- Press Create Credentials > Service Account.
- Name it whatever you want (e.g.,
openclaw-chat). - Leave permissions and principals blank (Continue, then Done).
- Create and download the JSON key:
- Click the new service account > Keys tab > Add Key > Create new key > JSON > Create.
- Store the downloaded JSON file on your gateway host (e.g.,
~/.openclaw/googlechat-service-account.json). - Create a Google Chat app in the Google Cloud Console Chat Configuration:
- Fill in Application info (app name, avatar URL, description).
- Enable Interactive features.
- Under Functionality, check Join spaces and group conversations.
- Under Connection settings, select HTTP endpoint URL.
- Under Triggers, select Use a common HTTP endpoint URL for all triggers and set it to your public gateway URL followed by
/googlechat(see Public URL). - Under Visibility, check Make this Chat app available to specific people and groups in
<Your Domain>and enter your email address. - Click Save.
- Enable the app status: refresh the page, find App status, set it to Live - available to users, and Save again.
- Configure OpenClaw with the service account and the webhook audience (must match the Chat app config):
- Env:
GOOGLE_CHAT_SERVICE_ACCOUNT_FILE=/path/to/service-account.json(default account only), or - Config: see Config highlights.
openclaw channels add --channel googlechatalso accepts--audience-type,--audience,--webhook-path, and--webhook-url.
- Env:
- Start the gateway. Google Chat will POST to your webhook path (default
/googlechat).
Add to Google Chat
Once the gateway is running and your email is on the visibility list:
- Go to Google Chat.
- Click the + (plus) icon next to Direct Messages.
- Search for the App name you configured in the Google Cloud Console.
- The bot does not appear in the Marketplace browse list because it is a private app. Search for it by name.
- Select the bot, click Add or Chat, and send a message.
Public URL (Webhook-only)
Google Chat webhooks require a public HTTPS endpoint. For security, expose only the /googlechat path to the internet and keep the OpenClaw dashboard and other endpoints private.
Option A: Tailscale Funnel (Recommended)
Use Tailscale Serve for the private dashboard and Funnel for the public webhook path.
-
Check what address your gateway is bound to:
bash # Linux (iproute2):ss -tlnp | grep 18789 # macOS (no ss):lsof -iTCP:18789 -sTCP:LISTENNote the IP (e.g.,
127.0.0.1,0.0.0.0, or a Tailscale100.x.x.xaddress). -
Expose the dashboard to the tailnet only (port 8443):
bash # If bound to localhost (127.0.0.1 or 0.0.0.0):tailscale serve --bg --https 8443 http://127.0.0.1:18789 # If bound to a Tailscale IP only:tailscale serve --bg --https 8443 http://100.x.x.x:18789 -
Expose only the webhook path publicly:
bash # If bound to localhost (127.0.0.1 or 0.0.0.0):tailscale funnel --bg --set-path /googlechat http://127.0.0.1:18789/googlechat # If bound to a Tailscale IP only:tailscale funnel --bg --set-path /googlechat http://100.x.x.x:18789/googlechat -
If prompted, visit the authorization URL shown in the output to enable Funnel for this node.
-
Verify:
bash tailscale serve statustailscale funnel status
Your public webhook URL is https://<node-name>.<tailnet>.ts.net/googlechat. The dashboard stays tailnet-only at https://<node-name>.<tailnet>.ts.net:8443/. Use the public URL (without :8443) in the Google Chat app config.
Note: This configuration persists across reboots. Remove it later with
tailscale funnel resetandtailscale serve reset.
Option B: Reverse Proxy (Caddy)
Proxy only the webhook path:
your-domain.com { reverse_proxy /googlechat* localhost:18789}Requests to your-domain.com/ are ignored or 404, while your-domain.com/googlechat routes to OpenClaw.
Option C: Cloudflare Tunnel
Configure the tunnel ingress rules to route only the webhook path:
- Path:
/googlechat->http://localhost:18789/googlechat - Default rule: HTTP 404 (Not Found)
How it works
- Google Chat POSTs JSON to the gateway webhook path (POST only, JSON content type required, per-IP rate limited).
- OpenClaw authenticates every request before dispatch:
- Chat app events carry
Authorization: Bearer <token>. The token is verified before the full body is parsed. - Google Workspace Add-on events carry the token in the body (
authorizationEventObject.systemIdToken). OpenClaw reads them under a stricter pre-auth budget (16 KB, 3 s) before verification.
- Chat app events carry
- The token is checked against
audienceType+audience:audienceType: "app-url"→ audience is your HTTPS webhook URL.audienceType: "project-number"→ audience is the Cloud project number.- Add-on tokens under
app-urladditionally requireappPrincipalset to the app's numeric OAuth 2.0 client ID (21 digits, not an email). Otherwise verification fails with a logged warning.
- Messages route by space:
- Spaces get per-space sessions
agent:<agentId>:googlechat:group:<spaceId>. Replies go to the message thread. - DMs collapse into the agent's main session by default. Set
session.dmScopefor per-peer DM sessions (see Session).
- Spaces get per-space sessions
- DM access is pairing by default. Unknown senders receive a pairing code. Approve with:
openclaw pairing approve googlechat <code>
- Group spaces require @-mention by default. Mentions are detected from Chat
USER_MENTIONannotations targeting the app. SetbotUser(e.g.,users/1234567890) if detection needs the app's user resource name. - When an exec or plugin approval starts from Google Chat and a stable
users/<id>approver is configured, OpenClaw posts a native approval card (cardsV2) in the originating space or thread. Card buttons carry opaque callback tokens. The manual/approve <id> <decision>prompt appears only when native delivery is unavailable.
Inbound durability
After request authentication, OpenClaw removes the add-on authorization object from storage and durably queues Google Chat MESSAGE events before returning 200. A persistence failure returns 503, allowing Google Chat to retry instead of acknowledging an event that could be lost. A durably queued 200 carries x-openclaw-delivery-accepted: durable. Non-message action acks and error responses omit the marker, so reverse proxies can require it to distinguish durable acceptance from a generic 200.
Pending or retryable messages survive a Gateway restart, remain serialized per space, and use the Google Chat message resource name to suppress duplicate queue entries while the active or retained completion record exists. Non-message actions keep their existing detached webhook path and do not receive this durable-queue guarantee. Delivery remains at least once across the queue-to-agent boundary, so a crash during handoff can replay a turn.
Targets
Use these identifiers for delivery and allowlists:
- Direct messages:
users/<userId>(recommended). - Spaces:
spaces/<spaceId>. - Raw email
[email protected]is mutable and only used for allowlist matching whenchannels.googlechat.dangerouslyAllowNameMatching: true. - Deprecated:
users/<email>is treated as a user id, not an email allowlist entry. - Prefixes
googlechat:,google-chat:, andgchat:are accepted and stripped.
Config highlights
{ channels: { googlechat: { enabled: true, serviceAccountFile: "/path/to/service-account.json", // or serviceAccount: { source: "file", provider: "filemain", id: "/channels/googlechat/serviceAccount" } audienceType: "app-url", audience: "https://gateway.example.com/googlechat", appPrincipal: "123456789012345678901", // add-on verification only; numeric OAuth client ID webhookPath: "/googlechat", botUser: "users/1234567890", // optional; helps mention detection allowBots: false, dmPolicy: "pairing", allowFrom: ["users/1234567890"], groupPolicy: "allowlist", groups: { "spaces/AAAA": { enabled: true, requireMention: true, users: ["users/1234567890"], systemPrompt: "Short answers only.", }, }, typingIndicator: "message", mediaMaxMb: 20, }, },}Notes:
- Service account credentials:
serviceAccountFile(path) orserviceAccount(inline JSON string, object, or env/file/exec/store SecretRef). Env varsGOOGLE_CHAT_SERVICE_ACCOUNT(inline JSON) andGOOGLE_CHAT_SERVICE_ACCOUNT_FILE(path) apply to the default account only. Multi-account setups usechannels.googlechat.accounts.<id>with the same keys, including per-accountserviceAccountSecretRefs. - Omitted account
dmPolicyandgroupPolicyinherit the channel root. Explicit account policies win. The root defaults topairingandallowlistrespectively. Shared settings fromaccounts.defaulthave lower precedence than the root. Its credentials,enabled, anddangerouslyAllowNameMatchingare not inherited by named accounts. - Default webhook path is
/googlechatwhenwebhookPathis unset.webhookUrlcan supply the path instead. - Group keys must be stable space ids (
spaces/<spaceId>). Display-name keys are deprecated and logged as such. dangerouslyAllowNameMatchingre-enables mutable email principal matching for allowlists (break-glass compatibility mode). Doctor warns about email entries.- Google Chat reaction actions are not exposed. The plugin uses service-account authentication, while Google Chat reaction endpoints require user authentication. Remove unsupported legacy reaction settings with
openclaw doctor --fix. - Native approval cards use Google Chat
cardsV2button clicks, not reaction events. Approvers come fromallowFromordefaultToand must be stable numericusers/<id>values. - Message actions expose text
sendonly. Google Chat attachment upload requires user authentication, while this plugin uses service-account authentication, so outbound file upload is not exposed. typingIndicator:message(default) posts a_<Bot> is typing..._placeholder and edits it into the first reply.nonedisables it.reactionrequires user OAuth and currently falls back tomessagewith a logged error under service-account auth.- OpenClaw downloads the first inbound attachment per message through the Chat API into the media pipeline.
mediaMaxMbcaps that download (default 20). Google Drive files are not downloaded. The agent receives an unavailable-attachment notice asking for a direct file upload instead. Other unsupported attachment sources receive the same upload guidance. Messages with multiple attachments include a counted notice for the additional attachments that were not processed. Oversize attachments retain their size-limit notice. - Bot-authored messages are ignored by default. With
allowBots: true, accepted bot messages use shared bot loop protection: configurechannels.defaults.botLoopProtection, then override withchannels.googlechat.botLoopProtectionorchannels.googlechat.groups.<space>.botLoopProtection.
Custom emoji listing is unavailable because Google Chat's customEmojis.list endpoint requires user authentication with the chat.customemojis or chat.customemojis.readonly scope. This plugin authenticates exclusively as a service account with the chat.bot scope, which cannot access that endpoint.
Secrets reference details: Secrets Management.
Troubleshooting
405 Method Not Allowed
If Google Cloud Logs Explorer shows errors like:
status code: 405, reason phrase: HTTP error response: HTTP/1.1 405 Method Not AllowedThe webhook handler is not registered. Common causes:
-
Channel not configured: the
channels.googlechatsection is missing. Verify with:bash openclaw config get channels.googlechatIf it returns "Config path not found", add the configuration (see Config highlights).
-
Plugin not enabled: check plugin status:
bash openclaw plugins list | grep googlechatIf it shows "disabled", add
plugins.entries.googlechat.enabled: trueto your config. -
Gateway not restarted after config changes:
bash openclaw gateway restart
Verify the channel is running:
openclaw channels status# Should show: Google Chat default: enabled, configured, ...Other issues
openclaw channels status --probesurfaces auth errors and missing audience config (audienceandaudienceTypeare both required).- If no messages arrive, confirm the Chat app's webhook URL and trigger configuration.
- If mention gating blocks replies, set
botUserto the app's user resource name and checkrequireMention. openclaw logs --followwhile sending a test message shows whether requests reach the gateway.
Related
- Channels Overview — all supported channels
- Channel routing — session routing for messages
- Gateway configuration
- Groups — group chat behavior and mention gating
- Pairing — DM authentication and pairing flow
- Security — access model and hardening