使用 Google Apps Script 串接 Google Analytics API,整合多站數據
本篇要解決的問題 一間公司裡可能旗下會有多個網站,想同時查看所有網站的 GA 數據,通常需要開啟多個瀏覽器視窗並排顯示,操作較為繁瑣。 如果可以改由 API 來取得 GA 的數據,工程師就可以把各站的資料顯示在一個頁面上,而不用同時開多個 GA 來看。 開通 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, "p

本篇要解決的問題
一間公司裡可能旗下會有多個網站,想同時查看所有網站的 GA 數據,通常需要開啟多個瀏覽器視窗並排顯示,操作較為繁瑣。
如果可以改由 API 來取得 GA 的數據,工程師就可以把各站的資料顯示在一個頁面上,而不用同時開多個 GA 來看。
開通 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 程式碼如下,可以直接複製貼上: