本篇要解決的問題
一間公司裡可能旗下會有多個網站,想同時查看所有網站的 GA 數據,通常需要開啟多個瀏覽器視窗並排顯示,操作較為繁瑣。
如果可以改由 API 來取得 GA 的數據,工程師就可以把各站的資料顯示在一個頁面上,而不用同時開多個 GA 來看。
English Version:Integrating Multi-Site Google Analytics Data Using Google Apps Script
開通 GA API
取得 GCP 專案編號
要先有 Google Cloud Platform(GCP)的專案,沒有的話登入自己的 Google 帳號,就可以先增一個。
專案編號就在 資訊主頁 上:

開通 GA API 功能
在使用 API 前,必須先於 GCP 開通對應的功能。
GCP 的專案點擊選單中的「API 和服務」> 「程式庫」:

搜尋框上搜尋「google analytics data api」,會看到結果清單裡會出現「Google Analytics Data API」,點進去後,再點擊啟用,就完成了:


取得 GA 的資源 ID
看要抓的是哪一個 GA 的資料,進到 GA 後台,進到「管理」,點擊「資源詳細資料」:

接著右上角就會看到資源編號:

調用 GA API 程式碼部份
因為調用 Google 的 API,要先經過認證的程序,但如果是寫在跟 GA 相同帳號的 Google Apps Script,就可以省掉這一段。
Google Apps Script 上新增專案
到 Google Apps Script 的頁面上,新增一個專案:

接著可以直接複製貼上以下的程式碼。
瀏覽量、活躍人數
以下程式碼是抓瀏覽量、活躍人數的:
var propertyId = "xxxxxx"; // 替換成 GA 的資源編號 var startDate = "2025-01-01", // 替換成想要從哪一天開始抓的日期 function getGA4Data() { var apiUrl = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}:runReport`; var payload = { "dateRanges": [{ "startDate": startDate, "endDate": "today" }], "metrics": [ { "name": "screenPageViews" }, // 瀏覽數 { "name": "activeUsers" } // 活躍用戶數 ] }; var options = { "method": "post", "contentType": "application/json", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }, "muteHttpExceptions": true, "payload": JSON.stringify(payload) }; var response = UrlFetchApp.fetch(apiUrl, options); var data = JSON.parse(response.getContentText()); // 檢查回應中是否有 rows 資料 if (data.rows && data.rows.length > 0) { // 取得瀏覽數和活躍用戶數 var screenPageViews = data.rows[0].metricValues[0].value; var activeUsers = data.rows[0].metricValues[1].value; // 回傳資料 return { "totalPageViews": screenPageViews, "activeUsers": activeUsers }; } else { // 若無符合資料,則回傳 0 作為預設值 return { "totalPageViews": 0, "activeUsers": 0 }; } }
瀏覽量、活躍人數:指定頁面標題
除了抓全站的資料,可以抓指定網頁的 title 是什麼結尾,比如這邊抓的是「會員中心」為結尾的頁面:
var propertyId = "xxxxxx"; // 替換成 GA 的資源編號 var startDate = "2025-01-01", // 替換成想要從哪一天開始抓的日期 var pageTitle = "會員中心"; // 替換成想要篩選的頁面標題文字 function getGA4DataPage() { var apiUrl = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}:runReport`; var payload = { "dateRanges": [{ "startDate": startDate, "endDate": "today" }], "metrics": [ { "name": "screenPageViews" }, // 瀏覽數 { "name": "activeUsers" } // 活躍用戶數 ], "dimensionFilter": { "filter": { "fieldName": "unifiedScreenName", "stringFilter": { "value": pageTitle, "matchType": "ENDS_WITH" } } } }; var options = { "method": "post", "contentType": "application/json", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }, "muteHttpExceptions": true, "payload": JSON.stringify(payload) }; var response = UrlFetchApp.fetch(apiUrl, options); var data = JSON.parse(response.getContentText()); if (data.rows && data.rows.length > 0) { var screenPageViews = data.rows[0].metricValues[0].value; var activeUsers = data.rows[0].metricValues[1].value; return { "totalPageViews": screenPageViews, "activeUsers": activeUsers }; } else { return { "totalPageViews": 0, "activeUsers": 0 }; } }
即時人數
var propertyId = "xxxxxx"; // 替換成 GA 的資源編號 function getGA4RealtimeData() { var apiUrl = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}:runRealtimeReport`; var payload = { "metrics": [{ "name": "activeUsers" }] }; var options = { "method": "post", "contentType": "application/json", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }, "muteHttpExceptions": true, "payload": JSON.stringify(payload) }; var response = UrlFetchApp.fetch(apiUrl, options); var data = JSON.parse(response.getContentText()); // 取得即時人數 return data.rows[0].metricValues[0].value; }
即時人數:指定頁面標題
這邊一樣是抓「會員中心」為結尾的頁面:
var propertyId = "xxxxxx"; // 替換成 GA 的資源編號 var pageTitle = "會員中心"; // 替換成想要篩選的頁面標題文字 function getGA4RealtimeDataPage() { var apiUrl = `https://analyticsdata.googleapis.com/v1beta/properties/${propertyId}:runRealtimeReport`; // 在 payload 中新增 dimensions 和 dimensionFilter var payload = { "metrics": [{ "name": "activeUsers" }], "dimensions": [{ "name": "unifiedScreenName" }], "dimensionFilter": { "filter": { "fieldName": "unifiedScreenName", "stringFilter": { "value": pageTitle, "matchType": "ENDS_WITH" } } } }; var options = { "method": "post", "contentType": "application/json", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }, "muteHttpExceptions": true, "payload": JSON.stringify(payload) }; var response = UrlFetchApp.fetch(apiUrl, options); var data = JSON.parse(response.getContentText()); var totalActiveUsers = 0; // 累加所有匹配頁面的人數 if (data.rows && data.rows.length > 0) { data.rows.forEach(function (row) { totalActiveUsers += parseInt(row.metricValues[0].value, 10); }); } return totalActiveUsers.toString(); // 返回所有匹配頁面的總人數 }
以 POST 的參數,判斷要給哪種資料
上面一共寫了四個函式,我們需要一個參數,讓 API 知道要回應的是哪個資料。
這邊用的參數是 type
,type
不同值,就給不同資料,共有 4 個值可以寫:
data
:瀏覽量、活躍人數。dataPage
:瀏覽量、活躍人數:指定頁面標題。realtimeData
:即時人數。realtimeDataPage
:即時人數:指定頁面標題。
// 回應錯誤訊息 function createErrorResponse(message, code) { var errorResponse = { success: false, error: message, code: code || 400, timestamp: new Date().toISOString() }; var jsonOutput = ContentService.createTextOutput(JSON.stringify(errorResponse)); jsonOutput.setMimeType(ContentService.MimeType.JSON); return jsonOutput; } // 處理 POST function doPost(e) { // 確認有傳入內容 if (!e.postData || !e.postData.contents) { return createErrorResponse("無效請求:未收到 POST 資料。" + e.postData); } // 將 POST 資料解析成 JSON var requestData; try { requestData = JSON.parse(e.postData.contents); } catch (error) { return createErrorResponse("JSON 格式無效。"); } // 檢查是否有 type 參數 if (!requestData.type) { return createErrorResponse("缺少「type」參數。"); } var output; // 根據 type 參數執行不同的邏輯 switch (requestData.type) { // 瀏覽量、活躍人數 case "data": var reportData = getGA4Data(); output = { "totalPageViews": reportData.totalPageViews, "activeUsers": reportData.activeUsers }; break; // 瀏覽量、活躍人數:指定頁面標題 case "dataPage": var reportData = getGA4DataPage(); output = { "totalPageViews": reportData.totalPageViews, "activeUsers": reportData.activeUsers }; break; // 即時人數 case "realtimeData": var reportData = getGA4RealtimeData(); output = { "activeUsers": reportData }; break; // 即時人數:指定頁面標題 case "realtimeDataPage": var reportData = getGA4RealtimeDataPage(); output = { "activeUsers": reportData }; break; default: return createErrorResponse("type 錯誤"); } // 回傳 JSON 格式的結果 var jsonOutput = ContentService.createTextOutput(JSON.stringify(output)); jsonOutput.setMimeType(ContentService.MimeType.JSON); return jsonOutput; }
Google Apps Script 連結到 GCP 專案
左側選單點擊「設定」,接著頁面往下滑,有一項「 Google Cloud Platform (GCP) 專案」,點擊這項的「變更專案」:

接著輸入框就填上第一步在 GCP 上取得的編號,再點擊「設定專案」就可以了:

如果專案存在,連結就會成功,成功的畫面像這樣:

設定完後,這份 GAS 檔就可以使用 GCP 上開啟的 GA API。
部署 GAS
Google Apps Script 的程式如果要能對外,要部署出去才行。
點擊右上角的「部署」> 「管理部署作業」:

部署的類型是「網頁應用程式」:

「誰可以存取」要選擇「所有人」:

選好後,點擊「部署」,需要授權時就直接授權。
部署成功,就會取得一個網址,這個網址就是對外的 API 網址了:

最後,只要 POST 到這個網址,帶上指定的參數 type
,就可以取得我們想要的資料。
手動補權限
如果 POST 後,取到的資料一直是 0,代表部署時提供的權限不完整,就要手動補授權。
點擊左側的「專案設定」,在編輯器中顯示「appsscript.json」資訊清單檔案 打勾:

接著回到編輯器,會看到 appsscript.json 這個檔案,補上以下:
"oauthScopes": [ "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/analytics.readonly" ]

最後再次部署,會出現要補權限的授權,一律給過就行,就可以取得 GA 上的資料了。
完整程式碼
完整的 Google Apps Script 程式碼如下,可以直接複製貼上:

