リンクをプレビュー

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

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

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

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

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

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

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

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

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

前提条件

Node.js

インタラクション イベントを受信して応答する Google Chat 用アプリ。HTTP サービスを使用してインタラクティブな Chat 用アプリを作成するには、このクイックスタートを完了してください。

Python

インタラクション イベントを受信して応答する Google Chat 用アプリ。HTTP サービスを使用してインタラクティブな Chat 用アプリを作成するには、このクイックスタートを完了してください。

Java

インタラクション イベントを受信して応答する Google Chat 用アプリ。HTTP サービスを使用してインタラクティブな Chat 用アプリを作成するには、このクイックスタートを完了してください。

Apps Script

インタラクション イベントを受信して応答する Google Chat 用アプリ。Apps Script で双方向の Chat 用アプリを作成するには、このクイック スタートを完了してください。

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 用アプリは MESSAGE インタラクション イベントを受け取ります。インタラクション イベントの JSON ペイロードには matchedUrl フィールドが含まれています。

JSON

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

Chat 用アプリは、MESSAGE イベント ペイロードに matchedUrl フィールドが存在するかどうかを確認することで、プレビューされたリンクを含むメッセージに情報を追加できます。Chat 用アプリは、基本的なテキスト メッセージで返信するか、カードを添付できます。

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

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

Node.js

node/preview-link/index.js
// Reply with a text message for URLs of the subdomain "text"
if (event.message.matchedUrl.url.includes("text.example.com")) {
  return {
    text: 'event.message.matchedUrl.url: ' + event.message.matchedUrl.url
  };
}

Python

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

Java

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Reply with a text message for URLs of the subdomain "text"
if (event.at("/message/matchedUrl/url").asText().contains("text.example.com")) {
  return new Message().setText("event.message.matchedUrl.url: " +
    event.at("/message/matchedUrl/url").asText());
}

Apps Script

apps-script/preview-link/preview-link.gs
// Reply with a text message for URLs of the subdomain "text"
if (event.message.matchedUrl.url.includes("text.example.com")) {
  return {
    text: 'event.message.matchedUrl.url: ' + event.message.matchedUrl.url
  };
}

プレビューされたリンクにカードを添付するには、タイプ UPDATE_USER_MESSAGE_CARDSActionResponse を返します。この例では、基本カードを添付します。

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

Node.js

node/preview-link/index.js
// Attach a card to the message for URLs of the subdomain "support"
if (event.message.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 {
    actionResponse: { type: 'UPDATE_USER_MESSAGE_CARDS' },
    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: 'assign'}}
          }]}}
        ]}]
      }
    }]
  };
}

Python

python/preview-link/main.py
# Attach a card to the message for URLs of the subdomain "support"
if 'support.example.com' in event.get('message').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 {
    'actionResponse': { 'type': 'UPDATE_USER_MESSAGE_CARDS' },
    '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': 'assign'}}
          }]}}
        ]}]
      }
    }]
  }

Java

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Attach a card to the message for URLs of the subdomain "support"
if (event.at("/message/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.
  return new Message()
    .setActionResponse(new ActionResponse()
      .setType("UPDATE_USER_MESSAGE_CARDS"))
    .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")),
          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("assign")))))))))))));
}

Apps Script

この例では、カード JSON を返すことでカード メッセージを送信します。Apps Script カードサービスを使用することもできます。

apps-script/preview-link/preview-link.gs
// Attach a card to the message for URLs of the subdomain "support"
if (event.message.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 {
    actionResponse: { type: 'UPDATE_USER_MESSAGE_CARDS' },
    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: 'assign'}}
          }]}}
        ]}]
      }
    }]
  };
}

ユーザーがリンク プレビュー カードを操作したとき(カードのボタンをクリックしたときなど)に、Chat 用アプリでリンク プレビュー カードを更新できます。

