Google Chat 메시지에서 링크 미리보기

사용자가 Google Chat에서 링크를 공유할 때 컨텍스트 전환을 방지하려면 Chat 앱에서 메시지에 카드를 첨부하여 더 많은 정보를 제공하고 사용자가 Google Chat에서 바로 작업을 실행할 수 있도록 하여 링크를 미리 볼 수 있습니다.

Google Chat에서 부가기능은 사용자에게 Google Chat 앱으로 표시됩니다. 자세한 내용은 Google Chat 확장 개요를 참고하세요.

예를 들어 회사의 모든 고객 서비스 상담사와 Case-y라는 Chat 앱이 포함된 Google Chat 스페이스를 생각해 보세요. 상담사는 Chat 스페이스에서 고객 서비스 케이스 링크를 자주 공유하며, 이때마다 동료가 케이스 링크를 열어 담당자, 상태, 제목과 같은 세부정보를 확인해야 합니다. 마찬가지로 케이스의 소유권을 가져오거나 상태를 변경하려는 경우 링크를 열어야 합니다.

링크 미리보기를 사용하면 스페이스의 상주 채팅 앱인 Case-y에서 사용자가 케이스 링크를 공유할 때마다 담당자, 상태, 제목을 보여주는 카드를 첨부할 수 있습니다. 카드의 버튼을 사용하면 상담사가 케이스의 소유권을 가져와 채팅 스트림에서 직접 상태를 변경할 수 있습니다.

사용자가 메시지에 링크를 추가하면 Chat 앱에서 링크를 미리 볼 수 있다는 내용을 알리는 칩이 표시됩니다.

Chat 앱에서 링크 미리보기를 표시할 수 있음을 나타내는 칩

메시지를 전송하면 링크가 Chat 앱으로 전송되고 Chat 앱에서 카드를 생성하여 사용자의 메시지에 첨부합니다.

메일에 카드를 첨부하여 링크를 미리 보는 Chat 앱

카드는 링크와 함께 버튼과 같은 양방향 요소를 포함하여 링크에 관한 추가 정보를 제공합니다. Chat 앱은 버튼 클릭과 같은 사용자 상호작용에 응답하여 첨부된 카드를 업데이트할 수 있습니다.

Chat 앱에서 메시지에 카드를 첨부하여 링크를 미리 보지 못하게 하려면 미리보기 칩에서 아이콘을 클릭하면 됩니다. 사용자는 언제든지 미리보기 삭제를 클릭하여 첨부된 카드를 삭제할 수 있습니다.

기본 요건

Node.js

Google Chat을 확장하는 Google Workspace 부가기능입니다. 빌드하려면 HTTP 빠른 시작을 완료하세요.

Apps Script

Google Chat을 확장하는 Google Workspace 부가기능입니다. 빌드하려면 Apps Script 빠른 시작을 완료하세요.

Chat 앱에서 미리 볼 수 있도록 Google Cloud 콘솔의 Chat 앱 구성 페이지에서 특정 링크(예: example.com, support.example.com, support.example.com/cases/)를 URL 패턴으로 등록합니다.

링크 미리보기 구성 메뉴

  1. Google Cloud 콘솔을 엽니다. 
  2. 'Google Cloud' 옆에 있는 아래쪽 화살표 를 클릭하고 Chat 앱의 프로젝트를 엽니다.
  3. 검색창에 Google Chat API를 입력하고 Google Chat API를 클릭합니다.
  4. 관리 > 구성을 클릭합니다.
  5. 링크 미리보기에서 URL 패턴을 추가하거나 수정합니다.
    1. 새 URL 패턴의 링크 미리보기를 구성하려면 URL 패턴 추가를 클릭합니다.
    2. 기존 URL 패턴의 구성을 수정하려면 아래쪽 화살표 를 클릭합니다.
  6. 호스트 패턴 필드에 URL 패턴의 도메인을 입력합니다. 채팅 앱에서 이 도메인으로 연결되는 링크를 미리 볼 수 있습니다.

    Chat 앱에서 subdomain.example.com와 같은 특정 하위 도메인의 링크를 미리 보려면 하위 도메인을 포함하세요.

    채팅 앱에서 전체 도메인의 링크를 미리 보도록 하려면 하위 도메인으로 별표 (*)가 있는 와일드 카드 문자를 지정합니다. 예를 들어 *.example.comsubdomain.example.comany.number.of.subdomains.example.com와 일치합니다.

  7. 경로 접두사 필드에 호스트 패턴 도메인에 추가할 경로를 입력합니다.

    호스트 패턴 도메인의 모든 URL과 일치시키려면 경로 접두사를 비워 둡니다.

    예를 들어 호스트 패턴이 support.example.com인 경우 support.example.com/cases/에 호스팅된 케이스의 URL과 일치시키려면 cases/을 입력합니다.

  8. 완료를 클릭합니다.

  9. 저장을 클릭합니다.

