ZhgChg.Li

GA4 自動數據通知機器人|3 步驟用 Google Apps Script 串接 Telegram Bot

針對希望即時掌握網站數據的使用者,教你用 3 步驟打造免費 GA4 自動通知機器人,結合 Google Apps Script 與 Telegram Bot,定時推送近 7 天流量與熱門頁面,減少人工查詢時間,提升數據監控效率。

GA4 自動數據通知機器人|3 步驟用 Google Apps Script 串接 Telegram Bot

簡單 3 步驟 — 打造免費 GA4 自動數據通知機器人

使用 Google Apps Script 完成 RPA,自行串接 GA4 + Telegram Bot 數據通知機器人

Photo by BoliviaInteligente

Photo by BoliviaInteligente

前言

大約從 2020 年開始就自己在摸索使用手邊工具實現 RPA,從一開始只是為了自動化個人例行任務,到後來工作也加入了規模更大型的組織,時常會遇到跨團隊或仰賴人與人的任務、甚至是重複性任務,才發現 RPA 自動化的效益所在。

舉例來說:某個重複任務每個月會發生 10 次,每次需花費 30 分鐘處理,有 60 人會遇到,每年團隊等於消耗 3,600 小時在這上面,如果能投資 100 小時開發成自動化,後續解放出來的時間,就能投入在更有價值的工作上;實際等於 3,600 浪費的工時+3,600 更值得投資的產出。

詳細可參考我之前的文章:

其他做過的 RPA:

從後台數據看之前蠻多文章有被 ChatGPT 或各種 GenAI 服務收錄,間接的幫助了許多非工程背景但也想嘗試使用 RPA 解決問題的朋友,因此我仍會持續分享自己生活或工作上遇到的 RPA 場景跟我的解決方案與大家分享 — ZRealm Robotic Process Automation

工商時間

如果您與您的團隊有自動化工具、流程串接需求,不論是 Slack App 開發、Notion、Asana、Google Sheet、Google Form、GA 數據,各種串接需求,歡迎與我 聯絡開發

本篇 Google Analytics 4 x Telegram Bot

這次要介紹的串接場景是接續上一篇「 10 分鐘快速移轉 Line Notify 到 Telegram Bot 通知 」時想到我的 Medium 備份站「 zhgchg.li 」一直都沒有關注他的 GA4 網站數據,想說好像可以多做一個通知機器人,每日傳送過去 7 天的網站數據到指定的 Telegram Channel 讓我知道。

本篇只是小品,如果要做完整的自動化數據報表請參考之前的文章「 使用 Google Apps Script 實現每日數據報表 RPA 自動化 」另外之前也曾串過 GA4 撈取 App Crash-free rate 可參考此篇文章「 Crashlytics + Google Analytics 自動查詢 App Crash-Free Users Rate 」。

  • Google Apps Script 免費限制、詳細使用、部署、功能介紹本篇不會再多介紹,請參考 之前文章
  • Telegram Bot 創建、使用本篇也不會再多介紹,同樣請參考 之前文章

成果

先上最終效果,Google Apps Script 每日下午 12–13 點之間會自動去撈取我想要的 Google Analytics 4 網站數據並組合成訊息透過 Telegram Bot 傳送到我的 Telegram Channel,我可以快速檢閱近 7 天網站數據。

我想要觀測的數據是:

  • 近 7 天 7daysAgo ~ today 總瀏覽數 screenPageViews
  • 活躍使用者數 active7DayUsers
  • 新使用者數 newUsers
  • Top 10 瀏覽頁面 screenPageViews / pageTitle
  • 新使用者最初來源媒介 newUsers / firstUserSourceMedium

實際可依照你自己的需求使用 GA Dev Tools 產生調整。

Step 1. 使用 GA4 Query Explorer 官方工具 產生數據報表查詢參數

首先,我們需要使用 GA4 Query Explorer 官方提供的工具產生我們需要的查詢數據報表參數:

  1. Select Property: 記下你的 property 編號 property 編號稍後撰寫 Google Apps Script 會使用。
  2. start date, end date: 報表開始~結束的日期範圍,可使用 YYYY-MM-DDyesterday , today , NdaysAgo 魔術變數。
  3. metrics: 選擇你想要查詢的指標
  4. dimensions: 選擇你想要查詢的維度
  5. metric aggregations: 數據合併計算規則