カードを更新するには、Chat 用アプリで CARD_CLICKED インタラクション イベントを処理し、リンク プレビューを含むメッセージを送信したユーザーに基づいて actionResponse を返す必要があります。

  • ユーザーがメッセージを送信した場合は、actionResponse.typeUPDATE_USER_MESSAGE_CARDS に設定します。
  • Chat 用アプリがメッセージを送信した場合は、actionResponse.typeUPDATE_MESSAGE に設定します。

メッセージの送信者を特定するには、インタラクション イベントの message.sender.type フィールドを使用して、送信者が HUMAN ユーザーか BOT かを確認します。

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

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

Node.js

node/preview-link/index.js
/**
 * Updates a card that was attached to a message with a previewed link.
 *
 * @param {Object} event The event object from Chat.
 *
 * @return {Object} Response from the Chat app. Either a new card attached to
 * the message with the previewed link, or an update to an existing card.
 */
function onCardClick(event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.action.actionMethodName === 'assign') {
    // 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.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    const actionResponseType = event.message.sender.type === 'HUMAN' ?
      'UPDATE_USER_MESSAGE_CARDS' :
      'UPDATE_MESSAGE';

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return {
      actionResponse: { type: actionResponseType },
      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: 'assign'}}
            }]}}
          ]}]
        }
      }]
    };
  }
}

Python

python/preview-link/main.py
def on_card_click(event: dict) -> dict:
  """Updates a card that was attached to a message with a previewed link."""
  # To respond to the correct button, checks the button's actionMethodName.
  if 'assign' == event.get('action').get('actionMethodName'):
    # 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.

    # Checks whether the message event originated from a human or a Chat app
    # and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    # "UPDATE_MESSAGE" if Chat app.
    actionResponseType = 'UPDATE_USER_MESSAGE_CARDS' if \
      event.get('message').get('sender').get('type') == 'HUMAN' else \
      'UPDATE_MESSAGE'

    # Returns the updated card that displays "You" for the assignee
    # and that disables the button.
    return {
      'actionResponse': { 'type': actionResponseType },
      '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': 'assign'}}
            }]}}
          ]}]
        }
      }]
    }

Java

java/preview-link/src/main/java/com/google/chat/preview/App.java
// Updates a card that was attached to a message with a previewed link.
Message onCardClick(JsonNode event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.at("/action/actionMethodName").asText().equals("assign")) {
    // 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.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    String actionResponseType =
      event.at("/message/sender/type").asText().equals("HUMAN")
      ? "UPDATE_USER_MESSAGE_CARDS" : "UPDATE_MESSAGE";

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return new Message()
    .setActionResponse(new ActionResponse()
      .setType(actionResponseType))
    .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")),
          new GoogleAppsCardV1Widget().setDecoratedText(new GoogleAppsCardV1DecoratedText()
            .setTopLabel("Assignee")
            // The assignee is now "You"
            .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("assign")))))))))))));
  }
  return null;
}

Apps Script

この例では、カード JSON を返すことでカード メッセージを送信します。Apps Script カードサービスを使用することもできます。

apps-script/preview-link/preview-link.gs
/**
 * Updates a card that was attached to a message with a previewed link.
 *
 * @param {Object} event The event object from Chat.
 *
 * @return {Object} Response from the Chat app. Either a new card attached to
 * the message with the previewed link, or an update to an existing card.
 */
function onCardClick(event) {
  // To respond to the correct button, checks the button's actionMethodName.
  if (event.action.actionMethodName === 'assign') {
    // 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.

    // Checks whether the message event originated from a human or a Chat app
    // and sets actionResponse.type to "UPDATE_USER_MESSAGE_CARDS if human or
    // "UPDATE_MESSAGE" if Chat app.
    const actionResponseType = event.message.sender.type === 'HUMAN' ?
      'UPDATE_USER_MESSAGE_CARDS' :
      'UPDATE_MESSAGE';

    // Returns the updated card that displays "You" for the assignee
    // and that disables the button.
    return {
      actionResponse: { type: actionResponseType },
      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: 'assign'}}
            }]}}
          ]}]
        }
      }]
    };
  }
}

制限事項と考慮事項

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 コンソールの [ログ エクスプローラ] にアクセスします。