이제 사용자가 Chat 앱이 포함된 Chat 스페이스의 메시지에 링크 미리보기 URL 패턴과 일치하는 링크를 포함할 때마다 앱에서 링크를 미리 봅니다.

특정 링크의 링크 미리보기를 구성하면 Chat 앱에서 더 많은 정보를 링크에 연결하여 링크를 인식하고 미리 볼 수 있습니다.

Chat 앱이 포함된 Chat 스페이스 내에서 다른 사용자의 메시지에 링크 미리보기 URL 패턴과 일치하는 링크가 포함된 경우 Chat 앱은 MessagePayload와 함께 이벤트 객체를 수신합니다. 페이로드에서 message.matchedUrl 객체에는 사용자가 메시지에 포함한 링크가 포함됩니다.

JSON

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

채팅 앱은 MESSAGE 이벤트 페이로드에 matchedUrl 필드가 있는지 확인하여 미리 본 링크가 포함된 메시지에 정보를 추가할 수 있습니다. Chat 앱은 기본 텍스트 메시지로 답장하거나 카드를 첨부할 수 있습니다.

SMS로 답장하기

기본 응답의 경우 Chat 앱은 링크에 텍스트 메시지로 답장하여 링크를 미리 볼 수 있습니다. 이 예에서는 링크 미리보기 URL 패턴과 일치하는 링크 URL을 반복하는 메시지를 첨부합니다.

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
    }}}}};
  }
}

미리 본 링크에 카드를 첨부하려면 UpdateInlinePreviewAction 유형의 ChatDataActionMarkup 객체와 함께 작업 DataActions를 반환합니다.

다음 예에서는 Chat 앱이 URL 패턴 support.example.com가 포함된 메시지에 미리보기 카드를 추가합니다.

메일에 카드를 첨부하여 링크를 미리 보는 Chat 앱

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

이 예에서는 카드 JSON을 반환하여 카드 메시지를 전송합니다. 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'}}
        }]}}
        ]}]
      }
    }]}}}};
  }
}

Chat 앱은 사용자가 카드의 버튼을 클릭하는 등 카드와 상호작용할 때 링크 미리보기 카드를 업데이트할 수 있습니다.

카드를 업데이트하려면 Chat 앱에서 다음 ChatDataActionMarkup 객체 중 하나와 함께 작업 DataActions를 반환해야 합니다.

메시지를 보낸 사람을 확인하려면 이벤트 페이로드(buttonClickedPayload)를 사용하여 발신자 (message.sender.type)가 HUMAN (사용자) 또는 BOT (Chat 앱)로 설정되어 있는지 확인합니다.

다음 예는 사용자가 Assign to Me 버튼을 클릭할 때마다 Chat 앱이 카드의 Assignee 필드를 업데이트하고 버튼을 사용 중지하여 링크 미리보기를 업데이트하는 방법을 보여줍니다.

메일에 첨부된 업데이트된 버전의 카드가 포함된 링크를 미리 보는 채팅 앱

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

이 예에서는 카드 JSON을 반환하여 카드 메시지를 전송합니다. 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 }}};
  }
}

제한사항 및 고려사항

Chat 앱의 링크 미리보기를 구성할 때 다음 제한사항과 고려사항에 유의하세요.

  • 각 Chat 앱은 최대 5개의 URL 패턴에 대한 링크 미리보기를 지원합니다.
  • Chat 앱은 메시지당 하나의 링크를 미리 봅니다. 단일 메시지에 미리 볼 수 있는 링크가 여러 개 있는 경우 미리 볼 수 있는 첫 번째 링크만 미리 볼 수 있습니다.
  • Chat 앱은 https://로 시작하는 링크만 미리보기하므로 https://support.example.com/cases/는 미리보기를 하지만 support.example.com/cases/는 미리보기를 하지 않습니다.
  • 메시지에 슬래시 명령어와 같이 채팅 앱에 전송되는 다른 정보가 포함되어 있지 않은 한 링크 미리보기에 의해 링크 URL만 채팅 앱에 전송됩니다.
  • 사용자가 링크를 게시하는 경우 채팅 앱은 사용자가 버튼 클릭과 같이 카드와 상호작용할 때만 링크 미리보기 카드를 업데이트할 수 있습니다. Message 리소스에서 Chat API의 update() 메서드를 호출하여 사용자의 메시지를 비동기식으로 업데이트할 수 없습니다.
  • 채팅 앱은 스페이스의 모든 사용자에게 링크를 미리 보여줘야 하므로 메시지에서 privateMessageViewer 필드를 생략해야 합니다.

링크 미리보기를 구현할 때 앱의 로그를 읽어 채팅 앱을 디버그해야 할 수 있습니다. 로그를 읽으려면 Google Cloud 콘솔의 로그 탐색기를 방문하세요.