這邊以我的場景為例:

  1. property 編號: 318495208
  2. start_date: 7daysAgo
  3. end_date: yesterday 因 GA 數據報表會延遲,查詢前一天~七天最準確。
  4. metric aggregations: total

其他 filter, limit 可依照自己需求設定:

filter 我用不到留空;limit 我輸入 10,因為我只想知道 Top 10。

點擊「MAKE REQUEST」產生對應的數據報表查詢參數及結果:

記下以下請求參數,稍後撰寫 Google Apps Script 會使用:

{
  "dimensions": [
    {
      "name": "pageTitle"
    }
  ],
  "metrics": [
    {
      "name": "screenPageViews"
    }
  ],
  "dateRanges": [
    {
      "startDate": "7daysAgo",
      "endDate": "yesterday"
    }
  ],
  "limit": "10",
  "metricAggregations": [
    "TOTAL"
  ]
}

結果:

  • 與 GA 上的數據比較是否正確,正確相符 ✅✅✅

Step 2. 建立 Google Apps Script & 使用 Google Analytics Data API 查詢資料

  • 前往 https://script.google.com/home
  • 建立新專案,命名專案名稱
  • 點擊「服務」->「+」新增服務
  • 選擇「Google Analytics Data API」
  • 點擊「新增」

貼上 Google Analytics Data API 查詢程式碼並組合:

將前面步驟產生的報表查詢數據參數:

{
  "dimensions": [
    {
      "name": "pageTitle"
    }
  ],
  "metrics": [
    {
      "name": "screenPageViews"
    }
  ],
  "dateRanges": [
    {
      "startDate": "7daysAgo",
      "endDate": "yesterday"
    }
  ],
  "limit": "10",
  "metricAggregations": [
    "TOTAL"
  ]
}

轉換成程式:

function execute() {
  Logger.log(JSON.stringify(fetchScreenPageViews("318495208")));
}

// 拆成獨立方法,方便日後重複使用...
// 預設 startDate=7daysAgo, endDate=yesterday
// 其他用法:
// e.g. fetchScreenPageViews("1111". "3daysAgo", "yesterday")
// e.g. fetchScreenPageViews("2222". "yesterday", "today")
function fetchScreenPageViews(propertyId, startDate = "7daysAgo", endDate = "yesterday") {
  const screenPageViewsMetric = AnalyticsData.newMetric();
  screenPageViewsMetric.name = "screenPageViews";

  const dateRange = AnalyticsData.newDateRange();
  dateRange.startDate = startDate;
  dateRange.endDate = endDate;

  const pageTitleDimension = AnalyticsData.newDimension();
  pageTitleDimension.name = "pageTitle";

  const request = AnalyticsData.newRunReportRequest();
  request.dimensions = [pageTitleDimension];
  request.metrics = [screenPageViewsMetric];
  request.dateRanges = dateRange;

  request.limit = 10;
  request.metricAggregations = "TOTAL";

  return AnalyticsData.Properties.runReport(request, "properties/" + propertyId);
}

程式碼解析:

// metric 指標,可以是多個,請分開宣告...
const screenPageViewsMetric = AnalyticsData.newMetric();
screenPageViewsMetric.name = "screenPageViews";

// 例如另一個 active1DayUsers:
const active1DayUsersMetric = AnalyticsData.newMetric();
active1DayUsersMetric.name = "active1DayUsers";

// 宣告日期範圍
const dateRange = AnalyticsData.newDateRange();
dateRange.startDate = startDate;
dateRange.endDate = endDate;

// dimension 維度,可以是多個,請分開宣告...
const pageTitleDimension = AnalyticsData.newDimension();
pageTitleDimension.name = "pageTitle";

// 例如另一個 dimension:
const firstUserSourceMediumDimension = AnalyticsData.newDimension();
firstUserSourceMediumDimension.name = "firstUserSourceMedium";

//

// 產生 Request 物件
const request = AnalyticsData.newRunReportRequest();
request.metrics = [active1DayUsersMetric, active1DayUsersMetric]; // 多個就都帶入...
request.dimensions = [pageTitleDimension, firstUserSourceMediumDimension]; // 多個就都帶入...

request.dateRanges = dateRange;

// 只需要前 10 筆資料 (Top 10)
request.limit = 10;

