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

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

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

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

Photo by [BoliviaInteligente](https://unsplash.com/@boliviainteligente?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash){:target="_blank"}

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 會使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "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 查詢程式碼並組合:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "dimensions": [
    {
      "name": "pageTitle"
    }
  ],
  "metrics": [
    {
      "name": "screenPageViews"
    }
  ],
  "dateRanges": [
    {
      "startDate": "7daysAgo",
      "endDate": "yesterday"
    }
  ],
  "limit": "10",
  "metricAggregations": [
    "TOTAL"
  ]
}

轉換成程式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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);
}

程式碼解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 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()) 取得輸出結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
{
  "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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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);
}

程式碼解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//...
  // 依照報表回傳的 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. 儲存

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

延伸作業

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

有任何問題及指教歡迎 與我聯絡

===

本文首次發表於 Medium ➡️ 前往查看



This post is licensed under CC BY 4.0 by the author.

10 分鐘快速移轉 Line Notify 到 Telegram Bot 通知

-