answerLoopsanswerLoopsDocs

Google Chat

Connect a Google Chat space to answerLoops with a one-time connect code — no OAuth flow required.

Your community

answerLoops

What happens next

Replies and escalation mentions appear in the same Google Chat thread
Your Chat space. A member posts in the Google Chat space you paired with a connect code. The answerLoops Chat app is in that space and replies there.

Overview

Google Chat connects differently than Slack or Discord. Google Chat's app model has no equivalent of Slack's "Add to Slack" OAuth button for installing across an arbitrary customer's Workspace — there's no redirect-based install answerLoops can drive. Instead, an org generates a one-time connect code in answerLoops, a Workspace admin adds the answerLoops app to a Chat space themselves, and posting that code in the space pairs it to the org.

Every message in a paired space is ingested as a ticket, exactly like every other channel:

  • AI deflection with a configurable confidence threshold — gated by the Automatic Deflections toggle below
  • Ticket creation and deduplication
  • Thread-aware replies — a reply inside a Google Chat thread appends to its existing ticket instead of creating a new one
  • Attachment handling — an attachment-only message with no caption is still ingested; each attachment is folded into a [Attachment: name] — url line so nothing gets silently dropped
  • Escalation mention when AI confidence is low, addressed to a specific Chat user id you configure

Automatic Deflections is off by default for every newly connected platform. While it's off, even a high-confidence answer is held as a draft on the dashboard awaiting Approve/Edit/Dismiss instead of posting to the space automatically — the space gets a brief acknowledgment instead. Turn it on per-platform in Integrations → Google Chat → Edit escalation, confidence & deflections, toggle Automatic Deflections, then Save, once you trust the AI's answers going out unsupervised.

