【LookerStudio】レポートをSlackに日次投稿する方法【GAS】

LookerStudioは無料で使えるBIツールで、GA4やGSCなど各種マーケティングツールを連携させて集計レポートを作っている人は多いと思います。その一方で、LookerStuidoはメールの通知機能はデフォルトであるのですがSlack連携&通知をするための機能は備わっていません。

(LookerはデフォルトでSlack通知機能がありますが、有料ツールで別途契約が必要です)

Google Cloud
Slack統合への配信のスケジューリング  |  Looker  |  Google Cloud Slackアプリ統合へのデータ配信のスケジュールを作成、テスト、保存する方法を理解しましょう。

基本的にメールよりSlackのほうがスマホだと見やすいので、Slackのチャンネル通知がしたいと思い試行錯誤した結果、GASを使って簡単に通知機能が作れたのでこちらにやり方を残しておきます。

完成イメージはこちらです。該当チャンネルにLookerStudioの該当レポートのPDFが送られてきます。PDFのほうがスマホで見やすいのですが、画像にすることもできます。このあたりはお好みで。

目次

通知の仕組み

SlackAppの初期設定とGASのコード作成だけ必要ですが、基本的には各ツールの基本機能で対応が可能です。なにより無料で設定できるのは大きい。作業内容は以下のとおりです。

作業手順
  • LookerStudioの「配信スケジュール」でメール配信を毎日するように設定
  • SlackのAppsを新規作成
  • GoogleAppScript(以下、GAS)でGmailを見に行く
  • 該当のメールが見つかったら、整形してSlackに送信

LookerStudioの「配信スケジュール」でメール配信を毎日するように設定。

作成したレポートの右上の共有から「配信のスケジュール」を選択。

メールの配信の細かい設定ができますが、開始時刻やリピートの間隔は必要に応じて変えてください。
件名とメッセージはデフォルトでもいいのですが、GASで取得しやすいようにカスタマイズで固定の件名にしています。今回は日次のレポートなので「Daily Report」と命名。

隣のタブの「フィルタ」を選択すると、ReportやPageごとにどの期間やディメンションを選択した状態でレポートをメールで送るかを選択できます。今回は毎日前日の数字を送りたいので「昨日」に設定することが大切です。

もし週次であれば「過去7日間」、月次であれば「前月」などにするのが良いかなと思いますがここは目的に応じて変更しましょう。ディメンションもチャネル別やエリア別など設定した項目で絞り込めるのでここも必要なら選択。

設定ができたら左下の「今すぐ送信」を押してメールを確認。内容が問題なければ右下の「保存」を押します。

設定が完了するとスケジュール設定が確認できますが、今回は毎日05:00に前日の数字を集計したレポートをメール送信したいので、設定内容問題なさそうです。

SlackのAppsを新規作成

Slack通知を実装する方法はいろいろとありますが、今回は「GAS×SlackApp」を採用しています。

SlackAppの実装方法はいろんな記事があるのでここでは説明を割愛しますが、このあたりの記事を参考に設定しました。(SlackAppの仕様がちょこちょこ変わるのでまとめるのは他の人にお任せします。。。!)

Qiita
Slackにボットを作成する始めの一歩 - Qiita はじめに職場でSlackを使っているので、定時処理などのお知らせを投稿出来たらいいなぁと思ってやってみた記録。アプリの作成まず始めにSlackにAppsというものを作る。http...

SlackAppが作成されており、「Install App」から「Bot User OAuth Token」が確認できれば問題ありません。
このkeyを使ってSlackに投稿ができるようになります。

「OAuth & Permissions」についても下記がBot Token Scopesについていれば問題ありません。

  • chat:write
  • files:write
  • remote_files:write

送りたいチャンネルに作成したAppを招待しておきます。招待されていないと投稿ができません。

該当のメールが見つかったら、整形してSlackに送信

新規のScriptファイルを作成したら、まずは下記のコードをコピーペーストで貼り付けます。chatGPTに作らせながら修正したので、チグハグ感は拭えないですが動けば良しの精神です。

