Hangouts Chat bots provide easy-to-use access points to your organization's data and services. Users can interact with bots conversationally within a chat experience.

Among other implementation options, you can create a Hangouts Chat bot using Google Apps Script. By building your bot in Apps Script, you can easily access other Google services like Drive, Gmail, Calendar, Docs, Sheets, and much more.

In this code lab, you learn how to create a simple Hangouts Chat bot—"Attendance Bot"—using Google Apps Script. The bot integrates with Gmail to set a user's vacation responder and integrates with Calendar to put a meeting on the user's calendar.

What you'll learn

What you'll need

You can either download a ZIP file or clone the GitHub repository to see the code for each step in this sample.

The step-NN folders contain the desired end state of each step of this codelab. They are there for reference.

Download the Code

Click the following link to download all the code for this codelab:

Download source code

Unpack the downloaded zip file. This will unpack a root folder (hangouts-chat-apps-script), which contains one folder for each step of this codelab.

Cloning the GitHub repository

To clone the GitHub repository for this codelab, run the following command:

git clone https://github.com/googlecodelabs/hangouts-chat-apps-script

To start implementing your bot, create a new Google Apps Script script by doing the following:

  1. In your browser, open the Google Apps Script editor.
  2. Rename the new script 'Attendance Bot'.

Events in Hangouts Chat

Most Apps Script bot interactions with Hangouts Chat are event-driven. The interaction between the user, the bot, and Hangouts chat typically follows this sequence:

  1. A user initiates an action, like adding a bot to a room, starting a direct message (DM) with a bot, or removing the bot from a room.
  2. The action raises an event aimed at the bot in Hangouts Chat.
  3. Hangouts Chat calls the corresponding event handler defined in the bot's script.

Hangouts Chat raises four events that your Apps Script bot can listen for:

