Respond to incidents with Google Chat, Vertex AI, and Apps Script

This tutorial shows how to make a Google Chat app that responds to incidents in real time. When responding to an incident, the app creates and populates a Chat space, facilitates incident resolution with messages, slash commands, and dialogs, and uses AI to summarize the incident response in a Google Docs document.

An incident is an event that requires the immediate attention of a team of people to resolve. Examples of incidents include:

  • A time-sensitive case is created in a Customer Relationship Management (CRM) platform, requiring a service team to collaborate on a resolution.
  • A system goes offline, alerting a group of site reliability engineers (SREs) so that they can work together to bring it back online.
  • A high magnitude earthquake occurs, and emergency workers need to coordinate their response.

For the purposes of this tutorial, the incident alert starts when someone reports the incident with a button click from a web page. The web page simulates an incident by asking users to enter basic incident information: title, description, and email addresses of the responders.

See the incident management Chat app in action:

  • The website that starts an incident.
    Figure 1. The website where someone can report an incident.
  • Notification that the incident Chat space is created.
    Figure 2. Notification that the incident Chat space is created.
  • The incident response Chat space.
    Figure 3. The incident response Chat space.
  • Resolving the incident with a slash command.
    Figure 4. Resolving the incident with a slash command.
  • Incident resolution dialog.
    Figure 5. Incident resolution dialog.
  • Incident resolution Google Docs document shared in space.
    Figure 6. Incident resolution Google Docs document shared in space.
  • The AI summary incident resolution Google Doc.
    Figure 7. The AI summary incident resolution Google Docs document.


If you need any of these prerequisites turned on for your organization, ask your Google Workspace administrator to turn them on:

  • A Google Workspace account with access to Google Chat.
  • To have Directory (contact sharing) turned on for Google Workspace. The incident app uses the directory to look up the incident responders' contact info, like name and email address. Incident responders must be users with a Google Chat account in your Google Workspace organization.


  • Build a Chat app that responds to incidents.
  • Help users respond to incidents by doing the following:
    • Creating incident response spaces.
    • Posting messages summarizing incidents and responses.
    • Supporting collaboration with interactive Chat app features.
  • Summarize conversations and resolutions with Vertex AI.


The following diagram shows the architecture of the Google Workspace and Google Cloud resources used by the incident response Google Chat app.

Architecture of the incident response Google Chat app

The architecture shows how the incident response Google Chat app processes an incident and resolution.

  1. A user starts an incident from an external website hosted on Apps Script.

  2. The website sends an asynchronous HTTP request to the Google Chat app, also hosted on Apps Script.

  3. The incident response Google Chat app processes the request:

    1. The Apps Script Admin SDK service gets team member information, like user ID and email address.

    2. With a set of HTTP requests to Chat API using the Apps Script Advanced Chat service, the incident response Google Chat app creates an incident Chat space, populates it with team members, and sends a message to the space.

  4. Team members discuss the incident in the Chat space.

  5. A team member invokes a slash command to signal a resolution to the incident.

    1. An HTTP call to Chat API using the Apps Script Advanced Chat service lists all the Chat space's messages.

    2. Vertex AI receives the listed messages and generates a summary.

    3. The Apps Script DocumentApp service creates a Docs document and adds Vertex AI's summary to the document.

    4. The incident response Google Chat app calls Chat API to send a message sharing a link to the summary Docs document.

Prepare the environment

This section shows how to create and configure a Google Cloud project for the Chat app.

Create a Google Cloud project

Google Cloud console

  1. In the Google Cloud console, go to Menu > IAM & Admin > Create a Project.

    Go to Create a Project

  2. In the Project Name field, enter a descriptive name for your project.

    Optional: To edit the Project ID, click Edit. The project ID can't be changed after the project is created, so choose an ID that meets your needs for the lifetime of the project.

  3. In the Location field, click Browse to display potential locations for your project. Then, click Select.
  4. Click Create. The Google Cloud console navigates to the Dashboard page and your project is created within a few minutes.

gcloud CLI

