google-chat-messages

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Google Chat Messages

Google Chat 消息发送

Send messages to Google Chat spaces via incoming webhooks. Produces text messages, rich cards (cardsV2), and threaded replies.
通过传入webhook向Google Chat空间发送消息。支持生成文本消息、富卡片(cardsV2)和线程回复。

What You Produce

可生成的内容

  • Text messages with Google Chat formatting
  • Rich card messages (cardsV2) with headers, sections, widgets
  • Threaded conversations
  • Reusable webhook sender utility
  • 带Google Chat格式的文本消息
  • 包含标题、章节、组件的富卡片消息(cardsV2)
  • 线程对话
  • 可复用的webhook发送工具

Workflow

操作流程

Step 1: Get Webhook URL

步骤1:获取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 a secret (environment variable or Bitwarden), never hardcode.
在Google Chat中:
  1. 打开一个空间 > 点击空间名称 > 管理webhook
  2. 创建webhook(设置名称,可选择性添加头像URL)
  3. 复制webhook URL
将URL存储为机密信息(环境变量或Bitwarden),切勿硬编码。

Step 2: Choose Message Type

步骤2:选择消息类型

NeedTypeComplexity
Simple notificationText messageLow
Structured info (status, digest)Card message (cardsV2)Medium
Ongoing updatesThreaded repliesMedium
Action buttons (open URL)Card with buttonListMedium
需求类型复杂度
简单通知文本消息
结构化信息(状态、摘要)卡片消息(cardsV2)
持续更新内容线程回复
操作按钮(打开URL)带buttonList的卡片

Step 3: Send the Message

步骤3:发送消息

Use
assets/webhook-sender.ts
for the sender utility. Use
assets/card-builder.ts
for structured card construction.
使用
assets/webhook-sender.ts
作为发送工具。使用
assets/card-builder.ts
构建结构化卡片。

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.
Google Chat 不使用标准Markdown语法。
格式语法示例
粗体
*text*
*important*
斜体
_text_
_emphasis_
删除线
~text~
~removed~
等宽文本
`text`
`code`
代码块
```text```
多行代码
链接
<url|text>
<https://example.com|Click here>
提及用户
<users/USER_ID>
<users/123456>
提及所有人
<users/all>
<users/all>
不支持
**双星号**
、标题(
###
)、块引用、表格、行内图片。

Text Message Example

文本消息示例

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

cardsV2 Structure

cardsV2 结构

Cards use the cardsV2 format (recommended over legacy cards).
typescript
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
        ]
      }]
    }
  }]
};
卡片使用cardsV2格式(推荐替代旧版卡片)。
typescript
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:
typescript
{ textParagraph: { text: '*Bold* and _italic_ text' } }
Decorated text — label + value with optional icon:
typescript
{
  decoratedText: {
    topLabel: 'Status',
    text: 'Deployed',
    startIcon: { knownIcon: 'STAR' }
  }
}
Button list — action buttons:
typescript
{
  buttonList: {
    buttons: [{
      text: 'View Dashboard',
      onClick: { openLink: { url: 'https://dashboard.example.com' } }
    }]
  }
}
Image — standalone image:
typescript
{ image: { imageUrl: 'https://example.com/chart.png', altText: 'Usage chart' } }
Divider — horizontal separator:
typescript
{ divider: {} }
See
references/widget-reference.md
for all widget types with full examples. See
references/icon-list.md
for all available knownIcon values.
文本段落 —— 格式化文本块:
typescript
{ textParagraph: { text: '*Bold* and _italic_ text' } }
装饰文本 —— 标签+值,可带图标:
typescript
{
  decoratedText: {
    topLabel: 'Status',
    text: 'Deployed',
    startIcon: { knownIcon: 'STAR' }
  }
}
按钮列表 —— 操作按钮:
typescript
{
  buttonList: {
    buttons: [{
      text: 'View Dashboard',
      onClick: { openLink: { url: 'https://dashboard.example.com' } }
    }]
  }
}
图片 —— 独立图片:
typescript
{ image: { imageUrl: 'https://example.com/chart.png', altText: 'Usage chart' } }
分隔线 —— 水平分隔符:
typescript
{ divider: {} }
查看
references/widget-reference.md
获取所有组件类型及完整示例。 查看
references/icon-list.md
获取所有可用的knownIcon值。

Threading

线程回复

Thread messages together using
threadKey
:
typescript
// 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}
).
使用
threadKey
将消息关联到同一线程:
typescript
// 第一条消息 —— 创建线程
const response = await sendCard(webhookUrl, card, {
  threadKey: 'deploy-2026-02-16'
});

// 回复线程 —— 追加&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'
});
threadKey
是客户端指定的字符串。对相关消息使用一致的键(例如
deploy-{date}
alert-{id}
)。

Common Patterns

常见模式

Notification Card

通知卡片

typescript
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://www.jezweb.com.au/wp-content/uploads/2020/03/favicon-100x100.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' } } }] } }
    ]
  }]
});
typescript
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://www.jezweb.com.au/wp-content/uploads/2020/03/favicon-100x100.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)

摘要卡片(每周汇总)

typescript
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 } } }]
        }
      }]
    }
  ]
});
typescript
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

简单文本警报

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

Error Prevention

错误预防

MistakeFix
**bold**
in text
Use
*bold*
(single asterisks)
[text](url)
links
Use
<url|text>
format
Missing
cardsV2
wrapper
Wrap 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
错误修复方案
文本中使用
**bold**
使用
*bold*
(单个星号)
使用
[text](url)
格式链接
使用
<url|text>
格式
缺少
cardsV2
包裹
将卡片包裹在
{ cardsV2: [{ cardId, card }] }
线程回复未关联到线程在webhook URL后追加
&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD
Webhook返回400错误检查JSON结构——常见问题是顶层缺少
text
cardsV2
卡片未显示确保
sections
中至少包含一个组件

Asset Files

资源文件

FilePurpose
assets/types.ts
TypeScript type definitions for cardsV2
assets/card-builder.ts
Utility to build card messages
assets/webhook-sender.ts
POST to webhook with error handling
文件用途
assets/types.ts
cardsV2的TypeScript类型定义
assets/card-builder.ts
用于构建卡片消息的工具
assets/webhook-sender.ts
向webhook发送POST请求并处理错误