Google Chat Integration: Setup and Configuration Guide
Covers the official @openclaw/googlechat plugin for Google Chat, including DMs and spaces via API webhooks. Written for gateway operators who need to install and configure the integration.
Read this when
- Working on Google Chat channel features
Google Chat is available as the official @openclaw/googlechat plugin, handling DMs and spaces via Google Chat API webhooks (HTTP endpoint only, no Pub/Sub).
Install
openclaw plugins install @openclaw/googlechat
When you're working from a git repo, use a local checkout:
openclaw plugins install ./path/to/local/googlechat-plugin
Quick setup (beginner)
- Set up a Google Cloud project, then turn on the Google Chat API.
- Visit: Google Chat API Credentials
- If the API isn't enabled yet, enable it.
- Set up a Service Account:
- Choose Create Credentials > Service Account.
- Pick any name you like (for instance,
openclaw-chat). - Skip permissions and principals (Continue, then Done).
- Generate and save the JSON key:
- Select the service account you just made > Keys tab > Add Key > Create new key > JSON > Create.
- Place the downloaded JSON file somewhere on your gateway host (for example,
~/.openclaw/googlechat-service-account.json). - In the Google Cloud Console Chat Configuration, build a Google Chat app:
- Complete Application info (name, avatar URL, description).
- Turn on Interactive features.
- In Functionality, tick Join spaces and group conversations.
- In Connection settings, choose HTTP endpoint URL.
- In Triggers, pick Use a common HTTP endpoint URL for all triggers, then point it at your public gateway URL with
/googlechatappended (refer to Public URL). - In Visibility, tick Make this Chat app available to specific people and groups in
<Your Domain>and fill in your email address. - Hit Save.
- Turn on the app status: reload the page, locate App status, switch it to Live - available to users, then Save once more.
- Set up OpenClaw with the service account and webhook audience (this has to line up with the Chat app config):
- Env:
GOOGLE_CHAT_SERVICE_ACCOUNT_FILE=/path/to/service-account.json(default account only), or - Config: refer to Config highlights.
openclaw channels add --channel googlechatalso takes--audience-type,--audience,--webhook-path, and--webhook-url.
- Env:
- Launch the gateway. Google Chat will POST to your webhook path (default
/googlechat).
Add to Google Chat
With the gateway up and your email listed under visibility:
- Open Google Chat.
- Hit the + (plus) icon beside Direct Messages.
- Look up the App name you set in the Google Cloud Console.
- Since it's a private app, the bot won't show up in the Marketplace browse list. Find it by searching its name.
- Pick the bot, press Add or Chat, then send a message.
Public URL (Webhook-only)
A public HTTPS endpoint is mandatory for Google Chat webhooks. To stay safe, expose only the /googlechat path to the internet, and leave the OpenClaw dashboard plus every other endpoint private.
Option A: Tailscale Funnel (Recommended)
For the private dashboard use Tailscale Serve, and for the public webhook path use Funnel.
-
Find out which address your gateway is bound to:
# Linux (iproute2): ss -tlnp | grep 18789 # macOS (no ss): lsof -iTCP:18789 -sTCP:LISTENTake note of the IP (such as
127.0.0.1,0.0.0.0, or a Tailscale100.x.x.xaddress). -
Make the dashboard reachable on the tailnet only (port 8443):
# 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 -
Make just the webhook path publicly reachable:
# 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 you're asked, open the authorization URL printed in the output to turn on Funnel for this node.
-
Confirm it works:
tailscale serve status tailscale funnel status
Your public webhook URL is https://<node-name>.<tailnet>.ts.net/googlechat. The dashboard remains tailnet-only at https://<node-name>.<tailnet>.ts.net:8443/. In the Google Chat app config, use the public URL (drop :8443).
Note: This setup survives reboots. To undo it later, run
tailscale funnel resetandtailscale serve reset.
Option B: Reverse Proxy (Caddy)
Forward only the webhook path:
your-domain.com {
reverse_proxy /googlechat* localhost:18789
}
Anything hitting your-domain.com/ gets ignored or returns 404, whereas your-domain.com/googlechat goes through to OpenClaw.
Option C: Cloudflare Tunnel
Set the tunnel ingress rules so that only the webhook path is routed:
- Path:
/googlechat->http://localhost:18789/googlechat - Default rule: HTTP 404 (Not Found)
How it works
- Google Chat sends JSON to the gateway webhook path (POST only, JSON content type required, rate limited per IP).
- OpenClaw verifies each request before dispatching it:
- Chat app events include
Authorization: Bearer <token>. Verification of the token happens before the full body is parsed. - For Google Workspace Add-on events, the token arrives in the body (
authorizationEventObject.systemIdToken). OpenClaw reads these under a stricter pre-auth budget (16 KB, 3 s) ahead of verification.
- Chat app events include
- The token is validated against
audienceType+audience:audienceType: "app-url"→ your HTTPS webhook URL is the audience.audienceType: "project-number"→ the Cloud project number is the audience.- Add-on tokens under
app-urlalso demand thatappPrincipalbe set to the app's numeric OAuth 2.0 client ID (21 digits, not an email). If not, verification fails and a warning is logged.
- Routing of messages happens by space:
- Each space gets its own session
agent:<agentId>:googlechat:group:<spaceId>. Replies land in the message thread. - By default, DMs fold into the agent's main session. For per-peer DM sessions, set
session.dmScope(see Session).
- Each space gets its own session
- DM access defaults to pairing. A pairing code is sent to unknown senders. To approve, use:
openclaw pairing approve googlechat <code>
- Group spaces need an @-mention by default. Detection relies on Chat
USER_MENTIONannotations that target the app. If detection requires the app's user resource name, setbotUser(for example,users/1234567890). - When an exec or plugin approval originates from Google Chat and a stable
users/<id>approver is configured, OpenClaw places a native approval card (cardsV2) in the space or thread where it started. Opaque callback tokens ride along on the card buttons. The manual/approve <id> <decision>prompt shows up only if native delivery is not possible.
Inbound durability
Once a request is authenticated, OpenClaw clears the add-on authorization object from storage and durably queues Google Chat MESSAGE events prior to returning 200. Should persistence fail, 503 is returned, which lets Google Chat retry rather than acknowledge an event that might be lost. A durably queued 200 carries x-openclaw-delivery-accepted: durable. Non-message action acks and error responses leave the marker out, so reverse proxies can demand it to tell durable acceptance apart from a generic 200.
Messages that are pending or retryable outlive a Gateway restart, stay serialized per space, and rely on the Google Chat message resource name to avoid duplicate queue entries while the active or retained completion record is present. Non-message actions follow their existing detached webhook path and are not covered by this durable-queue guarantee. Across the queue-to-agent boundary, delivery stays at least once, so a crash mid-handoff may replay a turn.
Targets
For delivery and allowlists, use the identifiers below:
- Direct messages:
users/<userId>(recommended). - Spaces:
spaces/<spaceId>. - Raw email
name@example.comcan change and is only matched against allowlists whenchannels.googlechat.dangerouslyAllowNameMatching: true. - Deprecated:
users/<email>counts as a user id, not as an email allowlist entry. - The prefixes
googlechat:,google-chat:, andgchat:are accepted and removed.
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). The env varsGOOGLE_CHAT_SERVICE_ACCOUNT(inline JSON) andGOOGLE_CHAT_SERVICE_ACCOUNT_FILE(path) only apply to the default account. For setups with multiple accounts, usechannels.googlechat.accounts.<id>with the same keys, which includes per-accountserviceAccountSecretRefs. - When account
dmPolicyandgroupPolicyare left out, they take after the channel root. Policies set explicitly on an account take precedence. The root falls back topairingandallowlistrespectively. Settings shared throughaccounts.defaultrank below the root. Named accounts do not inherit its credentials,enabled, ordangerouslyAllowNameMatching. - With
webhookPathunset, the webhook path defaults to/googlechat. Alternatively,webhookUrlcan provide the path. - Group keys need to be stable space ids (
spaces/<spaceId>). Keys based on display names are deprecated, and a log entry marks them as such. dangerouslyAllowNameMatchingturns mutable email principal matching back on for allowlists (a break-glass compatibility mode). Doctor raises a warning for email entries.- Reaction actions for Google Chat are not available. Service-account authentication is what the plugin uses, whereas Google Chat reaction endpoints demand user authentication. Use
openclaw doctor --fixto strip out legacy reaction settings that are unsupported. - Native approval cards rely on Google Chat
cardsV2button clicks rather than reaction events. Approvers are drawn fromallowFromordefaultTo, and each must be a stable numericusers/<id>value. - Only text
sendis offered through message actions. Uploading Google Chat attachments demands user authentication, but this plugin authenticates with a service account, so outbound file upload is not available. typingIndicator:message(the default) posts a_<Bot> is typing..._placeholder, then edits it into the first reply.noneturns this off.reactionneeds user OAuth and at present falls back tomessagewith a logged error when service-account auth is in use.- For each message, OpenClaw fetches the first inbound attachment via the Chat API and feeds it into the media pipeline. That download is capped by
mediaMaxMb(default 20). Files on Google Drive are skipped. In their place, the agent gets an unavailable-attachment notice that requests a direct file upload. The same upload guidance goes to other unsupported attachment sources. When a message carries several attachments, a counted notice names the extra ones that went unprocessed. Attachments that exceed the size limit keep their size-limit notice. - Messages written by bots are skipped unless you opt in. Once
allowBots: trueis set, accepted bot messages fall under shared bot loop protection: set upchannels.defaults.botLoopProtection, then override it withchannels.googlechat.botLoopProtectionorchannels.googlechat.groups.<space>.botLoopProtection.
Listing custom emoji is not possible, since Google Chat's customEmojis.list endpoint needs user authentication carrying the chat.customemojis or chat.customemojis.readonly scope. This plugin authenticates only as a service account with the chat.bot scope, which has no access to that endpoint.
For secrets reference details, see Secrets Management.
Troubleshooting
405 Method Not Allowed
When Google Cloud Logs Explorer reports errors along these lines:
status code: 405, reason phrase: HTTP error response: HTTP/1.1 405 Method Not Allowed
Then the webhook handler has not been registered. Typical causes:
-
Channel not configured: the
channels.googlechatsection is absent. Check with:openclaw config get channels.googlechatShould it return "Config path not found", add the configuration (see Config highlights).
-
Plugin not enabled: verify plugin status:
openclaw plugins list | grep googlechatShould it read "disabled", execute
openclaw plugins enable googlechatand review the application result. -
Configuration not applied: inspect hot reload status along with Gateway logs. Bring the Gateway up if it is offline. Restart the Gateway after changing the service environment so the change is loaded.
Confirm the channel is running:
openclaw channels status
# Should show: Google Chat default: enabled, configured, ...
Other issues
- Auth errors and missing audience config surface through
openclaw channels status --probe(audienceandaudienceTypeare both required). - Should no messages show up, double-check the Chat app's webhook URL and trigger configuration.
- Should mention gating stop replies, point
botUserat the app's user resource name and inspectrequireMention. - Running
openclaw logs --followduring a test message reveals whether requests are reaching the gateway.
Related
- Channels Overview: every channel that is supported
- Channel routing: how sessions are routed for messages
- Gateway configuration
- Groups: mention gating and how group chats behave
- Pairing: the pairing flow and DM authentication
- Security: the access model plus hardening