Visualizar links em mensagens do Google Chat

Para evitar a troca de contexto quando os usuários compartilham um link no Google Chat, seu app Chat pode visualizar o link anexando um card à mensagem com mais informações e permitindo que as pessoas realizem ações diretamente no Google Chat.

Por exemplo, imagine um espaço do Google Chat que inclua todos os agentes de atendimento ao cliente de uma empresa e um app do Chat chamado Case-y. Os agentes costumam compartilhar links para casos de atendimento ao cliente no espaço do Chat, e cada vez que fazem isso, os colegas precisam abrir o link do caso para ver detalhes como responsável, status e assunto. Da mesma forma, se alguém quiser assumir um caso ou mudar o status, é necessário abrir o link.

Com a visualização de links, o app de chat residente do espaço, o Case-y, anexa um card mostrando o atribuidor, o status e o assunto sempre que alguém compartilha um link de caso. Os botões no card permitem que os agentes assumam o caso e mudem o status diretamente do fluxo de chat.

Quando alguém adiciona um link à mensagem, um ícone aparece para informar que um app de chat pode mostrar uma prévia do link.

Ícone indicando que um app de chat pode visualizar um link

Depois de enviar a mensagem, o link é enviado ao app Chat, que gera e anexa o card à mensagem do usuário.

App de chat mostrando a prévia de um link ao anexar um card à mensagem

Além do link, o card fornece mais informações sobre ele, incluindo elementos interativos, como botões. O app Chat pode atualizar o card anexado em resposta a interações do usuário, como cliques em botões.

Se alguém não quiser que o app Chat mostre uma prévia do link anexando um card à mensagem, é possível impedir isso clicando em no ícone de prévia. Os usuários podem remover o card anexado a qualquer momento clicando em Remover visualização.

Pré-requisitos

HTTP

Um complemento do Google Workspace que estende o Google Chat. Para criar um, conclua o início rápido de HTTP.

Apps Script

Um complemento do Google Workspace que estende o Google Chat. Para criar um, conclua o guia de início rápido do Apps Script.

Registre links específicos, como example.com, support.example.com e support.example.com/cases/, como padrões de URL na página de configuração do app do Chat no console do Google Cloud para que o app possa visualizá-los.

Menu de configuração de visualizações de links

  1. Abra o Console do Google Cloud.
  2. Ao lado de "Google Cloud", clique na seta para baixo e abra o projeto do app Chat.
  3. No campo de pesquisa, digite Google Chat API e clique em API Google Chat.
  4. Clique em Gerenciar > Configuração.
  5. Em "Visualizações de link", adicione ou edite um padrão de URL.
    1. Para configurar prévias de link para um novo padrão de URL, clique em Adicionar padrão de URL.
    2. Para editar a configuração de um padrão de URL, clique na seta para baixo .
  6. No campo Padrão de host, insira o domínio do padrão de URL. O app Chat vai mostrar prévias dos links para esse domínio.

    Para que o app Chat mostre uma prévia de links de um subdomínio específico, como subdomain.example.com, inclua o subdomínio.

    Para que o app Chat mostre uma prévia dos links de todo o domínio, especifique um caractere curinga com um asterisco (*) como subdomínio. Por exemplo, *.example.com corresponde a subdomain.example.com e any.number.of.subdomains.example.com.

  7. No campo Prefixo do caminho, insira um caminho a ser anexado ao domínio do padrão de host.

    Para corresponder a todos os URLs no domínio do padrão de host, deixe Prefixo do caminho vazio.

    Por exemplo, se o padrão de host for support.example.com, para corresponder aos URLs de casos hospedados em support.example.com/cases/, insira cases/.

  8. Clique em Concluído.

  9. Clique em Salvar.

Agora, sempre que alguém incluir um link que corresponda a um padrão de URL de prévia de link em uma mensagem em um espaço do Chat que inclua seu app Chat, o app vai mostrar uma prévia do link.

Depois de configurar a visualização de links, seu app Chat pode reconhecer e visualizar o link anexando mais informações a ele.

Em espaços do Chat que incluem seu app Chat, quando a mensagem de alguém contém um link que corresponde a um padrão de URL de prévia de link, seu app Chat recebe um objeto de evento com um MessagePayload. No payload, o objeto message.matchedUrl contém o link que o usuário incluiu na mensagem:

JSON

message: {
  matchedUrl: {
    url: "https://support.example.com/cases/case123"
  },
  ... // other message attributes redacted
}

