Google Chat
Communication Tool
Google Chat
Overview
Google Chat is a team collaboration platform integrated with Google Workspace. It provides a unified workflow experience through seamless integration with Gmail, Google Drive, and Google Calendar. With Chat API, Webhook support, and Apps Script integration, it offers rich automation capabilities and bot development, providing advanced security features for enterprises.
Details
Google Chat is a business communication platform launched as part of Google Workspace in 2017. Evolved from Google Hangouts Chat, it is now widely adopted by enterprises worldwide. It's particularly notable for its high integration within the Google Workspace ecosystem, providing a unified collaboration experience through connectivity with Gmail, Google Drive, and Google Meet.
In 2024-2025, significant feature enhancements were implemented including Quick Commands functionality, Accessory Widgets, private messaging, Card Builder tool, Dialogflow CX integration, and Space Events (Developer Preview). Additionally, integration with Google Apps Script has been further improved, with development using the Advanced Chat service now being recommended.
Google Chat API provides comprehensive bot development capabilities, including Webhook integration, Apps Script integration, custom emoji management, notification settings API, and app-level authentication scopes, enabling advanced enterprise-grade features. Deep integration with Google Cloud Platform allows for building scalable and secure chat applications.
Pros and Cons
Pros
- Complete Google Workspace Integration: Seamless connectivity with Gmail, Drive, Calendar, Meet
- Rich API Features: Chat API, Advanced Chat service, Space Events API
- Apps Script Integration: No-code and low-code development support
- Powerful Webhook Features: Asynchronous messaging, external system integration
- Enterprise Security: Google Workspace-level security
- Card Builder: Visual design for interactive cards
- Dialogflow CX Integration: Advanced bots with natural language processing
- Free Workspace Integration: Basic features available for free
Cons
- Google Dependency: Strong dependency on Google Workspace ecosystem
- Customization Limitations: UI/UX customization scope constraints
- Learning Curve: Requires Google Cloud Platform knowledge
- Third-party Service Integration: Complexity in integrating non-Google services
- Feature Restrictions: Some limitations in free version
- Rate Limits: API call restrictions during large-scale usage
Key Links
- Google Chat Official Site
- Google Chat Developer Platform
- Chat API Reference
- Chat Development with Apps Script
- Webhook Guide
- Google Workspace
- Card Builder Tool
Code Examples
Google Chat App with Apps Script
// Google Chat App implementation with Apps Script
function onMessage(event) {
// Handle message events
const message = event.message;
const user = event.user;
const space = event.space;
console.log(`Message received: ${message.text} from ${user.displayName} in ${space.displayName}`);
// Basic echo response
if (message.text) {
return createTextResponse(`Echo: ${message.text}`);
}
// Handle mentions
if (message.argumentText) {
return handleCommand(message.argumentText, user, space);
}
return createTextResponse('Hello! How can I help you?');
}
// Create card response
function createCardResponse(title, description, buttonText, buttonAction) {
return {
cards: [{
header: {
title: title,
subtitle: 'Powered by Apps Script'
},
sections: [{
widgets: [{
textParagraph: {
text: description
}
}, {
buttons: [{
textButton: {
text: buttonText,
onClick: {
action: {
actionMethodName: buttonAction
}
}
}
}]
}]
}]
}]
};
}
// Command processing
function handleCommand(command, user, space) {
const [action, ...args] = command.split(' ');
switch (action.toLowerCase()) {
case 'help':
return createHelpCard();
case 'weather':
return getWeatherInfo(args[0] || 'Tokyo');
case 'schedule':
return getCalendarEvents(user);
case 'create':
return createTask(args.join(' '), user);
default:
return createTextResponse(`Unknown command: ${action}. Type 'help' for assistance.`);
}
}
// Create help card
function createHelpCard() {
return {
cards: [{
header: {
title: '🤖 Bot Commands',
subtitle: 'Available commands'
},
sections: [{
widgets: [{
keyValue: {
topLabel: 'Weather',
content: '@bot weather [city] - Get weather information',
icon: 'DESCRIPTION'
}
}, {
keyValue: {
topLabel: 'Schedule',
content: '@bot schedule - Show today\'s schedule',
icon: 'CLOCK'
}
}, {
keyValue: {
topLabel: 'Task',
content: '@bot create [task] - Create a new task',
icon: 'BOOKMARK'
}
}]
}]
}]
};
}
// Weather information retrieval
function getWeatherInfo(city) {
try {
const apiKey = PropertiesService.getScriptProperties().getProperty('WEATHER_API_KEY');
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric&lang=en`;
const response = UrlFetchApp.fetch(url);
const data = JSON.parse(response.getContentText());
if (data.cod === 200) {
return {
cards: [{
header: {
title: `🌤️ Weather in ${data.name}`,
subtitle: 'Current weather information'
},
sections: [{
widgets: [{
keyValue: {
topLabel: 'Weather',
content: data.weather[0].description,
icon: 'DESCRIPTION'
}
}, {
keyValue: {
topLabel: 'Temperature',
content: `${data.main.temp}°C`,
icon: 'CLOCK'
}
}, {
keyValue: {
topLabel: 'Humidity',
content: `${data.main.humidity}%`,
icon: 'DESCRIPTION'
}
}]
}]
}]
};
}
} catch (error) {
console.error('Weather API error:', error);
}
return createTextResponse('❌ Failed to retrieve weather information');
}
// Google Calendar integration
function getCalendarEvents(user) {
try {
const calendar = CalendarApp.getDefaultCalendar();
const today = new Date();
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
const events = calendar.getEvents(today, tomorrow);
if (events.length === 0) {
return createTextResponse('📅 No events scheduled for today');
}
const widgets = events.slice(0, 5).map(event => ({
keyValue: {
topLabel: event.getStartTime().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }),
content: event.getTitle(),
icon: 'CLOCK'
}
}));
return {
cards: [{
header: {
title: '📅 Today\'s Schedule',
subtitle: `${events.length} events`
},
sections: [{ widgets }]
}]
};
} catch (error) {
console.error('Calendar API error:', error);
return createTextResponse('❌ Failed to retrieve calendar information');
}
}
// Google Sheets integration for task management
function createTask(taskDescription, user) {
try {
const spreadsheetId = PropertiesService.getScriptProperties().getProperty('TASK_SHEET_ID');
const sheet = SpreadsheetApp.openById(spreadsheetId).getActiveSheet();
const timestamp = new Date();
const taskId = Utilities.getUuid();
sheet.appendRow([taskId, taskDescription, user.displayName, timestamp, 'Open']);
return {
cards: [{
header: {
title: '✅ Task Created',
subtitle: 'New task created successfully'
},
sections: [{
widgets: [{
keyValue: {
topLabel: 'Task ID',
content: taskId,
icon: 'BOOKMARK'
}
}, {
keyValue: {
topLabel: 'Description',
content: taskDescription,
icon: 'DESCRIPTION'
}
}, {
keyValue: {
topLabel: 'Created by',
content: user.displayName,
icon: 'PERSON'
}
}]
}]
}]
};
} catch (error) {
console.error('Task creation error:', error);
return createTextResponse('❌ Failed to create task');
}
}
// Button action handling
function onCardClick(event) {
const action = event.action.actionMethodName;
const parameters = event.action.parameters;
switch (action) {
case 'markComplete':
return markTaskComplete(parameters[0].value);
case 'deleteTask':
return deleteTask(parameters[0].value);
case 'assignTask':
return assignTask(parameters[0].value, event.user);
default:
return createTextResponse('Unknown action');
}
}
// Text response helper
function createTextResponse(text) {
return { text: text };
}
Google Chat Webhook Integration
// Webhook implementation with Node.js
const express = require('express');
const { IncomingWebhook } = require('@google-cloud/chat');
const app = express();
app.use(express.json());
// Webhook URL configuration
const WEBHOOK_URL = process.env.GOOGLE_CHAT_WEBHOOK_URL;
class GoogleChatNotifier {
constructor(webhookUrl) {
this.webhookUrl = webhookUrl;
}
// Send basic message
async sendMessage(text) {
try {
const response = await fetch(this.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ text })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Webhook send error:', error);
throw error;
}
}
// Send card format message
async sendCard(title, subtitle, widgets) {
const message = {
cards: [{
header: {
title: title,
subtitle: subtitle
},
sections: [{ widgets }]
}]
};
try {
const response = await fetch(this.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(message)
});
return await response.json();
} catch (error) {
console.error('Card send error:', error);
throw error;
}
}
// GitHub event notification
async sendGitHubNotification(eventType, payload) {
switch (eventType) {
case 'push':
return this.handlePushEvent(payload);
case 'pull_request':
return this.handlePullRequestEvent(payload);
case 'issues':
return this.handleIssueEvent(payload);
default:
return this.sendMessage(`🔄 Unknown GitHub event: ${eventType}`);
}
}
async handlePushEvent(payload) {
const { commits, repository, pusher } = payload;
const commitsList = commits.slice(0, 3).map(commit =>
`• [${commit.id.substring(0, 7)}](${commit.url}) ${commit.message}`
).join('\n');
const widgets = [
{
keyValue: {
topLabel: 'Repository',
content: repository.full_name,
contentMultiline: false,
icon: 'BOOKMARK'
}
},
{
keyValue: {
topLabel: 'Pusher',
content: pusher.name,
icon: 'PERSON'
}
},
{
keyValue: {
topLabel: 'Commits',
content: `${commits.length} commits`,
icon: 'DESCRIPTION'
}
},
{
textParagraph: {
text: `<b>Recent commits:</b>\n${commitsList}`
}
},
{
buttons: [{
textButton: {
text: 'View Changes',
onClick: {
openLink: {
url: payload.compare
}
}
}
}]
}
];
return this.sendCard('🚀 Push Event', repository.full_name, widgets);
}
async handlePullRequestEvent(payload) {
const { pull_request: pr, action } = payload;
const emoji = {
opened: '📝',
closed: pr.merged ? '🎉' : '❌',
reopened: '🔄'
};
const widgets = [
{
keyValue: {
topLabel: 'Action',
content: action,
icon: 'DESCRIPTION'
}
},
{
keyValue: {
topLabel: 'Author',
content: pr.user.login,
icon: 'PERSON'
}
},
{
keyValue: {
topLabel: 'Branch',
content: `${pr.head.ref} → ${pr.base.ref}`,
icon: 'BOOKMARK'
}
},
{
textParagraph: {
text: pr.body || 'No description provided'
}
},
{
buttons: [{
textButton: {
text: 'View PR',
onClick: {
openLink: {
url: pr.html_url
}
}
}
}]
}
];
return this.sendCard(
`${emoji[action]} Pull Request ${action}`,
`#${pr.number} - ${pr.title}`,
widgets
);
}
// CI/CD pipeline notification
async sendDeploymentNotification(status, environment, service, version) {
const emoji = status === 'success' ? '✅' : '❌';
const color = status === 'success' ? '#28a745' : '#d73a49';
const widgets = [
{
keyValue: {
topLabel: 'Status',
content: status.toUpperCase(),
icon: status === 'success' ? 'STAR' : 'DESCRIPTION'
}
},
{
keyValue: {
topLabel: 'Environment',
content: environment,
icon: 'BOOKMARK'
}
},
{
keyValue: {
topLabel: 'Service',
content: service,
icon: 'DESCRIPTION'
}
},
{
keyValue: {
topLabel: 'Version',
content: version,
icon: 'CLOCK'
}
}
];
return this.sendCard(
`${emoji} Deployment ${status}`,
`${service} to ${environment}`,
widgets
);
}
// Alert notification
async sendAlert(severity, message, details) {
const emoji = {
'critical': '🚨',
'warning': '⚠️',
'info': 'ℹ️'
};
const widgets = [
{
keyValue: {
topLabel: 'Severity',
content: severity.toUpperCase(),
icon: 'DESCRIPTION'
}
},
{
keyValue: {
topLabel: 'Timestamp',
content: new Date().toLocaleString('en-US'),
icon: 'CLOCK'
}
},
{
textParagraph: {
text: `<b>Details:</b>\n${details}`
}
}
];
return this.sendCard(
`${emoji[severity]} Alert: ${message}`,
'System Notification',
widgets
);
}
}
// Express server usage example
const notifier = new GoogleChatNotifier(WEBHOOK_URL);
// GitHub Webhook endpoint
app.post('/github-webhook', async (req, res) => {
const eventType = req.headers['x-github-event'];
const payload = req.body;
try {
await notifier.sendGitHubNotification(eventType, payload);
res.status(200).send('OK');
} catch (error) {
console.error('GitHub webhook processing error:', error);
res.status(500).send('Error');
}
});
// CI/CD notification endpoint
app.post('/deployment-notification', async (req, res) => {
const { status, environment, service, version } = req.body;
try {
await notifier.sendDeploymentNotification(status, environment, service, version);
res.status(200).send('OK');
} catch (error) {
console.error('Deployment notification error:', error);
res.status(500).send('Error');
}
});
// System alert endpoint
app.post('/alert', async (req, res) => {
const { severity, message, details } = req.body;
try {
await notifier.sendAlert(severity, message, details);
res.status(200).send('OK');
} catch (error) {
console.error('Alert send error:', error);
res.status(500).send('Error');
}
});
app.listen(3000, () => {
console.log('Google Chat notification server running on port 3000');
});
Bot Development with Chat API
// Chat API Bot implementation with Node.js
const { GoogleAuth } = require('google-auth-library');
const { google } = require('googleapis');
class GoogleChatBot {
constructor(credentials) {
this.auth = new GoogleAuth({
credentials: credentials,
scopes: ['https://www.googleapis.com/auth/chat.bot']
});
this.chat = google.chat({ version: 'v1', auth: this.auth });
}
// Send message
async sendMessage(spaceName, text, threadKey = null) {
try {
const request = {
parent: spaceName,
requestBody: {
text: text,
thread: threadKey ? { name: threadKey } : undefined
}
};
const response = await this.chat.spaces.messages.create(request);
return response.data;
} catch (error) {
console.error('Message send error:', error);
throw error;
}
}
// Send card message
async sendCardMessage(spaceName, cards, threadKey = null) {
try {
const request = {
parent: spaceName,
requestBody: {
cards: cards,
thread: threadKey ? { name: threadKey } : undefined
}
};
const response = await this.chat.spaces.messages.create(request);
return response.data;
} catch (error) {
console.error('Card message send error:', error);
throw error;
}
}
// List spaces
async listSpaces() {
try {
const response = await this.chat.spaces.list();
return response.data.spaces || [];
} catch (error) {
console.error('Space list retrieval error:', error);
throw error;
}
}
// Get message history
async getMessages(spaceName, pageSize = 100) {
try {
const response = await this.chat.spaces.messages.list({
parent: spaceName,
pageSize: pageSize
});
return response.data.messages || [];
} catch (error) {
console.error('Message history retrieval error:', error);
throw error;
}
}
// Get members list
async getMembers(spaceName) {
try {
const response = await this.chat.spaces.members.list({
parent: spaceName
});
return response.data.memberships || [];
} catch (error) {
console.error('Members list retrieval error:', error);
throw error;
}
}
// Create interactive card
createTaskCard(taskId, title, description, assignee) {
return [{
header: {
title: '📋 Task Management',
subtitle: 'Task Management System'
},
sections: [{
widgets: [
{
keyValue: {
topLabel: 'Task ID',
content: taskId,
icon: 'BOOKMARK'
}
},
{
keyValue: {
topLabel: 'Title',
content: title,
icon: 'DESCRIPTION'
}
},
{
textParagraph: {
text: `<b>Description:</b>\n${description}`
}
},
{
keyValue: {
topLabel: 'Assignee',
content: assignee,
icon: 'PERSON'
}
},
{
buttons: [
{
textButton: {
text: '✅ Complete',
onClick: {
action: {
actionMethodName: 'completeTask',
parameters: [{ key: 'taskId', value: taskId }]
}
}
}
},
{
textButton: {
text: '✏️ Edit',
onClick: {
action: {
actionMethodName: 'editTask',
parameters: [{ key: 'taskId', value: taskId }]
}
}
}
}
]
}
]
}]
}];
}
// Project management card
createProjectCard(projectName, progress, milestones) {
const progressBar = '█'.repeat(Math.floor(progress / 10)) +
'░'.repeat(10 - Math.floor(progress / 10));
const milestoneWidgets = milestones.map(milestone => ({
keyValue: {
topLabel: milestone.name,
content: milestone.completed ? '✅ Complete' : '⏳ In Progress',
icon: milestone.completed ? 'STAR' : 'CLOCK'
}
}));
return [{
header: {
title: `🚀 ${projectName}`,
subtitle: 'Project Status'
},
sections: [{
widgets: [
{
keyValue: {
topLabel: 'Progress',
content: `${progress}% ${progressBar}`,
icon: 'DESCRIPTION'
}
},
...milestoneWidgets
]
}]
}];
}
// Generate report
async generateDailyReport(spaceName) {
try {
const now = new Date();
const reportData = await this.fetchReportData(); // Fetch data from external systems
const widgets = [
{
keyValue: {
topLabel: 'Total Tasks',
content: reportData.totalTasks.toString(),
icon: 'BOOKMARK'
}
},
{
keyValue: {
topLabel: 'Completed',
content: reportData.completedTasks.toString(),
icon: 'STAR'
}
},
{
keyValue: {
topLabel: 'In Progress',
content: reportData.inProgressTasks.toString(),
icon: 'CLOCK'
}
},
{
textParagraph: {
text: `<b>Top Contributors:</b>\n${reportData.topContributors.join('\n')}`
}
}
];
const cards = [{
header: {
title: '📊 Daily Report',
subtitle: now.toLocaleDateString('en-US')
},
sections: [{ widgets }]
}];
return this.sendCardMessage(spaceName, cards);
} catch (error) {
console.error('Daily report generation error:', error);
throw error;
}
}
// Fetch external system data (example)
async fetchReportData() {
// In actual implementation, fetch data from external APIs, databases, etc.
return {
totalTasks: 45,
completedTasks: 32,
inProgressTasks: 13,
topContributors: [
'👑 John Smith (8 tasks)',
'🥈 Jane Doe (6 tasks)',
'🥉 Bob Johnson (5 tasks)'
]
};
}
}
// Usage example
async function main() {
const credentials = {
type: 'service_account',
project_id: process.env.GOOGLE_CLOUD_PROJECT_ID,
private_key_id: process.env.GOOGLE_PRIVATE_KEY_ID,
private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n'),
client_email: process.env.GOOGLE_CLIENT_EMAIL,
client_id: process.env.GOOGLE_CLIENT_ID,
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://oauth2.googleapis.com/token'
};
const bot = new GoogleChatBot(credentials);
// Send daily report
const spaceName = 'spaces/AAAAGCEIgKY'; // Replace with actual space name
try {
await bot.generateDailyReport(spaceName);
console.log('Daily report sent successfully');
} catch (error) {
console.error('Error:', error);
}
}
// Scheduled execution (daily at 9 AM)
const cron = require('node-cron');
cron.schedule('0 9 * * *', () => {
main().catch(console.error);
});
Environment Variables Configuration
# .env file
# Google Apps Script settings
SCRIPT_ID=your-apps-script-project-id
WEATHER_API_KEY=your-openweather-api-key
TASK_SHEET_ID=your-google-sheet-id
# Google Chat Webhook
GOOGLE_CHAT_WEBHOOK_URL=https://chat.googleapis.com/v1/spaces/xxx/messages?key=xxx
# Chat API credentials
GOOGLE_CLOUD_PROJECT_ID=your-project-id
GOOGLE_PRIVATE_KEY_ID=your-private-key-id
GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nxxxx\n-----END PRIVATE KEY-----\n"
GOOGLE_CLIENT_EMAIL=your-service-account@your-project.iam.gserviceaccount.com
GOOGLE_CLIENT_ID=your-client-id
# External API integration
JIRA_API_TOKEN=your-jira-api-token
GITHUB_TOKEN=your-github-token
SLACK_WEBHOOK_URL=your-slack-webhook-url
# Database (optional)
DATABASE_URL=your-database-connection-string
Docker Configuration Example
# Dockerfile
FROM node:18-alpine
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci --only=production
# Copy application files
COPY . .
# Environment variables
ENV NODE_ENV=production
ENV PORT=3000
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# Start application
CMD ["npm", "start"]
Google Cloud Functions Deployment Example
# cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/npm'
args: ['install']
- name: 'gcr.io/cloud-builders/npm'
args: ['run', 'test']
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'functions'
- 'deploy'
- 'google-chat-bot'
- '--source=.'
- '--trigger-http'
- '--runtime=nodejs18'
- '--entry-point=handleChatEvent'
- '--memory=512MB'
- '--timeout=60s'
- '--set-env-vars=NODE_ENV=production'
- '--allow-unauthenticated'
timeout: '600s'
Card UI Design Guide
// UI design using Card Builder Tool
function createAdvancedCard() {
return {
cardsV2: [{
cardId: 'unique-card-id',
card: {
header: {
title: '📋 Advanced Task Manager',
subtitle: 'Powered by Google Chat API',
imageUrl: 'https://developers.google.com/chat/images/logo.png',
imageType: 'CIRCLE'
},
sections: [
{
header: 'Quick Actions',
widgets: [
{
buttonList: {
buttons: [
{
text: '➕ Create Task',
onClick: {
action: {
function: 'createTaskDialog'
}
}
},
{
text: '📊 View Report',
onClick: {
action: {
function: 'generateReport'
}
}
}
]
}
}
]
},
{
header: 'Recent Tasks',
collapsible: true,
widgets: [
{
decoratedText: {
text: '✅ Task 1 completed successfully',
startIcon: {
knownIcon: 'STAR'
},
button: {
text: 'View',
onClick: {
openLink: {
url: 'https://example.com/task/1'
}
}
}
}
}
]
}
]
}
}]
};
}