// 設定數據合併計算邏輯:Total (SUM)
request.metricAggregations = "TOTAL";

// 產生查詢結果
return AnalyticsData.Properties.runReport(request, "properties/" + propertyId).rows;

第一次執行,會需要授權(日後若程式碼有新增需要的權限也會要重新認證一次):

實際上就是授權 Google Apps Script 日後使用你的帳號身份執行這些程式,所以需要確保你選擇的帳號身份有對應的 GA 報表存取權限。

  • 撰寫好程式碼後,點擊「偵錯」-> 點擊「審查權限」

  • 選擇要執行的身份帳戶,通常等於當前 Google Apps Script 帳戶

  • 選擇「進階」展開 -> 點擊「前往 XXX」 這是我們自己寫給自己用的應用程式,不需經過 Google 驗證。

  • 點擊「允許」

允許之後再點「偵錯」或「執行」就能執行程式:

這邊我們先使用 Logger.log(JSON.stringify()) 取得輸出結果:

{
  "kind": "analyticsData#runReport",
  "dimensionHeaders": [
    {
      "name": "pageTitle"
    }
  ],
  "rowCount": 71,
  "metadata": {
    "currencyCode": "TWD",
    "timeZone": "Asia/Taipei"
  },
  "rows": [
    {
      "dimensionValues": [
        {
          "value": "ZhgChgLi"
        }
      ],
      "metricValues": [
        {
          "value": "166"
        }
      ]
    },
    {
      "metricValues": [
        {
          "value": "109"
        }
      ],
      "dimensionValues": [
        {
          "value": "Apple Watch 原廠不鏽鋼米蘭錶帶開箱 | ZhgChgLi"
        }
      ]
    },
    {
      "dimensionValues": [
        {
          "value": "iOS ≥ 13.1 使用「捷徑」自動化功能搭配米家智慧家居 | ZhgChgLi"
        }
      ],
      "metricValues": [
        {
          "value": "101"
        }
      ]
    },
    {
      "dimensionValues": [
        {
          "value": "Medium Partner Program 終於對全球(包含台灣)寫作者開放啦! | ZhgChgLi"
        }
      ],
      "metricValues": [
        {
          "value": "85"
        }
      ]
    },
    {
      "metricValues": [
        {
          "value": "77"
        }
      ],
      "dimensionValues": [
        {
          "value": "iOS 捷徑自動化應用場景 — 自動轉發簡訊與自動建立提醒待辦事項 | ZhgChgLi"
        }
      ]
    },
    {
      "metricValues": [
        {
          "value": "51"
        }
      ],
      "dimensionValues": [
        {
          "value": "遊記 9/11 名古屋一日快閃自由行 | ZhgChgLi"
        }
      ]
    },
    {
      "metricValues": [
        {
          "value": "42"
        }
      ],
      "dimensionValues": [
        {
          "value": "iOS 隱私與便利的前世今生 | ZhgChgLi"
        }
      ]
    },
    {
      "dimensionValues": [
        {
          "value": "iOS Vision framework x WWDC 24 Discover Swift enhancements in the Vision framework Session | ZhgChgLi"
        }
      ],
      "metricValues": [
        {
          "value": "34"
        }
      ]
    },
    {
      "dimensionValues": [
        {
          "value": "iOS ≥ 18 NSAttributedString attributes Range 合併的一個行為改變 | ZhgChgLi"
        }
      ],
      "metricValues": [
        {
          "value": "30"
        }
      ]
    },
    {
      "metricValues": [
        {
          "value": "30"
        }
      ],
      "dimensionValues": [
        {
          "value": "手工打造 HTML 解析器的那些事 | ZhgChgLi"
        }
      ]
    }
  ],
  "metricHeaders": [
    {
      "type": "TYPE_INTEGER",
      "name": "screenPageViews"
    }
  ],
  "totals": [
    {
      "dimensionValues": [
        {
          "value": "RESERVED_TOTAL"
        }
      ],
      "metricValues": [
        {
          "value": "1229"
        }
      ]
    }
  ]
}
  • Google Apps Script 請求 GA 數據成功!🎉🎉🎉

Step 3. 組合起來!Google Apps Script + GA4 + Telegram Bot

依照上篇文章「 10 分鐘快速移轉 Line Notify 到 Telegram Bot 通知 」建立你的 Telegram Bot 取得 Bot Token & 想要傳送到的 Channel Chat ID