Ao verificar a presença do campo matchedUrl no payload do evento MESSAGE, seu app de chat pode adicionar informações à mensagem com o link visualizado. Seu app do Chat pode responder com uma mensagem de texto básica ou anexar um card.

Responder com uma mensagem de texto

Para respostas básicas, o app do Chat pode mostrar uma prévia de um link respondendo com uma mensagem de texto a um link. Este exemplo anexa uma mensagem que repete o URL do link que corresponde a um padrão de URL de visualização de link.

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to messages that have links whose URLs match URL patterns configured
 * for link previewing.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Response to send back depending on the matched URL.
 */
function handlePreviewLink(chatMessage) {
  // If the Chat app does not detect a link preview URL pattern, reply
  // with a text message that says so.
  if (!chatMessage.matchedUrl) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'No matchedUrl detected.'
    }}}}};
  }

  // Reply with a text message for URLs of the subdomain "text"
  if (chatMessage.matchedUrl.url.includes("text.example.com")) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.matchedUrl.url
    }}}}};
  }
}

Apps Script

/**
 * Reply to messages that have links whose URLs match the pattern
 * "text.example.com" configured for link previewing.
 *
 * @param {Object} event The event object from Google Workspace add-on.
 *
 * @return {Object} The action response.
 */
function onMessage(event) {
  // Stores the Google Chat event as a variable.
  const chatMessage = event.chat.messagePayload.message;

  // If the Chat app doesn't detect a link preview URL pattern, reply
  // with a text message that says so.
  if (!chatMessage.matchedUrl) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'No matchedUrl detected.'
    }}}}};
  }

  // Reply with a text message for URLs of the subdomain "text".
  if (chatMessage.matchedUrl.url.includes("text.example.com")) {
    return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.matchedUrl.url
    }}}}};
  }
}

Para anexar um card a um link visualizado, retorne a ação DataActions com o objeto ChatDataActionMarkup do tipo UpdateInlinePreviewAction.

No exemplo a seguir, um app do Chat adiciona um card de visualização às mensagens que contêm o padrão de URL support.example.com.

App de chat mostrando a prévia de um link ao anexar um card à mensagem

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to messages that have links whose URLs match URL patterns configured
 * for link previewing.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Response to send back depending on the matched URL.
 */
