When your bot sends a card
message to Google Chat, the
space (chat room or direct message) displays a card. The card can contain
various UI elements, and you can attach onClick
events to these elements to
make a card interactive.
Included in the onClick
event is a specification of what should happen when the
card element receives a click:
openLink
lets you specify a URL to display.action
lets you pass app-specific information back to the bot implementation to implement arbitrary behavior. This behavior can include updating cards that are already displayed in the chat, as shown in the above example.
The following paragraphs introduce the main concepts of interactive cards.
Click to open URL
Opening a URL is simple: the card message simply defines the URL that should be opened when the click occurs:
"textButton": {
"text": "VISIT WEBSITE",
"onClick": {
"openLink": { "url": "http://site.com" }
}
}
After sending the card message, the bot has no further involvement; Google Chat takes care of opening the specified URL when the click occurs.
Click to perform app action
If you want your bot to do something when a click occurs, use the action
object to define information that will be sent back to the bot.
"textButton": {
"text": "Click Me",
"onClick": {
"action": { ...action specification... }
}
}
In this case, the specified information is sent to the bot when the click occurs, and the bot can then take appropriate action in response to the click.
Displaying an interactive button
To display an interactive button, a bot sends a card message that includes
an onClick
object with corresponding action as shown in the following example:
"buttons": [
{
"textButton": {
"text": "Click Me",
"onClick": {
"action": {
"actionMethodName": "snooze",
"parameters": [
{
"key": "time",
"value": "1 day"
},
{
"key": "id",
"value": "123456"
}
]
}
}
}
}
]
HTTP and Cloud PubSub bots
Cloud PubSub and HTTP bots must specify action.actionMethodName
to identify
the action. They can also use action.parameters
to pass key/value pairs
containing other arbitrary information back to themselves. These key/value
pairs are optional.
Apps Script bots
Apps Script bots must also specify action.actionMethodName
, and optionally
can use action.parameters
. To support interactive cards, bots must also
define an onCardClick(event)
method to handle user clicks. This method will
receive a callback when the user clicks on the card.
Updating an interactive card
When your bot handles an onClick.action
, in many cases you'll want to update
the card that's already displayed (rather than adding a new message to the
space).
For example, a bug system may post a new bug into a Chat room and have a button at the bottom that says "Assign to me". When the user clicks it, the card updates to say "Bug was assigned to username".
The following paragraphs discuss how your bot receives user click information, and how to respond to it either by injecting a new card or by updating the existing one.
Receiving user click information
When the user clicks an object in the card that has an onClick.action
defined,
Google Chat sends a message to the bot describing the event.
A CARD_CLICKED
event is passed back to the developer with the action payload
that was specified above. Your bot should handle this event
and respond accordingly. You can use action.actionMethodName
and
action.parameters
to add special-case clicks to different buttons for your bot.
{
type:"CARD_CLICKED",
eventTime:"2017-11-14T01:44:58.521823Z",
message:{
name:"spaces/AAAAtZLKDkk/messages/e3fCf-i1PXE.8OGDcWT2HwI",
sender:{
name:"users/118066814328248020034",
displayName:"Test Bot",
avatarUrl:"https://lh6.googleusercontent.com/...",
type:"BOT"
},
createTime:"2017-11-14T01:44:58.521823Z",
space:{
name:"spaces/AAAAtZLKDkk",
type:"ROOM",
displayName:"Testing Room"
},
thread:{
name:"spaces/AAAAtZLKDkk/threads/e3fCf-i1PXE",
retentionSettings:...
}
},
user:{
name:"users/102651148563033885715",
displayName:"Geordi La Forge",
avatarUrl:"https://dev2-lighthouse.sandbox.google.com/...",
type:"HUMAN"
},
space:{
name:"spaces/AAAAtZLKDkk",
type:"ROOM",
displayName:"Testing Room"
},
action:{
actionMethodName:"upvote",
parameters:[
{
"key":"count",
"value":"7"
},
{
"key":"id",
"value":"123456"
}
]
}
}
Responding to clicks with a new or updated message
Bots can respond to a request by updating the original message, or by creating a
new message. They do this by specifying the actionResponse.type
in the JSON
response.
UPDATE_MESSAGE
— Responding with this type updates the original message already shown in the thread.NEW_MESSAGE
— Responding with this type sends a new message in the same thread.
The following code snippet shows both of these response types:
// The bot can respond by updating the message...
{
"actionResponse":{
"type":"UPDATE_MESSAGE"
},
"cards":[
{
"header":{
"title":"Hello World!"
},
"sections": ...
}
]
}
.
.
.
// ...or respond by adding a new message
{
"actionResponse":{
"type":"NEW_MESSAGE"
},
"cards":[
{
"header":{
"title":"Hello World!"
},
"sections": ...
}
]
}
JavaScript example: Vote Bot
Below is an example of an interactive bot that keeps track of a vote count. When the user clicks "Upvote", the bot updates the vote count on the original card. When the user clicks "New Vote", the bot posts a new card.
/**
* Google Cloud Function that responds to events sent from a
* Google Chat room.
*
* @param {Object} req Request sent from Google Chat room
* @param {Object} res Response to send back
*/
exports.processEvent = function processEvent(req, res) {
var message;
if (req.body.type == "ADDED_TO_SPACE" || req.body.type == "MESSAGE") {
// Start a new vote when this bot is added or mentioned.
message = createMessage("nobody", 0, false);
}
if (req.body.type == "CARD_CLICKED") {
// Update the card in place when the "UPVOTE" button is clicked.
if (req.body.action.actionMethodName == "upvote") {
var count = parseInt(req.body.action.parameters[0].value);
message = createMessage(req.body.user.displayName, count + 1, true);
}
// Create a new vote when the "NEW VOTE" button is clicked.
if (req.body.action.actionMethodName == "newvote") {
message = createMessage(req.body.user.displayName, 0, false);
}
}
res.send(message);
};
/**
* Creates a card encouraging users to vote.
* @param voter The last person to vote.
* @param count The current vote count.
* @param update Whether to update the existing message or post a new message.
*/
function createMessage(voter, count, update) {
return {
"actionResponse": { "type": update ? "UPDATE_MESSAGE" : "NEW_MESSAGE" },
"cards": [{
"header": { "title": `Last vote by ${voter}!` },
"sections": [{
"widgets": [{
"textParagraph": { "text": `${count} votes!` }
}, {
"image": { "imageUrl": IMAGES[count % IMAGES.length] }
}, {
"buttons": [{
"textButton": {
"text": "UPVOTE",
"onClick": {
"action": {
"actionMethodName": "upvote",
"parameters": [
{
"key": "count",
"value": `${count}`
}
]
}
}
}
}, {
"textButton": {
"text": "NEW VOTE",
"onClick": {
"action": {
"actionMethodName": "newvote"
}
}
}
}]
}]
}]
}]
};
}
IMAGES = [
"https://media2.giphy.com/media/3oEjHK3aw2LcB1V3QQ/giphy.gif",
"https://media3.giphy.com/media/l0HlUIHlH4AKadXzy/giphy.gif",
"https://media0.giphy.com/media/3otPorfb8Lu7wjKllm/giphy.gif",
"https://media3.giphy.com/media/xT9IgFLBcm3Wi6l6qA/giphy.gif",
];