このGASでは「Gmailを検索→該当があれば添付ファイルを取得→SlackAPIに送信→GmailでStarをつける」という処理をしています。Starをつけることで処理済みという意味を持たせて次回からはスター付きのメールはスキップするようにしています。

一部、設定や変更が必要な箇所があるので解説していきます。

function postAttachmentToSlack() {
  // Slack Bot TokenとチャンネルIDを環境変数から取得
  var slackBotToken =
    PropertiesService.getScriptProperties().getProperty("SLACK_BOT_TOKEN");
  var slackChannelId =
    PropertiesService.getScriptProperties().getProperty("SLACK_CHANNEL_ID");

  // Gmailで未処理のメール(スターが付いていないメール)を検索
  var threads = GmailApp.search(
    'from:looker-studio-noreply@google.com subject:"Daily Report" -is:starred'
  );

  if (threads.length > 0) {
    for (var t = 0; t < threads.length; t++) {
      var messages = threads[t].getMessages();

      for (var m = 0; m < messages.length; m++) {
        var currentMessage = messages[m];
        var attachments = currentMessage.getAttachments();

        if (attachments.length > 0) {
          for (var i = 0; i < attachments.length; i++) {
            var attachment = attachments[i];

            // PDFファイルのみを処理
            if (attachment.getContentType() === "application/pdf") {
              var fileBlob = Utilities.newBlob(
                attachment.getBytes(),
                attachment.getContentType()
              );

              // 本日の日付をファイル名にする (例: 2024-10-07.pdf)
              var today = new Date();
              var formattedDate = Utilities.formatDate(
                today,
                Session.getScriptTimeZone(),
                "yyyy-MM-dd"
              );
              var fileName = formattedDate + ".pdf";

              // ファイルをSlackにアップロード
              uploadFileToSlack(
                fileName,
                fileBlob,
                slackBotToken,
                slackChannelId
              );

              // Looker StudioのURLを投稿
              var message =
                "Looker Studio Report URL:\nhttps://lookerstudio.google.com/u/0/reporting/085e7a69-2827-4e25-8530-cf468e87e26b/page/p_3nkl0kaold";
              UrlFetchApp.fetch("https://slack.com/api/chat.postMessage", {
                method: "post",
                headers: {
                  Authorization: "Bearer " + slackBotToken,
                  "Content-Type": "application/json",
                },
                payload: JSON.stringify({
                  channel: slackChannelId,
                  text: message,
                }),
              });
            }

            // メールにスターを付ける(次回以降処理しないように)
            currentMessage.star();
          }
        } else {
          Logger.log("添付ファイルが見つかりませんでした。");
        }
      }
    }
  } else {
    Logger.log("処理すべきメールが見つかりませんでした。");
  }
}

/**
 * Slackにファイルをアップロードする関数
 * @param {string} name - ファイル名
 * @param {Blob} fileBlob - アップロードするファイルのBlob
 * @param {string} token - SlackのAPIトークン
 * @param {string} channel - ファイルを投稿するチャンネルID
 */
