Google Chat メッセージのリンクをプレビューする

ユーザーが Google Chat でリンクを共有する際にコンテキストの切り替えが発生しないように、Chat 用アプリでは、メッセージにカードを添付してリンクをプレビューできます。カードには詳細情報が表示され、ユーザーは Google Chat から直接操作できます。

たとえば、会社のすべてのカスタマー サービス エージェントと Case-y という Chat 用アプリが含まれる Google Chat スペースを考えてみましょう。エージェントは Chat スペースでカスタマー サービス ケースへのリンクを頻繁に共有しますが、そのたびに同僚はケースリンクを開いて、割り当て先、ステータス、件名などの詳細を確認する必要があります。同様に、ケースの所有権を取得したり、ステータスを変更したりする場合は、リンクを開く必要があります。

リンクのプレビュー機能を使用すると、スペースの常駐 Chat 用アプリである Case-y は、ケースのリンクが共有されるたびに、割り当て先、ステータス、件名を示すカードを添付できます。カードのボタンを使用すると、エージェントはチャット ストリームから直接ケースの所有権を取得し、ステータスを変更できます。

メッセージにリンクを追加すると、Chat 用アプリがリンクをプレビューする可能性があることを知らせるチップが表示されます。

Chat 用アプリがリンクをプレビューする可能性があることを示すチップ

メッセージを送信すると、リンクが Chat 用アプリに送信され、アプリがカードを生成してユーザーのメッセージに添付します。

メッセージにカードを添付してリンクをプレビューする Chat 用アプリ

リンクの横に、ボタンなどのインタラクティブな要素を含むリンクに関する追加情報がカードに表示されます。Chat 用アプリは、ボタンクリックなどのユーザー操作に応じて、添付されたカードを更新できます。

メッセージにカードを添付して Chat 用アプリでリンクをプレビューしたくない場合は、プレビュー チップの をクリックしてプレビューを無効にできます。ユーザーは、[プレビューを削除] をクリックして、添付したカードをいつでも削除できます。

前提条件

HTTP

Google Chat を拡張する Google Workspace アドオン。作成するには、HTTP クイックスタートを完了します。

Apps Script

Google Chat を拡張する Google Workspace アドオン。作成するには、Apps Script のクイックスタートを完了します。

example.comsupport.example.comsupport.example.com/cases/ などの特定のリンクを、Google Cloud コンソールの Chat 用アプリの設定ページで URL パターンとして登録します。これにより、Chat 用アプリでリンクをプレビューできるようになります。

リンク プレビューの構成メニュー

  1. Google Cloud コンソールを開きます。
  2. [Google Cloud] の横にある下矢印 をクリックして、Chat 用アプリのプロジェクトを開きます。
  3. 検索フィールドに「Google Chat API」と入力し、[Google Chat API] をクリックします。
  4. [Manage] > [Configuration] をクリックします。
  5. [リンク プレビュー] で、URL パターンを追加または編集します。
    1. 新しい URL パターンのリンクのプレビューを設定するには、[URL パターンを追加] をクリックします。
    2. 既存の URL パターンの構成を編集するには、下矢印 をクリックします。
  6. [ホスト パターン] フィールドに、URL パターンのドメインを入力します。Chat アプリでこのドメインへのリンクがプレビューされます。

    Chat 用アプリで subdomain.example.com などの特定のサブドメインのリンクをプレビューするには、サブドメインを含めます。

    ドメイン全体のリンクをチャットアプリでプレビューするには、サブドメインとしてアスタリスク(*)を含むワイルドカード文字を指定します。たとえば、*.example.comsubdomain.example.com および any.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 用アプリはプレビューされたリンクを含むメッセージに情報を追加できます。Chat 用アプリは、基本的なテキスト メッセージで返信するか、カードを添付できます。

テキスト メッセージで返信する

基本的なレスポンスの場合、Chat 用アプリはリンクにテキスト メッセージで返信することで、リンクをプレビューできます。この例では、リンク プレビューの URL パターンに一致するリンク URL を繰り返すメッセージを添付します。

Node.js

node/chat/preview-link/index.js
// 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
  }}}}};
}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Python

python/chat/preview-link/main.py
# Reply with a text message for URLs of the subdomain "text"
if "text.example.com" in chatMessage.get('matchedUrl').get('url'):
  return { 'hostAppDataAction': { 'chatDataAction': { 'createMessageAction': { 'message': {
    'text': 'event.chat.messagePayload.message.matchedUrl.url: ' + chatMessage.get('matchedUrl').get('url')
  }}}}}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Java