function handlePreviewLink(chatMessage) {
  // Attach a card to the message for URLs of the subdomain "support"
  if (chatMessage.matchedUrl.url.includes("support.example.com")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // the case information would be fetched and used to build the card.
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: { cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case basics',
        },
        sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // Use runtime environment variable set with self URL
          onClick: { action: { function: process.env.BASE_URL }}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

Apps Script

Este exemplo envia uma mensagem de card retornando um JSON de card. Você também pode usar o serviço de card do Apps Script.

/**
 * Attach a card to messages that have links whose URLs match the pattern
 * "support.example.com" configured for link previewing.
 *
 * @param {Object} event The event object from Google Workspace add-on.
 *
 * @return {Object} The action response.
 */
function onMessage(event) {
  // Stores the Google Chat event as a variable.
  const chatMessage = event.chat.messagePayload.message;

  // Attach a card to the message for URLs of the subdomain "support".
  if (chatMessage.matchedUrl.url.includes("support.example.com")) {
    // A hard-coded card is used in this example. In a real-life scenario,
    // the case information would be fetched and used to build the card.
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: { cardsV2: [{
      cardId: 'attachCard',
      card: {
        header: {
          title: 'Example Customer Service Case',
          subtitle: 'Case summary',
        },
        sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        { decoratedText: { topLabel: 'Assignee', text: 'Charlie'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // Clicking this button triggers the execution of the function
          // "assign" from the Apps Script project.
          onClick: { action: { function: 'assign'}}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

O app Chat pode atualizar um card de visualização de link quando os usuários interagem com ele, como clicar em um botão no card.

Para atualizar o card, seu app Chat precisa retornar a ação DataActions com um dos seguintes objetos ChatDataActionMarkup:

Para determinar quem enviou a mensagem, use o payload do evento (buttonClickedPayload) para verificar se o remetente (message.sender.type) está definido como HUMAN (usuário) ou BOT (app de chat).

O exemplo a seguir mostra como um app de chat atualiza uma prévia de link sempre que um usuário clica no botão Atribuir a mim atualizando o campo Atribuído a do card e desativando o botão.

App de chat mostrando a prévia de um link com uma versão atualizada de um card anexado a uma mensagem

Node.js

/**
 * Google Cloud Function that handles messages that have links whose
 * URLs match URL patterns configured for link previewing.
 *
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.previewLinks = function previewLinks(req, res) {
  const chatEvent = req.body.chat;

  // Handle MESSAGE events
  if(chatEvent.messagePayload) {
    return res.send(handlePreviewLink(chatEvent.messagePayload.message));
  // Handle button clicks
  } else if(chatEvent.buttonClickedPayload) {
    return res.send(handleCardClick(chatEvent.buttonClickedPayload.message));
  }
};

/**
 * Respond to clicks by assigning user and updating the card that was attached to a
 * message with a previewed link.
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Action response depending on the original message.
 */
function handleCardClick(chatMessage) {
  // Creates the updated card that displays "You" for the assignee
  // and that disables the button.
  //
  // A hard-coded card is used in this example. In a real-life scenario,
  // an actual assign action would be performed before building the card.
  const message = { cardsV2: [{
    cardId: 'attachCard',
    card: {
      header: {
        title: 'Example Customer Service Case',
        subtitle: 'Case basics',
      },
      sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        // The assignee is now "You"
        { decoratedText: { topLabel: 'Assignee', text: 'You'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // The button is now disabled
          disabled: true,
          // Use runtime environment variable set with self URL
          onClick: { action: { function: process.env.BASE_URL }}
        }]}}
      ]}]
    }
  }]};

  // Checks whether the message event originated from a human or a Chat app
  // to return the adequate action response.
  if(chatMessage.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

Apps Script

Este exemplo envia uma mensagem de card retornando um JSON de card. Você também pode usar o serviço de card do Apps Script.

/**
 * Assigns and updates the card that's attached to a message with a
 * previewed link of the pattern "support.example.com".
 *
 * @param {Object} event The event object from the Google Workspace add-on.
 *
 * @return {Object} Action response depending on the message author.
 */
function assign(event) {
  // Creates the updated card that displays "You" for the assignee
  // and that disables the button.
  //
  // A hard-coded card is used in this example. In a real-life scenario,
  // an actual assign action would be performed before building the card.
  const message = { cardsV2: [{
    cardId: 'attachCard',
    card: {
      header: {
        title: 'Example Customer Service Case',
        subtitle: 'Case summary',
      },
      sections: [{ widgets: [
        { decoratedText: { topLabel: 'Case ID', text: 'case123'}},
        // The assignee is now "You"
        { decoratedText: { topLabel: 'Assignee', text: 'You'}},
        { decoratedText: { topLabel: 'Status', text: 'Open'}},
        { decoratedText: { topLabel: 'Subject', text: 'It won\'t turn on...' }},
        { buttonList: { buttons: [{
          text: 'OPEN CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123'
          }},
        }, {
          text: 'RESOLVE CASE',
          onClick: { openLink: {
            url: 'https://support.example.com/orders/case123?resolved=y',
          }},
        }, {
          text: 'ASSIGN TO ME',
          // The button is now disabled
          disabled: true,
          onClick: { action: { function: 'assign'}}
        }]}}
      ]}]
    }
  }]};

  // Use the adequate action response type. It depends on whether the message
  // the preview link card is attached to was created by a human or a Chat app.
  if(event.chat.buttonClickedPayload.message.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

Limitações e considerações

Ao configurar as prévias de links para seu app do Chat, observe estes limites e considerações:

  • Cada app do Chat aceita visualizações de link para até cinco padrões de URL.
  • Os apps de chat mostram a prévia de um link por mensagem. Se uma mensagem tiver vários links que podem ser visualizados, apenas o primeiro será mostrado.
  • Os apps de chat só mostram prévias de links que começam com https://. Portanto, https://support.example.com/cases/ mostra uma prévia, mas support.example.com/cases/ não.
  • A menos que a mensagem inclua outras informações enviadas ao app Chat, como um comando de barra, apenas o URL do link é enviado ao app Chat pelas prévias de link.
  • Se um usuário postar o link, um app do Chat só poderá atualizar o card de visualização do link se os usuários interagirem com ele, por exemplo, clicando em um botão. Não é possível chamar o método update() da API Chat no recurso Message para atualizar a mensagem de um usuário de forma assíncrona.
  • Os apps de chat precisam mostrar prévias dos links para todos no espaço. Por isso, a mensagem precisa omitir o campo privateMessageViewer.

Ao implementar visualizações de link, talvez seja necessário depurar seu app de chat lendo os registros dele. Para ler os registros, acesse o Explorador de registros no console do Google Cloud.