function uploadFileToSlack(name, fileBlob, token, channel) {
  // 1. ファイルのサイズを取得
  var fileSize = fileBlob.getBytes().length;

  // 2. files.getUploadURLExternal APIを呼び出してURLとファイルIDを取得
  var uploadUrlResponse = UrlFetchApp.fetch(
    `https://slack.com/api/files.getUploadURLExternal?filename=${name}&length=${fileSize}`,
    {
      method: "get",
      headers: {
        Authorization: "Bearer " + token,
      },
    }
  );

  var uploadUrlJson = JSON.parse(uploadUrlResponse.getContentText());
  if (!uploadUrlJson.ok) {
    throw new Error("Failed to get upload URL: " + uploadUrlJson.error);
  }

  var uploadUrl = uploadUrlJson.upload_url;
  var fileId = uploadUrlJson.file_id;

  Logger.log("Upload URL: " + uploadUrl);
  Logger.log("File ID: " + fileId);

  // 3. 取得したURLにファイルをアップロード
  var uploadResponse = UrlFetchApp.fetch(uploadUrl, {
    method: "post",
    payload: fileBlob.getBytes(), // ファイルのバイトデータを送信
    headers: {
      "Content-Type": fileBlob.getContentType(), // ファイルのMIMEタイプを設定
    },
    muteHttpExceptions: true,
  });

  if (uploadResponse.getResponseCode() !== 200) {
    throw new Error(
      "Failed to upload file: " + uploadResponse.getContentText()
    );
  }

  // 4. files.completeUploadExternal APIにファイルIDとオプション引数を送信してアップロードを完了
  var completeUploadPayload = {
    files: [{ id: fileId, title: name }],
  };

  if (channel) {
    completeUploadPayload.channel_id = channel;
  }

  var completeUploadResponse = UrlFetchApp.fetch(
    "https://slack.com/api/files.completeUploadExternal",
    {
      method: "post",
      headers: {
        Authorization: "Bearer " + token,
        "Content-Type": "application/json",
      },
      payload: JSON.stringify(completeUploadPayload),
    }
  );

  var completeUploadJson = JSON.parse(completeUploadResponse.getContentText());
  if (!completeUploadJson.ok) {
    throw new Error("Failed to complete upload: " + completeUploadJson.error);
  }

  Logger.log(completeUploadJson);
  return completeUploadJson;
}

環境変数の設定

  // Slack Bot TokenとチャンネルIDを環境変数から取得
  var slackBotToken =
    PropertiesService.getScriptProperties().getProperty("SLACK_BOT_TOKEN");
  var slackChannelId =
    PropertiesService.getScriptProperties().getProperty("SLACK_CHANNEL_ID");

slackBotTokenとslackChannelIdはベタ書きですと安全性が低いため、環境変数で取得するようにしています。「スクリプトプロパティ」からそれぞれの値を設定します。

  • SLACK_BOT_TOKEN
  • SLACK_CHANNEL_ID

BOT_TOKEは先程のAppの画面からcopy、チャンネルIDがわからない場合はこちらを参照に取得ができます。

あわせて読みたい
SlackのチャンネルIDの確認方法 | Yoomヘルプセンター SlackのチャンネルIDの確認方法について説明します

Gmailの検索

  // Gmailで未処理のメール(スターが付いていないメール)を検索
  var threads = GmailApp.search(
    'from:looker-studio-noreply@google.com subject:"Daily Report" -is:starred'
  );

Gmailを検索する際に件名を見るようにしているのですが、 subject:"Daily Report" の値の部分はLookerStudioでメール配信をする時に設定した件名に変更するようにしてください。

逆に件名がレポートを送るメールごとにユニークでないとここで誤作動が起きてしまいます。

実行してみる

postAttachmentToSlack の変数を実行すると初回は認証が出ると思いますがそのまま承認、もう一度押して問題なく動けばSlackに投稿されると思います。

Logger.logにuploadされたURLなどが出てきたら成功です。「処理すべきメールが見つかりませんでした。」と出てきた場合は、Gmail検索がうまくいっていないので GmailApp.search の部分を色々と変更しながら確認してみてください。

トリガー設定

動くことを確認したら定期実行するために「トリガー」を設定します。

今回は「毎日8時からの出勤中に確認できるようにしたい」ため、日付ベースで午前7~8時の間にSlack通知されるように設定しました。このあたりは状況に応じて通知タイミングが頻度は調整してください。

注意事項

今回は2025 年 3 月にSlackがfiles.upload API 廃止をしたため、添付ファイルを送る仕様やAPIが変更されていてそこに苦戦しました。。。Slackの仕様はちょこちょこ変わるのでもしSlackAPIでエラーが頻発する場合は最新のドキュメントを参考に修正してみてください。

まとめ

「LookerStudio×Slack」を実装することで、毎日自分が見るべき数字を通勤中のスマホから確認したり、毎週見るべきKPIをチームメンバーに共有する手間から開放されます。LookerStudioを使って自動化を更に進める一手として、記事が参考になれば幸いです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次