In one of the following development environments, access the Google Cloud CLI (`gcloud`):

  • Cloud Shell: To use an online terminal with the gcloud CLI already set up, activate Cloud Shell.
    Activate Cloud Shell
  • Local Shell: To use a local development environment, install and initialize the gcloud CLI.
    To create a Cloud project, use the `gcloud projects create`command:
    gcloud projects create PROJECT_ID
    Replace PROJECT_ID by setting the ID for the project you want to create.

Enable billing for the Cloud project

Google Cloud console

  1. In the Google Cloud console, go to Billing. Click Menu > Billing > My Projects.

    Go to Billing for My Projects

  2. In Select an organization, choose the organization associated with your Google Cloud project.
  3. In the project row, open the Actions menu (), click Change billing, and choose the Cloud Billing account.
  4. Click Set account.

gcloud CLI

  1. To list available billing accounts, run:
    gcloud billing accounts list
  2. Link a billing account with a Google Cloud project:
    gcloud billing projects link PROJECT_ID --billing-account=BILLING_ACCOUNT_ID

    Replace the following:

    • PROJECT_ID is the Project ID for the Cloud project for which you want to enable billing.
    • BILLING_ACCOUNT_ID is the billing account ID to link with the Google Cloud project.

Enable the APIs

Google Cloud console

  1. In the Google Cloud console, enable the Google Chat API, the Google Docs API, the Admin SDK API, and the Vertex AI API.

    Enable the APIs

  2. Confirm that you're enabling the APIs in the correct Cloud project, then click Next.

  3. Confirm that you're enabling the correct APIs, then click Enable.

gcloud CLI

  1. If necessary, set the current Cloud project to the one you created with the gcloud config set project command:

    gcloud config set project PROJECT_ID

    Replace PROJECT_ID with the Project ID of the Cloud project you created.

  2. Enable the Google Chat API, Google Docs API, Admin SDK API, and Vertex AI API with the gcloud services enable command:

    gcloud services enable

Set up authentication and authorization

Authentication and authorization lets the Chat app access resources in Google Workspace and Google Cloud to process an incident response.

In this tutorial, you publish the app internally so it's OK to use placeholder information. Before publishing the app externally, replace placeholder information with real information for the consent screen.

  1. In the Google Cloud console, go to Menu > APIs & Services > OAuth consent screen.

    Go to OAuth consent screen

  2. Under User type, select Internal, then click Create.

  3. In App name, type Incident Management.

  4. In User support email, select your email address or an appropriate Google group.

  5. Under Developer contact information, enter your email address.

  6. Click Save and Continue.

  7. Click Add or Remove Scopes. A panel appears with a list of scopes for each API that you've enabled in your Cloud project.

  8. Under Manually add scopes, paste the following scopes:

  9. Click Add to Table.

  10. Click Update.

  11. Click Save and Continue.

  12. Review the app registration summary, then click Back to Dashboard.

Create and deploy the Chat app

In the following section, you copy and update an entire Apps Script project that contains all the required application code for your Chat app, so there's no need to copy and paste each file.

Some functions include underscores at the end of their names, like processSlashCommand_() from The underscore hides the function from the incident initialization web page when it's open in a browser. For more information, see Private functions.

Apps Script supports two file types, .gs scripts and .html files. To abide by this support, the app's client-side JavaScript is included inside <script /> tags and its CSS is included inside <style /> tags inside an HTML file.

Optionally, you can view the entire project on GitHub.

View on GitHub

Here's an overview of each file:

Defines constants referenced by other code files, including your Cloud project ID, Vertex AI location ID, and the slash command ID for closing an incident.

View code

const PROJECT_ID = 'replace-with-your-project-id';
const VERTEX_AI_LOCATION_ID = 'us-central1';

Handles Chat interaction events, including messages, card clicks, slash commands, and dialogs. Responds to the /closeIncident slash command by opening a dialog to gather incident resolution details. Reads messages in the space by calling the spaces.messages.list method in the Chat API. Gets user IDs using the Admin SDK Directory service in Apps Script.

View code

 * Responds to a MESSAGE event in Google Chat.
 * This app only responds to a slash command with the ID 1 ("/closeIncident").
 * It will respond to any other message with a simple "Hello" text message.
 * @param {Object} event the event object from Google Chat
function onMessage(event) {
  if (event.message.slashCommand) {
    return processSlashCommand_(event);
  return { "text": "Hello from Incident Response app!" };

 * Responds to a CARD_CLICKED event in Google Chat.
 * This app only responds to one kind of dialog (Close Incident).
 * @param {Object} event the event object from Google Chat
function onCardClick(event) {
  if (event.isDialogEvent) {
    if (event.dialogEventType == 'SUBMIT_DIALOG') {
      return processSubmitDialog_(event);
    return {
      actionResponse: {
        type: "DIALOG",
        dialogAction: {
          actionStatus: "OK"

 * Responds to a MESSAGE event with a Slash command in Google Chat.
 * This app only responds to a slash command with the ID 1 ("/closeIncident")
 * by returning a Dialog.
 * @param {Object} event the event object from Google Chat
function processSlashCommand_(event) {
  if (event.message.slashCommand.commandId != CLOSE_INCIDENT_COMMAND_ID) {
    return {
      "text": "Command not recognized. Use the command `/closeIncident` to close the incident managed by this space."
  const sections = [
      header: "Close Incident",
      widgets: [
          textInput: {
            label: "Please describe the incident resolution",
            type: "MULTIPLE_LINE",
            name: "description"
          buttonList: {
            buttons: [
                text: "Close Incident",
                onClick: {
                  action: {
                    function: "closeIncident"
  return {
    actionResponse: {
      type: "DIALOG",
      dialogAction: {
        dialog: {
          body: {

 * Responds to a CARD_CLICKED event with a Dialog submission in Google Chat.
 * This app only responds to one kind of dialog (Close Incident).
 * It creates a Doc with a summary of the incident information and posts a message
 * to the space with a link to the Doc.
 * @param {Object} event the event object from Google Chat
function processSubmitDialog_(event) {
  const resolution = event.common.formInputs.description[""].stringInputs.value[0];
  const chatHistory = concatenateAllSpaceMessages_(;
  const chatSummary = summarizeChatHistory_(chatHistory);
  const docUrl = createDoc_(, resolution, chatHistory, chatSummary);
  return {
    actionResponse: {
      type: "NEW_MESSAGE",
    text: `Incident closed with the following resolution: ${resolution}\n\nHere is the automatically generated post-mortem:\n${docUrl}`

 * Lists all the messages in the Chat space, then concatenate all of them into
 * a single text containing the full Chat history.
 * For simplicity for this demo, it only fetches the first 100 messages.
 * Messages with slash commands are filtered out, so the returned history will
 * contain only the conversations between users and not app command invocations.
 * @return {string} a text containing all the messages in the space in the format:
 *          Sender's name: Message
function concatenateAllSpaceMessages_(spaceName) {
  // Call Chat API method spaces.messages.list
  const response = Chat.Spaces.Messages.list(spaceName, { 'pageSize': 100 });
  const messages = response.messages;
  // Fetch the display names of the message senders and returns a text
  // concatenating all the messages.
  let userMap = new Map();
  return messages
    .filter(message => message.slashCommand === undefined)
    .map(message => `${getUserDisplayName_(userMap,}: ${message.text}`)

 * Obtains the display name of a user by using the Admin Directory API.
 * The fetched display name is cached in the provided map, so we only call the API
 * once per user.
 * If the user does not have a display name, then the full name is used.
 * @param {Map} userMap a map containing the display names previously fetched
 * @param {string} userName the resource name of the user
 * @return {string} the user's display name
function getUserDisplayName_(userMap, userName) {
  if (userMap.has(userName)) {
    return userMap.get(userName);
  let displayName = 'Unknown User';
  try {
    const user = AdminDirectory.Users.get(
      userName.replace("users/", ""),
      { projection: 'BASIC', viewType: 'domain_public' });
    displayName = ? :;
  } catch (e) {
    // Ignore error if the API call fails (for example, because it's an
    // out-of-domain user or Chat app)) and just use 'Unknown User'.
  userMap.set(userName, displayName);
  return displayName;

Receives form data users enter on the incident initialization web page, and uses it to set up a Chat space by creating and populating it, and then posts a message about the incident.

View code

 * Creates a space in Google Chat with the provided title and members, and posts an
 * initial message to it.
 * @param {Object} formData the data submitted by the user. It should contain the fields
 *                          title, description, and users.
 * @return {string} the resource name of the new space.
function createChatSpace(formData) {
  const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
  const spaceName = setUpSpace_(formData.title, users);
  createMessage_(spaceName, formData.description);
  return spaceName;

 * Creates a space in Google Chat with the provided display name and members.
 * @return {string} the resource name of the new space.
function setUpSpace_(displayName, users) {
  const memberships = => ({
    member: {
      name: `users/${email}`,
      type: "HUMAN"
  const request = {
    space: {
      displayName: displayName,
      spaceType: "SPACE",
      externalUserAllowed: true
    memberships: memberships
  // Call Chat API method spaces.setup
  const space = Chat.Spaces.setup(request);

 * Adds this Chat app to the space.
 * @return {string} the resource name of the new membership.
function addAppToSpace_(spaceName) {
  const request = {
    member: {
      name: "users/app",
      type: "BOT"
  // Call Chat API method spaces.members.create
  const membership = Chat.Spaces.Members.create(request, spaceName);

 * Posts a text message to the space on behalf of the user.
 * @return {string} the resource name of the new message.
function createMessage_(spaceName, text) {
  const request = {
    text: text
  // Call Chat API method spaces.messages.create
  const message = Chat.Spaces.Messages.create(request, spaceName);

Calls the Google Docs API to create a Google Docs document in a user's Google Drive and writes a summary of the incident information, created in, to the document.

View code

 * Creates a Doc in the user's Google Drive and writes a summary of the incident information to it.
 * @param {string} title The title of the incident
 * @param {string} resolution Incident resolution described by the user
 * @param {string} chatHistory The whole Chat history be included in the document
 * @param {string} chatSummary A summary of the Chat conversation to be included in the document
 * @return {string} the URL of the created Doc
function createDoc_(title, resolution, chatHistory, chatSummary) {
  let doc = DocumentApp.create(title);
  let body = doc.getBody();
  body.appendParagraph(`Post-Mortem: ${title}`).setHeading(DocumentApp.ParagraphHeading.TITLE);
  body.appendParagraph("Summary of the conversation").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph("Full Chat history").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  return doc.getUrl();

Summarizes the conversation in the Chat space using Vertex AI. This summary is posted in a specially-created document in

View code

 * Summarizes a Chat conversation using the Vertex AI text prediction API.
 * @param {string} chatHistory The Chat history that will be summarized.
 * @return {string} The content from the text prediction response.
function summarizeChatHistory_(chatHistory) {
  const prompt =
    "Summarize the following conversation between Engineers resolving an incident"
      + " in a few sentences. Use only the information from the conversation.\n\n"
      + chatHistory;
  const request = {
    instances: [
      { prompt: prompt }
    parameters: {
      temperature: 0.2,
      maxOutputTokens: 256,
      topK: 40,
      topP: 0.95
  const fetchOptions = {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
    contentType: 'application/json',
    payload: JSON.stringify(request)
  const response = UrlFetchApp.fetch(
      + `/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}`
      + "/publishers/google/models/text-bison:predict",
  const payload = JSON.parse(response.getContentText());
  return payload.predictions[0].content;

Serves the incident initialization website.

View code

 * Serves the web page from Index.html.
function doGet() {
  return HtmlService

 * Serves the web content from the specified filename.
function include(filename) {
  return HtmlService

 * Returns the email address of the user running the script.
function getUserEmail() {
  return Session.getActiveUser().getEmail();

The HTML comprising the incident initialization website.

View Index.html code

<!DOCTYPE html>
    <base target="_top">
    <link href='' rel='stylesheet'>
    <?!= include('Stylesheet'); ?>
    <div class="container">
      <div class="content">
        <h1>Incident Manager</h1>
        <form id="incident-form" onsubmit="handleFormSubmit(this)">
          <div id="form">
              <label for="title">Incident title</label><br/>
              <input type="text" name="title" id="title" />
              <label for="users">Incident responders</label><br/>
                Please enter a comma-separated list of email addresses of the users
                that should be added to the space.
                Do not include <?= getUserEmail() ?> as it will be added automatically.
              <input type="text" name="users" id="users" />
              <label for="description">Initial message</label></br>
              <small>This message will be posted after the space is created.</small><br/>
              <textarea name="description" id="description"></textarea>
            <p class="text-center">
              <input type="submit" value="CREATE CHAT SPACE" />
          <div id="output" class="hidden"></div>
          <div id="clear" class="hidden">
            <input type="reset" value="CREATE ANOTHER INCIDENT" onclick="onReset()" />
    <?!= include('JavaScript'); ?>

Handles form behavior including submits, errors, and clears, for the incident initialization website. It's included into Index.html by the custom include function in

View JavaScript.html code

  var formDiv = document.getElementById('form');
  var outputDiv = document.getElementById('output');
  var clearDiv = document.getElementById('clear');

  function handleFormSubmit(formObject) {
    outputDiv.innerHTML = 'Please wait while we create the space...';

  function updateOutput(response) {
    var spaceId = response.replace('spaces/', '');
    outputDiv.innerHTML =
      '<p>Space created!</p><p><a href="'
        + spaceId
        + '" target="_blank">Open space</a></p>';

  function onFailure(error) {
    outputDiv.innerHTML = 'ERROR: ' + error.message;

  function onReset() {
    outputDiv.innerHTML = '';

  function hide(element) {

  function show(element) {

The CSS for the incident initialization website. It's included into Index.html by the custom include function in

View Stylesheet.html code

  * {
    box-sizing: border-box;
  body {
    font-family: Roboto, Arial, Helvetica, sans-serif;
  div.container {
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
  div.content {
    width: 80%;
    max-width: 1000px;
    padding: 1rem;
    border: 1px solid #999;
    border-radius: 0.25rem;
    box-shadow: 0 2px 2px 0 rgba(66, 66, 66, 0.08), 0 2px 4px 2px rgba(66, 66, 66, 0.16);
  h1 {
    text-align: center;
    padding-bottom: 1rem;
    margin: 0 -1rem 1rem -1rem;
    border-bottom: 1px solid #999;
 #output {
    text-align: center;
    min-height: 250px;
  div#clear {
    text-align: center;
    padding-top: 1rem;
    margin: 1rem -1rem 0 -1rem;
    border-top: 1px solid #999;
  input[type=text], textarea {
    width: 100%;
    padding: 1rem 0.5rem;
    margin: 0.5rem 0;
    border: 0;
    border-bottom: 1px solid #999;
    background-color: #f0f0f0;
  textarea {
    height: 5rem;
  small {
    color: #999;
  input[type=submit], input[type=reset] {
    padding: 1rem;
    border: none;
    background-color: #6200ee;
    color: #fff;
    border-radius: 0.25rem;
    width: 25%;
  .hidden {
    display: none;
  .text-center {
    text-align: center;
  .error {
    color: red;

Find your Cloud project number and ID

  1. In the Google Cloud console, go to your Cloud project.

    Go to Google Cloud console

  2. Click Settings and Utilities > Project settings.

  3. Note the values in the Project number and Project ID fields. You use them in the following sections.

Create the Apps Script project

To create an Apps Script project and connect it with your Cloud project:

  1. Click the following button to open the Respond to incidents with Google Chat Apps Script project.
    Open the project
  2. Click Overview.
  3. On the overview page, click The icon for making a copy Make a copy.
  4. Name your copy of the Apps Script project:

    1. Click Copy of Respond to incidents with Google Chat.

    2. In Project title, type Incident Management Chat app.

    3. Click Rename.

  5. In your copy of the Apps Script project, go to the file and replace YOUR_PROJECT_ID with the ID of your Cloud project.

Set the Apps Script project's Cloud project

  1. In your Apps Script project, click The icon for project settings Project Settings.
  2. Under Google Cloud Platform (GCP) Project, click Change project.
  3. In GCP project number, paste the project number of your Cloud project.
  4. Click Set project. The Cloud project and Apps Script project are now connected.

Create an Apps Script deployment

Now that all the code is in place, deploy the Apps Script project. You use the deployment ID when you configure the Chat app in the Google Cloud.

  1. In Apps Script, open the incident response app's project.

    Go to Apps Script

  2. Click Deploy > New deployment.

  3. If Add-on and Web app aren't already selected, next to Select type, click deployment types The icon for project settings and select Add-on and Web app.

  4. In Description, enter a description for this version, like Complete version of incident management app.

  5. In Execute as, select User accessing the web app

  6. In Who has access, select Anyone within your Workspace organization, where "your Workspace organization" is the name of your Google Workspace organization.

  7. Click Deploy. Apps Script reports successful deployment and provides a deployment ID and a URL for the incident initialization web page.

  8. Make note of the Web app URL to visit later when you start an incident. Copy the Deployment ID. You use this ID while configuring the Chat app in Google Cloud console.

  9. Click Done.

Configure the Chat app in the Google Cloud console

This section shows how to configure the Google Chat API in the Google Cloud console with information about your Chat app, including the ID of the deployment that you just created from your Apps Script project.

  1. In the Google Cloud console, click Menu > More products > Google Workspace > Product Library > Google Chat API > Manage > Configuration.

    Go to Chat API configuration

  2. In App name, type Incident Management.

  3. In Avatar URL, type

  4. In Description, type Responds to incidents..

  5. Click the Enable Interactive features toggle to the on position.

  6. Under Functionality, select Receive 1:1 messages, Join spaces and group conversations.

  7. Under Connection settings, select Apps Script project.

  8. In Deployment ID, paste the Apps Script Deployment ID that you copied earlier from the Apps Script project deployment.

  9. Register a slash command that the fully implemented Chat app uses:

    1. Under Slash commands, click Add a slash command.

    2. In Name, type /closeIncident.

    3. In Command ID, type 1.

    4. In Description, type Closes the incident being discussed in the space.

    5. Select Opens a dialog.

    6. Click Done. The slash command is registered and listed.

  10. Under Visibility, select Make this Chat app available to specific people and groups in Your Workspace Domain and enter your email address.

  11. Under Logs, select Log errors to Logging.

  12. Click Save. A configuration saved message appears, meaning the app is ready to test.

Test the Chat app

To test the incident management Chat app, initiate an incident from the web page and verify that the Chat app works as expected:

  1. Go to the Apps Script deployment web app URL.

  2. When Apps Script asks permission to access your data, click Review permissions, sign in with an appropriate Google Account in your Google Workspace domain, and click Allow.

  3. The incident initialization web page opens. Enter test information:

    1. In Incident title, type The First Incident.
    2. Optionally, in Incident responders, enter the email addresses of your fellow incident responders. They must be users with a Google Chat account in your Google Workspace organization or space creation fails. Don't enter your own email address because it's included automatically.
    3. In Initial message, type Testing the incident management Chat app.
  4. Click Create Chat Space. A creating space message appears.

  5. After the space is created, a Space created! message appears. Click Open space, which opens the space in Chat in a new tab.

  6. Optionally, you and the other incident responders can send messages in the space. The app summarizes these messages using Vertex AI and shares a retrospective document.

  7. To end the incident response and begin the resolution process, in the Chat space, type /closeIncident. An incident management dialog opens.

  8. In Close incident, enter a description for the incident resolution, like Test complete.

  9. Click Close Incident.

The Incident Management app lists the messages in the space, summarizes them with Vertex AI, pastes the summary in a Google Docs document, and shares the document in the space.

Clean up

To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, we recommend that you delete the Cloud project.

  1. In the Google Cloud console, go to the Manage resources page. Click Menu > IAM & Admin > Manage Resources.

    Go to Resource Manager

  2. In the project list, select the project you want to delete and then click Delete .
  3. In the dialog, type the project ID and then click Shut down to delete the project.