java/chat/preview-link/src/main/java/com/google/chat/previewLink/App.java
// Reply with a text message for URLs of the subdomain "text"
if (chatMessage.at("/matchedUrl/url").asText().contains("text.example.com")) {
  return new GenericJson() {{
    put("hostAppDataAction", new GenericJson() {{
      put("chatDataAction", new GenericJson() {{
        put("createMessageAction", new GenericJson() {{
          put("message", new GenericJson() {{
            put("text", "event.chat.messagePayload.message.matchedUrl.url: " + chatMessage.at("/matchedUrl/url").asText());
          }});
        }});
      }});
    }});
  }};
}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Apps Script

apps-script/chat/preview-link/preview-link.gs
// 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
  }}}}};
}

プレビューされたリンクにカードを添付するには、タイプ UpdateInlinePreviewActionChatDataActionMarkup オブジェクトを含むアクション DataActions を返します。

次の例では、Chat 用アプリが URL パターン support.example.com を含むメッセージにプレビュー カードを追加します。

メッセージにカードを添付してリンクをプレビューする Chat 用アプリ

Node.js

node/chat/preview-link/index.js
// 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',
        onClick: { action: { function: FUNCTION_URL }}
      }]}}
      ]}]
    }
  }]}}}};
}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Python

python/chat/preview-link/main.py
# Attach a card to the message for URLs of the subdomain "support"
if "support.example.com" in chatMessage.get('matchedUrl').get('url'):
  # 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',
        'onClick': { 'action': { 'function': FUNCTION_URL }}
      }]}}
      ]}]
    }
  }]}}}}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Java

java/chat/preview-link/src/main/java/com/google/chat/previewLink/App.java
// Attach a card to the message for URLs of the subdomain "support"
if (chatMessage.at("/matchedUrl/url").asText().contains("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.
  CardWithId cardV2 = new CardWithId()
    .setCardId("attachCard")
    .setCard(new GoogleAppsCardV1Card()
      .setHeader(new GoogleAppsCardV1CardHeader()
        .setTitle("Example Customer Service Case")
        .setSubtitle("Case basics"))
      .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Case ID")
          .setText("case123")),
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Assignee")
          .setText("Charlie")),
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Status")
          .setText("Open")),
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Subject")
          .setText("It won't turn on...")),
        new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList()
          .setButtons(List.of(
            new GoogleAppsCardV1Button()
              .setText("OPEN CASE")
            .setOnClick(new GoogleAppsCardV1OnClick()
                .setOpenLink(new GoogleAppsCardV1OpenLink()
                  .setUrl("https://support.example.com/orders/case123"))),
            new GoogleAppsCardV1Button()
              .setText("RESOLVE CASE")
            .setOnClick(new GoogleAppsCardV1OnClick()
                .setOpenLink(new GoogleAppsCardV1OpenLink()
                  .setUrl("https://support.example.com/orders/case123?resolved=y"))),
            new GoogleAppsCardV1Button()
              .setText("ASSIGN TO ME")
              .setOnClick(new GoogleAppsCardV1OnClick()
                .setAction(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL)))
          ))
        )
      ))))
    );

  return new GenericJson() {{
    put("hostAppDataAction", new GenericJson() {{
      put("chatDataAction", new GenericJson() {{
        put("updateInlinePreviewAction", new GenericJson() {{
          put("cardsV2", List.of(cardV2));
        }});
      }});
    }});
  }};
}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Apps Script

apps-script/chat/preview-link/preview-link.gs
// 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 を返す必要があります。

  • ユーザーがメッセージを送信した場合は、UpdateMessageAction オブジェクトを返します。
  • Chat 用アプリがメッセージを送信した場合は、UpdateInlinePreviewAction オブジェクトを返します。

メッセージの送信者を特定するには、イベント ペイロード(buttonClickedPayload)を使用して、送信者(message.sender.type)が HUMAN(ユーザー)または BOT(Chat 用アプリ)に設定されているかどうかを確認します。

次の例は、ユーザーが [Assign to Me](自分に割り当てる)ボタンをクリックするたびに、Chat 用アプリがリンクのプレビューを更新する方法を示しています。この例では、カードの [Assignee](割り当て先)フィールドを更新し、ボタンを無効にしています。

メッセージに添付されたカードの更新バージョンを含むリンクをプレビューするチャットアプリ

Node.js

node/chat/preview-link/index.js
/**
 * Respond to clicks by assigning and updating the card that's attached to a
 * message previewed link of the pattern "support.example.com".
 *
 * @param {Object} chatMessage The chat message object from Google Workspace Add On event.
 * @return {Object} Action response depending on the message author.
 */
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,
          onClick: { action: { function: FUNCTION_URL }}
        }]}}
      ]}]
    }
  }]};

  // 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(chatMessage.sender.type === 'HUMAN') {
    return { hostAppDataAction: { chatDataAction: { updateInlinePreviewAction: message }}};
  } else {
    return { hostAppDataAction: { chatDataAction: { updateMessageAction: message }}};
  }
}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Python

