Назад към всички

google-chat-messages

// Send Google Chat messages via webhook — text, rich cards (cardsV2), threaded replies. Includes TypeScript types, card builder utility, and widget reference.

$ git log --oneline --stat
stars:577
forks:110
updated:March 4, 2026
SKILL.mdreadonly
SKILL.md Frontmatter
namegoogle-chat-messages
descriptionSend Google Chat messages via webhook — text, rich cards (cardsV2), threaded replies. Includes TypeScript types, card builder utility, and widget reference.
compatibilityclaude-code-only

Google Chat Messages

Send messages to Google Chat spaces via incoming webhooks. Produces text messages, rich cards (cardsV2), and threaded replies.

What You Produce

  • Text messages with Google Chat formatting
  • Rich card messages (cardsV2) with headers, sections, widgets
  • Threaded conversations
  • Reusable webhook sender utility

Workflow

Step 1: Get Webhook URL

In Google Chat:

  1. Open a Space > click space name > Manage webhooks
  2. Create webhook (name it, optionally add avatar URL)
  3. Copy the webhook URL

Store the URL as an environment variable or in your secrets manager — never hardcode.

Step 2: Choose Message Type

NeedTypeComplexity
Simple notificationText messageLow
Structured info (status, digest)Card message (cardsV2)Medium
Ongoing updatesThreaded repliesMedium
Action buttons (open URL)Card with buttonListMedium

Step 3: Send the Message

Use assets/webhook-sender.ts for the sender utility. Use assets/card-builder.ts for structured card construction.

Text Formatting

Google Chat does NOT use standard Markdown.

FormatSyntaxExample
Bold*text**important*
Italic_text__emphasis_
Strikethrough~text~~removed~
Monospace`text``code`
Code block```text```Multi-line code
Link<url|text><https://example.com|Click here>
Mention user<users/USER_ID><users/123456>
Mention all<users/all><users/all>

Not supported: **double asterisks**, headings (###), blockquotes, tables, images inline.

Text Message Example

await sendText(webhookUrl, '*Build Complete*\n\nBranch: `main`\nStatus: Passed\n<https://ci.example.com/123|View Build>');

cardsV2 Structure

Cards use the cardsV2 format (recommended over legacy cards).

const message = {
  cardsV2: [{
    cardId: 'unique-id',
    card: {
      header: {
        title: 'Card Title',
        subtitle: 'Optional subtitle',
        imageUrl: 'https://example.com/icon.png',
        imageType: 'CIRCLE'  // or 'SQUARE'
      },
      sections: [{
        header: 'Section Title',  // optional
        widgets: [
          // widgets go here
        ]
      }]
    }
  }]
};

Widget Types

Text paragraph — formatted text block:

{ textParagraph: { text: '*Bold* and _italic_ text' } }

Decorated text — label + value with optional icon:

{
  decoratedText: {
    topLabel: 'Status',
    text: 'Deployed',
    startIcon: { knownIcon: 'STAR' }
  }
}

Button list — action buttons:

{
  buttonList: {
    buttons: [{
      text: 'View Dashboard',
      onClick: { openLink: { url: 'https://dashboard.example.com' } }
    }]
  }
}

Image — standalone image:

{ image: { imageUrl: 'https://example.com/chart.png', altText: 'Usage chart' } }

Divider — horizontal separator:

{ divider: {} }

See references/widget-reference.md for all widget types with full examples. See references/icon-list.md for all available knownIcon values.

Threading

Thread messages together using threadKey:

// First message — creates thread
const response = await sendCard(webhookUrl, card, {
  threadKey: 'deploy-2026-02-16'
});

// Reply to thread — append &messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD
const threadUrl = `${webhookUrl}&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD`;
await sendCard(threadUrl, replyCard, {
  threadKey: 'deploy-2026-02-16'
});

The threadKey is a client-assigned string. Use consistent keys for related messages (e.g., deploy-{date}, alert-{id}).

Common Patterns

Notification Card

import { buildCard, sendCard } from './assets/card-builder';
import { sendWebhook } from './assets/webhook-sender';

const card = buildCard({
  cardId: 'deploy-notification',
  title: 'Deployment Complete',
  subtitle: 'production - v2.1.0',
  imageUrl: 'https://example.com/your-icon.png',
  sections: [{
    widgets: [
      { decoratedText: { topLabel: 'Environment', text: 'Production' } },
      { decoratedText: { topLabel: 'Version', text: 'v2.1.0' } },
      { decoratedText: { topLabel: 'Status', text: '*Healthy*', startIcon: { knownIcon: 'STAR' } } },
      { buttonList: { buttons: [{ text: 'View Deployment', onClick: { openLink: { url: 'https://dash.example.com' } } }] } }
    ]
  }]
});

Digest Card (Weekly Summary)

const digest = buildCard({
  cardId: 'weekly-digest',
  title: 'Weekly Summary',
  subtitle: `${count} updates this week`,
  sections: [
    {
      header: 'Highlights',
      widgets: items.map(item => ({
        decoratedText: { text: item.title, bottomLabel: item.date }
      }))
    },
    {
      widgets: [{
        buttonList: {
          buttons: [{ text: 'View All', onClick: { openLink: { url: dashboardUrl } } }]
        }
      }]
    }
  ]
});

Simple Text Alert

await sendText(webhookUrl, `*Alert*: CPU usage above 90% on \`worker-prod-1\`\n<${alertUrl}|View Alert>`);

Error Prevention

MistakeFix
**bold** in textUse *bold* (single asterisks)
[text](url) linksUse <url|text> format
Missing cardsV2 wrapperWrap card in { cardsV2: [{ cardId, card }] }
Thread replies not threadingAppend &messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD to webhook URL
Webhook returns 400Check JSON structure — common issue is missing text or cardsV2 at top level
Card not showingEnsure sections has at least one widget

Asset Files

FilePurpose
assets/types.tsTypeScript type definitions for cardsV2
assets/card-builder.tsUtility to build card messages
assets/webhook-sender.tsPOST to webhook with error handling