v1 supports one connected Google Chat space per org. Multi-space support (like Discord's multi-server connections) may follow later if there's demand.


The connect-code pairing flow

This is Google Chat's most distinctive setup step, so it's worth walking through exactly what happens on each side.

1. Generate a connect code

In Settings → Integrations → Google Chat, click Generate connect code. This calls generateGoogleChatConnectCodeAction, which:

  • Requires an organization owner or admin.
  • Checks the org isn't already connected — if a google_chat integration row already has a paired space id, the action refuses and returns an error telling you to disconnect first. Regenerating a code for an already-paired org has no legitimate use case, and silently overwriting the pairing would be surprising.
  • Generates a one-time connect code beginning with gc_.
  • Saves it on a pending integration (enabled: false) with a 24-hour expiry, stored protected rather than in plain text, so Settings can keep showing it until it is used or expires.

The code is single-use and expires 24 hours after it is generated. While an unexpired code is outstanding, generating again shows the same code.

2. Add the answerLoops app to a Google Chat space

You (or your Workspace admin) add the answerLoops Chat app to the space you want connected — the same app every answerLoops org uses, hosted under answerLoops' own Google Cloud project. If your Workspace admin hasn't enabled third-party Chat apps for the domain yet, they'll need to do that first from their Admin Console before the app can be added.

3. Post the code in that space

Post /connect <code> as a message in the space. That message hits the shared inbound webhook (app/api/google-chat/events/route.ts), which matches it against ^\/connect\s+(\S+)$ before doing anything else with the event. The handler redeems the code with completeGoogleChatPairing(code, spaceName), a single atomic database statement. It only matches a google_chat row that has not been paired yet, whose pairing code digest matches and has not expired.

  • Code not recognized (typo, expired, already consumed, never generated, or the integration is already paired): the space gets back "That connect code wasn't recognized or has expired — check Settings → Integrations → Google Chat for a fresh one." Nothing is written to the database.
  • Space already connected elsewhere: if another enabled integration already holds that space, the space is told it is already connected and nothing changes.
  • Code recognized: in the same statement that matches it, team_id is set to the space's resourceName (e.g. spaces/AAAAxxxxxxx), enabled becomes 1, and the pairing columns are cleared, so the code cannot be used a second time. The space receives "✅ This space is now connected. Questions posted here will flow into your answerLoops dashboard."

4. Confirm on the Settings page

Back in answerLoops, leave the Google Chat card open. While a connect code is outstanding it polls for the pairing every few seconds and switches to Connected · space paired on its own once pairing completes server-side — there's also a Check now button to force it. The card then reveals the connected space id, escalation user, confidence threshold, and Automatic Deflections state. The connect code is stored the moment you generate it, so it survives a page reload; you won't be asked to generate a new one (and won't accidentally invalidate the one you already posted) until it expires.

A paired Google Chat integration has no shared secret of its own: requests from Google are authenticated by the signed token Google attaches to every event, and a connect code is never accepted as a credential for any other endpoint.

The connect code and the "add the app to a space" step can happen in either order — generating the code doesn't require the app to already be in the space, and adding the app doesn't require a code yet. Pairing only completes once /connect <code> is posted in the space after the app has joined it.


Authentication model

Unlike Slack and Discord, where each connected workspace/server gets its own bot token, Google Chat authenticates every send as a single service account shared by every connected org — the Chat app itself, owned by answerLoops' Google Cloud project, scoped to https://www.googleapis.com/auth/chat.bot. There's no per-org token to paste or rotate; routing an outbound reply to the right org's space happens entirely by mapping the message's spaceName to the paired integrations row.

Inbound events are verified the same centralized way: every request Google Chat sends to the webhook carries a signed OIDC ID token in its Authorization header, issued by [email protected] with an audience matching GOOGLE_CHAT_ENDPOINT_URL exactly. lib/google-chat/verify.ts checks both the issuer and the audience before any event is processed — a request that doesn't carry a valid token from Google is rejected with a 403 before it's even parsed.

Outbound replies longer than 2,990 characters are split across multiple messages at the nearest newline (lib/google-chat/send.ts), the same conservative threshold used for Slack. A reply into an existing thread sets messageReplyOption=REPLY_MESSAGE_OR_FAIL and includes the thread's resourceName (spaces/AAAA/threads/BBBB) — Google Chat's equivalent of Slack's thread_ts.


Escalation and thresholds

Configure these from Integrations → Google Chat → Edit escalation, confidence & deflections:

FieldFormatNotes
Escalation user idusers/12345678901234567890The Chat resource name of the person to notify when AI confidence is below threshold. Google Chat has no role or group-mention equivalent — escalation always targets one specific user.
Confidence threshold0–1, default 0.8Answers scoring at or above this are eligible to auto-post (if Automatic Deflections is on) or are held as drafts otherwise.
Automatic Deflectionson/off, default offSee the callout above.

A reply inside a tracked thread is ingested even if it's very short — anything under 10 characters that isn't a tracked reply and carries no attachment is dropped as noise (e.g. a lone "ok" or emoji reaction in an otherwise unrelated space). This mirrors the noise filtering other channels apply.


What's different from Slack/Discord

  • No bot token per org. Sending replies authenticates as the single answerLoops-owned service account described above — nothing to paste or rotate per workspace.
  • No OAuth callback. Pairing is the connect-code flow above, not a redirect-based "Add to Slack"/"Add to Discord"-style install, because Google Chat's unlisted-app model doesn't hand back an install callback with the space id.
  • No role/group mentions. Escalation targets exactly one Chat user id, not a role or usergroup.
  • One space per org (v1). Discord supports multiple connected servers per org; Google Chat currently supports one paired space.

Environment variables reference

These are set once by the platform operator — they configure the single shared Chat app, not anything per-org. Self-hosted deployments must set both; answerLoops Cloud manages them centrally.

VariableRequiredDescription
GOOGLE_CHAT_SERVICE_ACCOUNT_JSONYes (self-host)Full JSON key for the service account used to authenticate outbound sends, as a single-line string
GOOGLE_CHAT_ENDPOINT_URLYes (self-host)Public HTTPS URL of the inbound webhook (https://{domain}/api/google-chat/events) — must exactly match the endpoint configured in the Chat app's connection settings, since Google signs each request's token audience to this value

See Google Chat App Setup for the full one-time Google Cloud walkthrough (creating the project, enabling the Chat API, creating the service account, and configuring the app's connection settings and visibility).


Troubleshooting

On this page