python/chat/preview-link/main.py
def handle_card_click(chatMessage: dict) -> dict:
  """Respond to clicks by assigning and updating the card that's attached to a
  message previewed link of the pattern "support.example.com".

  - Reply with text messages that echo "text.example.com" link URLs in messages.
  - Attach cards to messages with "support.example.com" link URLs.

  Args:
      chatMessage (Mapping[str, Any]): The chat message object from Google Workspace Add On event.

  Returns:
      Mapping[str, Any]: Action response depending on the message author.
  """
  # 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.
  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,
        'onClick': { 'action': { 'function': FUNCTION_URL }}
      }]}}
      ]}]
    }
  }]}

  # 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 chatMessage.get('sender').get('type') == 'HUMAN':
    return { 'hostAppDataAction': { 'chatDataAction': { 'updateInlinePreviewAction': message }}}
  else:
    return { 'hostAppDataAction': { 'chatDataAction': { 'updateMessageAction': message }}}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Java

java/chat/preview-link/src/main/java/com/google/chat/previewLink/App.java
/**
 * Respond to clicks by assigning and updating the card that's attached to a
 * message previewed link of the pattern "support.example.com".
 *
 * @param chatMessage The chat message object from Google Workspace Add On event.
 * @return Action response depending on the message author.
 */
GenericJson handleCardClick(JsonNode 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.
  Message message = new Message().setCardsV2(List.of(new CardWithId()
    .setCardId("attachCard")
    .setCard(new GoogleAppsCardV1Card()
      .setHeader(new GoogleAppsCardV1CardHeader()
        .setTitle("Example Customer Service Case")
        .setSubtitle("Case basics"))
      .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Case ID")
          .setText("case123")),
        // The assignee is now "You"
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Assignee")
          .setText("You")),
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Status")
          .setText("Open")),
        new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
          .setTopLabel("Subject")
          .setText("It won't turn on...")),
        new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList()
          .setButtons(List.of(
            new GoogleAppsCardV1Button()
              .setText("OPEN CASE")
              .setOnClick(new GoogleAppsCardV1OnClick()
                .setOpenLink(new GoogleAppsCardV1OpenLink()
                  .setUrl("https://support.example.com/orders/case123"))),
            new GoogleAppsCardV1Button()
              .setText("RESOLVE CASE")
              .setOnClick(new GoogleAppsCardV1OnClick()
                .setOpenLink(new GoogleAppsCardV1OpenLink()
                  .setUrl("https://support.example.com/orders/case123?resolved=y"))),
            new GoogleAppsCardV1Button()
              .setText("ASSIGN TO ME")
              // The button is now disabled
              .setDisabled(true)
              .setOnClick(new GoogleAppsCardV1OnClick()
                .setAction(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL)))
          ))
        )
      ))))
    )
  ));

  // 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("HUMAN".equals(chatMessage.at("/sender/type").asText())) {
    return new GenericJson() {{
      put("hostAppDataAction", new GenericJson() {{
        put("chatDataAction", new GenericJson() {{
          put("updateInlinePreviewAction", message);
        }});
      }});
    }};
  } else {
    return new GenericJson() {{
      put("hostAppDataAction", new GenericJson() {{
        put("chatDataAction", new GenericJson() {{
          put("updateMessageAction", message);
        }});
      }});
    }};
  }
}

FUNCTION_URL は、ボタンクリックを処理する HTTP エンドポイントに置き換えます。

Apps Script

apps-script/chat/preview-link/preview-link.gs
/**
 * 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 アプリでは、メッセージごとに 1 つのリンクがプレビューされます。1 つのメッセージに複数のプレビュー可能なリンクが含まれている場合、最初のプレビュー可能なリンクのみがプレビューされます。
  • チャットアプリは https:// で始まるリンクのみをプレビューするため、https://support.example.com/cases/ はプレビューされますが、support.example.com/cases/ はプレビューされません。
  • メッセージに スラッシュ コマンドなど、Chat 用アプリに送信される他の情報が含まれていない限り、リンク プレビューによって Chat 用アプリに送信されるのはリンクの URL のみです。
  • ユーザーがリンクを投稿した場合、Chat 用アプリがリンクのプレビュー カードを更新できるのは、ユーザーがボタンのクリックなどによってカードを操作した場合のみです。Chat API の Message リソースで update() メソッドを呼び出して、ユーザーのメッセージを非同期で更新することはできません。
  • Chat 用アプリはスペース内のすべてのユーザーに対してリンクをプレビューする必要があるため、メッセージで privateMessageViewer フィールドを省略する必要があります。

リンク プレビューを実装する際に、アプリのログを読んで Chat 用アプリをデバッグする必要がある場合があります。ログを読み取るには、Google Cloud コンソールの [ログ エクスプローラ] にアクセスします。