Agent skill
google-chat-messages
Send Google Chat messages via webhook — text, rich cards (cardsV2), threaded replies. Includes TypeScript types, card builder utility, and widget reference.
Install this agent skill to your Project
npx add-skill https://github.com/jezweb/claude-skills/tree/main/plugins/integrations/skills/google-chat-messages
SKILL.md
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:
- Open a Space > click space name > Manage webhooks
- Create webhook (name it, optionally add avatar URL)
- Copy the webhook URL
Store the URL as an environment variable or in your secrets manager — never hardcode.
Step 2: Choose Message Type
| Need | Type | Complexity |
|---|---|---|
| Simple notification | Text message | Low |
| Structured info (status, digest) | Card message (cardsV2) | Medium |
| Ongoing updates | Threaded replies | Medium |
| Action buttons (open URL) | Card with buttonList | Medium |
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.
| Format | Syntax | Example |
|---|---|---|
| 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 Reference
All widget types available in cardsV2 sections.
textParagraph
Formatted text block. Supports Google Chat formatting (*bold*, _italic_, <url|text>).
{
textParagraph: {
text: '*Status*: All systems operational\n_Last checked_: 5 minutes ago'
}
}
decoratedText
Labelled value with optional icons. Most versatile widget for key-value data.
Basic:
{
decoratedText: {
topLabel: 'Environment',
text: 'Production',
bottomLabel: 'Last deployed 2h ago'
}
}
With start icon:
{
decoratedText: {
topLabel: 'Status',
text: 'Healthy',
startIcon: { knownIcon: 'STAR' }
}
}
With custom icon URL:
{
decoratedText: {
topLabel: 'GitHub',
text: 'PR #142 merged',
startIcon: {
iconUrl: 'https://github.githubassets.com/favicons/favicon.svg',
altText: 'GitHub'
}
}
}
With button:
{
decoratedText: {
topLabel: 'Alert',
text: 'CPU at 95%',
button: {
text: 'View',
onClick: { openLink: { url: 'https://monitoring.example.com' } }
}
}
}
Clickable (whole widget):
{
decoratedText: {
text: 'View full report',
wrapText: true,
onClick: { openLink: { url: 'https://reports.example.com' } }
}
}
With wrap text:
{
decoratedText: {
topLabel: 'Description',
text: 'This is a longer description that should wrap to multiple lines instead of being truncated',
wrapText: true
}
}
buttonList
One or more action buttons. Buttons open URLs or trigger actions.
Single button:
{
buttonList: {
buttons: [{
text: 'Open Dashboard',
onClick: { openLink: { url: 'https://dashboard.example.com' } }
}]
}
}
Multiple buttons:
{
buttonList: {
buttons: [
{
text: 'Approve',
onClick: { openLink: { url: 'https://app.example.com/approve/123' } },
color: { red: 0, green: 0.5, blue: 0, alpha: 1 }
},
{
text: 'Reject',
onClick: { openLink: { url: 'https://app.example.com/reject/123' } }
}
]
}
}
Button with icon:
{
buttonList: {
buttons: [{
text: 'View on GitHub',
icon: { knownIcon: 'BOOKMARK' },
onClick: { openLink: { url: 'https://github.com/org/repo/pull/42' } }
}]
}
}
image
Standalone image widget.
{
image: {
imageUrl: 'https://example.com/chart.png',
altText: 'Monthly usage chart'
}
}
divider
Horizontal line separator between widgets.
{ divider: {} }
Collapsible Sections
Sections can be collapsed with only the first N widgets visible:
{
header: 'Details',
collapsible: true,
uncollapsibleWidgetsCount: 2, // Show first 2, collapse rest
widgets: [
{ decoratedText: { topLabel: 'Status', text: 'Active' } },
{ decoratedText: { topLabel: 'Region', text: 'AU' } },
// These start collapsed
{ decoratedText: { topLabel: 'Instance', text: 'prod-01' } },
{ decoratedText: { topLabel: 'Memory', text: '2.1 GB' } },
{ decoratedText: { topLabel: 'CPU', text: '45%' } }
]
}
Known Icons
Icons available via knownIcon in decoratedText and button widgets.
{ startIcon: { knownIcon: 'STAR' } }
// or
{ icon: { knownIcon: 'EMAIL' } }
| Icon Name | Use For |
|---|---|
AIRPLANE |
Travel, flights |
BOOKMARK |
Save, reference, links |
BUS |
Transport, transit |
CAR |
Driving, transport |
CLOCK |
Time, duration, schedule |
CONFIRMATION_NUMBER_ICON |
Tickets, bookings |
DESCRIPTION |
Documents, files |
DOLLAR |
Money, pricing, cost |
EMAIL |
Email, messages |
INVITE |
Invitations |
MAP_PIN |
Location, address |
MEMBERSHIP |
Members, users |
MULTIPLE_PEOPLE |
Teams, groups |
OFFER |
Deals, promotions |
PERSON |
Individual user |
PHONE |
Phone number, calls |
SHOPPING_CART |
Commerce, purchases |
STAR |
Rating, favourite, important |
STORE |
Shop, retail |
TICKET |
Tickets, events |
VIDEO_CAMERA |
Video, meetings |
For icons not in the list, use iconUrl with any publicly accessible image (square, ideally 24x24 or 48x48 pixels).
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 } } }]
}
}]
}
]
});
Error Prevention
| Mistake | Fix |
|---|---|
**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 threading | Append &messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD to webhook URL |
| Webhook returns 400 | Check JSON structure — common issue is missing text or cardsV2 at top level |
| Card not showing | Ensure sections has at least one widget |
Asset Files
| File | Purpose |
|---|---|
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 |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
shadcn-ui
Install and configure shadcn/ui components for React projects. Guides component selection, installation order, dependency management, customisation with semantic tokens, and common UI recipes (forms, data tables, navigation, modals). Use after tailwind-theme-builder has set up the theme infrastructure, when adding components, building forms, creating data tables, or setting up navigation.
walkthrough-video
Generate professional walkthrough videos from app screenshots or live sites using Remotion. Smooth transitions, zoom effects, text overlays, and optional voiceover narration. Produces MP4 videos for demos, product showcases, or documentation. Triggers: 'walkthrough video', 'demo video', 'product video', 'create a video walkthrough', 'remotion video', 'screen recording', 'app demo', 'showcase video', 'generate video from screenshots'.
product-showcase
Generate a comprehensive marketing website for a web app — multi-page with real screenshots, animated GIF walkthroughs, feature deep-dives, and workflow demonstrations. Browses the running app, captures screens and sequences, and produces a deployable site that actually teaches people what the product does. Especially useful for complex or agentic apps that are hard to explain. Triggers: 'showcase site', 'product page', 'show off the app', 'marketing site', 'demo site', 'product showcase', 'explain the app', 'how do I market this'.
design-system
Extract a complete design system from an existing website or screenshot into a DESIGN.md file. Analyses colours, typography, component styles, spacing, and atmosphere through browser automation and HTML inspection. Produces a semantic design system document optimised for consistent page generation. Triggers: 'extract design system', 'design system', 'create DESIGN.md', 'analyse the design', 'what design does this site use', 'extract styles from', 'reverse engineer the design'.
react-patterns
React 19 performance patterns and composition architecture for Vite + Cloudflare projects. 50+ rules ranked by impact — eliminating waterfalls, bundle optimisation, re-render prevention, composition over boolean props, server/client boundaries, and React 19 APIs. Use when writing, reviewing, or refactoring React components. Triggers: 'react patterns', 'react review', 'react performance', 'optimise components', 'react best practices', 'composition patterns', 'why is it slow', 'reduce re-renders', 'fix waterfall'.
react-native
React Native and Expo patterns for building performant mobile apps. Covers list performance, animations with Reanimated, navigation, UI patterns, state management, platform-specific code, and Expo workflows. Use when building or reviewing React Native code. Triggers: 'react native', 'expo', 'mobile app', 'react native performance', 'flatlist', 'reanimated', 'expo router', 'mobile development', 'ios app', 'android app'.
Didn't find tool you were looking for?