Replace the contents of the Code.gs file with the following code that defines handlers for the ADDED_TO_SPACE and REMOVE_FROM_SPACE events. (You'll add handlers for the MESSAGE and CARD_CLICKED events later in this codelab.)

Code.gs

/**
 * Responds to an ADDED_TO_SPACE event in Hangouts Chat.
 * @param {object} event the event object from Hangouts Chat
 * @return {object} JSON-formatted response
 * @see https://developers.google.com/hangouts/chat/reference/message-formats/events
 */
function onAddToSpace(event) {
  console.info(event);
  var message = 'Thank you for adding me to ';
  if (event.space.type === 'DM') {
    message += 'a DM, ' + event.user.displayName + '!';
  } else {
    message += event.space.displayName;
  }
  return { text: message };
}

/**
 * Responds to a REMOVED_FROM_SPACE event in Hangouts Chat.
 * @param {object} event the event object from Hangouts Chat
 * @see https://developers.google.com/hangouts/chat/reference/message-formats/events
 */
function onRemoveFromSpace(event) {
  console.info(event);
  console.log('Bot removed from ', event.space.name);
}

Before you can run and test the bot, you need to enable the Hangouts Chat API and publish your bot to your G Suite organization through the Google Cloud Console.

Publish your bot

Before you can publish your bot to Hangouts Chat, you need to first update the script manifest.

  1. In the Apps Script editor, click View > Show manifest file.
  2. Add the line "chat": {} to your manifest file.

Your manifest file should look similar to the following example.

appsscript.json

{
  "timeZone": "America/Los_Angeles",
  "dependencies": {
  },
  "chat": {}
}

To publish your bot to Hangouts Chat, do the following:

  1. From the Apps Script editor, get the deployment ID for the script by clicking Publish > Deploy from manifest.
  2. In the Deployments dialog box, click Get ID.
  3. In the Deployment ID dialog box, copy the value listed for the Deployment ID. Click Close and Close to dismiss the dialog boxes.
  4. In the App Script Editor, click Resources > Cloud Platform project. Click the link for the associated project to open the Google Cloud Console.
  5. In the Google Cloud Console, click APIs & Services > Library.
  6. In the Library, search for ‘Hangouts Chat'. Select the API from the list of results.
  7. On the page for the Hangouts Chat API, click Enable. The Cloud Console displays a progress indicator while enabling the API.
  8. Once the API is enabled, on the Hangouts Chat API page click the Configuration tab.
    Note: Ignore any messages asking you to create credentials.
  9. In the Configuration tab, do the following:

After you save your changes, verify that the status on the Hangouts Chat API page shows the Bot Status to be LIVE – available to users.

Test the bot

To test your bot in Hangouts Chat, do the following:

  1. Open Hangouts Chat.
  2. Click Find people, rooms, bots > Message a bot.
  3. From the list, select the "Attendance Bot" that you created.

When the direct message thread opens, you should see a message from the bot thanking you for adding it to a DM, as shown in the following image.

In the previous step, your bot responded to Hangouts Chat events a simple text response. In this step, you will update your bot to respond with cards.

Card responses

Hangouts Chat supports the use of cards for responses. Cards are visual containers that allow you to group sets of user interface widgets together. Cards can display headers, text paragraphs, sets of buttons, images, and key/value text. Your bot can define one or many cards in its JSON response to Hangouts Chat, which then translates your response into the corresponding UI elements.

The following image shows a card response with three sections, that includes a header, a key/value widget, an image widget, and a text button.

To respond to user messages with a card response, add the following code to your bot's Code.gs file.

Code.gs

var DEFAULT_IMAGE_URL = 'https://goo.gl/bMqzYS';
var HEADER = {
  header: {
    title : 'Attendance Bot',
    subtitle : 'Log your vacation time',
    imageUrl : DEFAULT_IMAGE_URL
  }
};

/**
 * Creates a card-formatted response.
 * @param {object} widgets the UI components to send
 * @return {object} JSON-formatted response
 */
function createCardResponse(widgets) {
  return {
    cards: [HEADER, {
      sections: [{
        widgets: widgets
      }]
    }]
  };
}

/**
 * Responds to a MESSAGE event triggered
 * in Hangouts Chat.
 *
 * @param event the event object from Hangouts Chat
 * @return JSON-formatted response
 */
function onMessage(event) {
  var userMessage = event.message.text;

  var widgets = [{
    "textParagraph": {
      "text": "You said: " + userMessage
    }
  }];

  return createCardResponse(widgets);
}

The onMessage() function, added in this step, reads the user's original message and constructs a response as a simple TextParagragh widget. The onMessage() function then calls createCardResponse(), which places the TextParagraph widget within a section of a single card. The bot returns the JavaScript object constructed with the card response back to Hangouts Chat.

Test the bot


To test this bot, simply go back to your direct message with the bot in Hangouts Chat and type a message (any message will do).

Note that the onMessage() event handler parses the event object passed to it by Hangouts Chat to extract the user's original message. You can also get other types of information about the event, including the name of the user that initiated the event, their email address, the name of the room that the event occurred in, and much more.

For more information about the structure of the event objects sent by Hangouts Chat, see the Event formats reference.

In the previous step, your bot responded to a message from a user—a MESSAGE event—with a simple card that contained a TextParagragh widget. In this step, you will create a response that includes buttons, where each button has a custom action defined for it.

Interactive cards


Card responses can contain one of two types of buttons: TextButton widgets, which display text-only buttons; and ImageButton widgets, which display a button with a simple icon or image without text. Both TextButton and ImageButton widgets support one of two onClick behaviors (as defined in the JSON response sent back to Hangouts Chat): either openLink or action. As the name implies, openLink opens a specified link in a new browser tab.

The action object, however, specifies a custom action for the button to perform. You can specify several arbitrary values in the action object, including a unique actionMethodName and a set of key / value parameter pairs.

Specifying an action object for the button creates an interactive card. When the user clicks the button in the message, Hangouts Chat raises a CARD_CLICKED event and sends a request back to the bot that sent the original message. The bot then needs to handle the event raised from Hangouts Chat and return a response back to the space.

Replace the onMessage() function in Code.gs with the following code. This code creates two buttons, a Set vacation in Gmail and a Block out day in Calendar button in the card sent to Hangouts Chat.

Code.gs

var REASON = {
  SICK: 'Out sick',
  OTHER: 'Out of office'
};
/**
 * Responds to a MESSAGE event triggered in Hangouts Chat.
 * @param {object} event the event object from Hangouts Chat
 * @return {object} JSON-formatted response
 */
function onMessage(event) {
  console.info(event);
  var reason = REASON.OTHER;
  var name = event.user.displayName;
  var userMessage = event.message.text;

  // If the user said that they were 'sick', adjust the image in the
  // header sent in response.
  if (userMessage.indexOf('sick') > -1) {
    // Hospital material icon
    HEADER.header.imageUrl = 'https://goo.gl/mnZ37b';
    reason = REASON.SICK;
  } else if (userMessage.indexOf('vacation') > -1) {
    // Spa material icon
    HEADER.header.imageUrl = 'https://goo.gl/EbgHuc';
  }

  var widgets = [{
    textParagraph: {
      text: 'Hello, ' + name + '.<br/>Are you taking time off today?'
    }
  }, {
    buttons: [{
      textButton: {
        text: 'Set vacation in Gmail',
        onClick: {
          action: {
            actionMethodName: 'turnOnAutoResponder',
            parameters: [{
              key: 'reason',
              value: reason
            }]
          }
        }
      }
    }, {
      textButton: {
        text: 'Block out day in Calendar',
        onClick: {
          action: {
            actionMethodName: 'blockOutCalendar',
            parameters: [{
              key: 'reason',
              value: reason
            }]
          }
        }
      }
    }]
  }];
  return createCardResponse(widgets);
}

To handle the CARD_CLICKED event, you need to add the onCardClick() function to your bot's script. Add the following code that defines the onCardClick() function Code.gs.

Code.gs

/**
 * Responds to a CARD_CLICKED event triggered in Hangouts Chat.
 * @param {object} event the event object from Hangouts Chat
 * @return {object} JSON-formatted response
 * @see https://developers.google.com/hangouts/chat/reference/message-formats/events
 */
function onCardClick(event) {
  console.info(event);
  var message = '';
  var reason = event.action.parameters[0].value;
  if (event.action.actionMethodName == 'turnOnAutoResponder') {
    turnOnAutoResponder(reason);
    message = 'Turned on vacation settings.';
  } else if (event.action.actionMethodName == 'blockOutCalendar') {
    blockOutCalendar(reason);
    message = 'Blocked out your calendar for the day.';
  } else {
    message = "I'm sorry; I'm not sure which button you clicked.";
  }
  return { text: message };
}

In responding to user clicks, now the bot does one of two things: it sets the user's vacation responder in Gmail to an "out of office" message; or it schedules an all-day meeting on the user's Calendar. To accomplish these tasks, the bot calls the Gmail advanced service and the Calendar Apps Script API.

Add the following code to your script to integrate the bot with Gmail and Calendar.

Code.gs

var ONE_DAY_MILLIS = 24 * 60 * 60 * 1000;
/**
 * Turns on the user's vacation response for today in Gmail.
 * @param {string} reason the reason for vacation, either REASON.SICK or REASON.OTHER
 */
function turnOnAutoResponder(reason) {
  var currentTime = (new Date()).getTime();
  Gmail.Users.Settings.updateVacation({
    enableAutoReply: true,
    responseSubject: reason,
    responseBodyHtml: "I'm out of the office today; will be back on the next business day.<br><br><i>Created by Attendance Bot!</i>",
    restrictToContacts: true,
    restrictToDomain: true,
    startTime: currentTime,
    endTime: currentTime + ONE_DAY_MILLIS
  }, 'me');
}

/**
 * Places an all-day meeting on the user's Calendar.
 * @param {string} reason the reason for vacation, either REASON.SICK or REASON.OTHER
 */
function blockOutCalendar(reason) {
  CalendarApp.createAllDayEvent(reason, new Date(), new Date(Date.now() + ONE_DAY_MILLIS));
}

Finally, you need to enable the Gmail Advanced Service in the project. To enable the Gmail API, do the following:

  1. Click Resources > Advanced Google Services.
  2. In the list, find Gmail API and select on.
  3. Still in the dialog box, click the link below that opens the Google API Console.
  4. Click Enable APIs and Services.
  5. Search for ‘Gmail API' and click the Gmail API card.
  6. On the Gmail API page, click Enable.

Test the bot

To test this version of your bot, open the DM that you started in previous steps in Hangouts Chat and type ‘I'm sick'. The bot should respond with a card similar to the image below.

Note: If you are asked to provide access to the bot, you may have to type your message a second time.

Your bot can now respond to user messages, set their vacation responder in Gmail, and put an all-day event on their Calendar.

What we've covered

Learn more