const telegramToken = "XXXX" // 帶入你的 Telegram Bot Token
//

function execute() {
  const screenPageViewsReport = fetchScreenPageViews("318495208");
  
  //
  const total = parseInt(screenPageViewsReport.totals[0].metricValues[0].value);
  var message = "總瀏覽數:"+total.toLocaleString()+"\n";

  screenPageViewsReport.rows.forEach(function(element, index) {
    const pageTitle = element.dimensionValues[0].value;
    const value = parseInt(element.metricValues[0].value);

    message += "[Top "+(index + 1)+"] "+pageTitle+": "+value.toLocaleString()+"\n";
  });

  sendNotifyMessage(message, -xxxx); // 帶入你的 Channel Chat ID
}


// 發送訊息到 Telegram 指定 Channel Chat ID
function sendNotifyMessage(message, chatId) {
  var url = "https://api.telegram.org/bot"+telegramToken+"/sendMessage";
  
  const payload = {
    "chat_id": chatId,
    "text": message,
    "disable_web_page_preview": true
  } 
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'muteHttpExceptions': true,
    'payload': JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(url, options);
  const data = JSON.parse(response.getContentText());

  if (data["ok"] == undefined || data["ok"] != true) {
    if (data["error_code"] != undefined && data["error_code"] == 429) {
      Utilities.sleep(1000);
      sendNotifyMessage(message, chatId);
    }
  }
}

function fetchScreenPageViews(propertyId, startDate = "7daysAgo", endDate = "yesterday") {
  const screenPageViewsMetric = AnalyticsData.newMetric();
  screenPageViewsMetric.name = "screenPageViews";

  const dateRange = AnalyticsData.newDateRange();
  dateRange.startDate = startDate;
  dateRange.endDate = endDate;

  const pageTitleDimension = AnalyticsData.newDimension();
  pageTitleDimension.name = "pageTitle";

  const request = AnalyticsData.newRunReportRequest();
  request.dimensions = [pageTitleDimension];
  request.metrics = [screenPageViewsMetric];
  request.dateRanges = dateRange;

  request.limit = 10;
  request.metricAggregations = "TOTAL";

  return AnalyticsData.Properties.runReport(request, "properties/" + propertyId);
}

程式碼解析:

//...
  // 依照報表回傳的 json 找到 total 位置,parseInt 將字串轉成 INT 數字格式
  // .toLocaleString() -> 格式化數字,123456 -> 123,456
  const total = parseInt(screenPageViewsReport.totals[0].metricValues[0].value);
  var message = "總瀏覽數:"+total.toLocaleString()+"\n";

  // 依照報表回傳的 json 遍歷資料,組合成訊息
  screenPageViewsReport.rows.forEach(function(element, index) {
    const pageTitle = element.dimensionValues[0].value;
    const value = parseInt(element.metricValues[0].value);

    message += "[Top "+(index + 1)+"] "+pageTitle+": "+value.toLocaleString()+"\n";
  });
//...

執行:點擊上方「執行」或「偵錯」並確定方法名稱是選擇「 execute 」:

  • 成功!🎉🎉🎉

設定排程定時自動執行

最後一步是我們希望報表機器人能定時自動執行,從左側選單前往「觸發條件」:

  • 選擇右下角「新增觸發條件」按鈕

  1. 選擇鐔要執行的功能:選擇 「 execute 」方法名稱
  2. 選擇執行的部署作業:選擇「 上端
  3. 選取活動來源:選擇「 時間驅動
  4. 選取時間型觸發條件類型:選擇你想要的觸發頻率
  5. 選取時段:選擇你想要每日自動觸發的時間
  6. 如果執行失敗…通知信件的頻率設定
  7. 儲存

完成!這樣時間到就會自動執行囉。 🎉🎉🎉

延伸作業

其他數據如 新使用者數、來源媒介等,同樣使用前面程式碼就能達成,這邊就不在重複贅述,就當成給大家的回家作業囉。

在 GitHub 上補充修正
編輯這篇文章
本文首次發表於 Medium
點此查看原文
分享這篇文章
複製連結 · 分享到社群
ZhgChgLi
作者

ZhgChgLi

An iOS, web, and automation developer from Taiwan 🇹🇼 who also loves sharing, traveling, and writing.

留言 · Comments