如何建立伺服器代碼

伺服器端代碼簡介中,您已大致瞭解代碼管理工具中的伺服器端代碼。您已瞭解用戶端是什麼,以及用戶端的功能:用戶端會接收使用者裝置的事件資料,並調整資料,供容器的其餘部分使用。本文說明如何在伺服器端代碼中處理這類資料。

在伺服器容器中,代碼會接收來自用戶端的傳入事件資料、轉換資料,然後傳送出去以供收集和分析。代碼可將資料傳送到任何位置。只要目的地接受 HTTP 要求,就能接受來自伺服器容器的資料。

伺服器容器有三個內建代碼,不需自訂設定即可使用:

  • Google Analytics
  • HTTP 要求

如要將資料傳送至 Google Analytics 以外的位置,或是需要 HTTP 要求代碼未提供的功能,請改用其他代碼。您可以在社群範本庫中找到其他代碼,也可以自行編寫代碼。本教學課程將說明如何為伺服器容器編寫自訂代碼。

目標

  • 瞭解要使用哪些 API 讀取事件資料、傳送 HTTP 要求,以及在瀏覽器中設定 Cookie。
  • 瞭解設計代碼設定選項的最佳做法。
  • 瞭解使用者指定資料和自動收集資料之間的差異,以及這項區別的重要性。
  • 瞭解代碼在伺服器容器中的角色。瞭解代碼應執行的動作和不應執行的動作。
  • 瞭解何時應考慮將代碼範本提交至社群範本庫

必要條件

Baz Analytics 代碼

在本教學課程中,您將建立代碼,將評估資料傳送至名為 Baz Analytics 的服務。

Baz Analytics 是一項簡單的假設性數據分析服務,可透過 HTTP GET 要求擷取資料至 https://example.com/baz_analytics。其參數如下:

參數 範例 說明
ID BA-1234 Baz Analytics 帳戶的 ID。
en click 這是指活動名稱。
l https://www.google.com/search?q=sgtm 發生事件的網頁網址。
u <0x0 2384294892 執行動作的使用者 ID。用於將多項動作連結回單一使用者。

代碼設定

首先,請建立代碼範本。前往容器的「範本」部分,然後在「代碼範本」部分中按一下「新增」。 為代碼輸入名稱和說明。

接著,前往範本編輯器的「欄位」部分,為代碼新增不同的設定選項。接下來的問題很顯然就是:您需要哪些選項?您可以選擇透過下列三種方式建立代碼:

  1. 設定總數:為每個參數新增設定欄位。 要求使用者明確設定所有項目。
  2. 無設定:沒有任何代碼設定選項。所有資料都直接取自活動。
  3. 部分設定:部分參數有欄位,其他參數則沒有。

每個參數都有對應的欄位,可讓使用者彈性地全面掌控代碼設定。但實際上,這通常會導致大量重複作業。舉例來說,Baz Analytics l 參數 (內含網頁網址) 等項目明確且通用。每次設定代碼時都輸入相同且不變的資料,最好交由電腦處理。

或許解決方法是使用只會從事件擷取資料的代碼。這是使用者可設定的最簡單代碼,因為他們實際上不需要執行任何動作。另一方面,這也是限制最多且最容易出錯的選項。即使有需要,使用者也無法變更代碼的行為。 舉例來說,他們可能在網站和 Google Analytics 中將事件稱為 purchase,但 Baz Analytics 則稱為 buy。或者,代碼對傳入事件資料結構所做的假設,實際上與現實不符。無論是哪一種情況,使用者都會卡住。

如同許多事物一樣,答案介於這兩個極端之間。有些資料一律應從事件中擷取。其他資料應由使用者設定。如何判斷哪個是哪個?如要回答這個問題,我們需要仔細查看容器收到的資料。

資料來源為何?

從 Google Analytics 代碼傳送至伺服器容器的資料大致可分為兩類:使用者指定的資料和自動收集的資料。

使用者指定的資料是指使用者在 gtag.js event 指令中輸入的所有內容。例如:

gtag('event', 'search', {
  search_term: 'beets',
});

伺服器容器中會出現下列參數:

{
  event_name: 'search',
  search_term: 'beets',
}

這項做法相當簡單,但從代碼的角度來看,卻非常難以處理。由於這項資料是由使用者輸入,因此可以是任何內容。 如上所述,使用者可能只會傳送建議事件和參數,但這並非必要。除了 event_name 參數的位置 (但不是值!) 外,使用者資料的形式或結構沒有任何保證。

幸好容器收到的資料不只有使用者輸入的資料。此外,系統也會從瀏覽器中 Google Analytics 代碼自動收集大量資料。其中包括:

  • ip_override
  • language
  • page_location
  • page_referrer
  • page_title
  • screen_resolution
  • user_agent

此外,如果伺服器要求來自網路瀏覽器,您也可以透過 getCookieValue API 取得瀏覽器 Cookie 資料。

這些資料共同構成我們上述提及的自動收集資料。一般而言,這類資料具有通用性,且語意明確。當瀏覽器中的 Google Analytics 代碼發出要求時,這項資料一律可用,且格式一律相同。如要進一步瞭解這些參數,請參閱事件參考資料

這項分類可做為實用工具,協助我們決定應由使用者設定哪些資料,以及應在代碼中指定哪些資料。您可以直接從事件中讀取自動收集的資料,不必擔心安全問題。其餘設定應由使用者設定。

請根據上述說明,再次查看 Baz Analytics 標記的參數。

  • 評估 ID,id由於系統不會自動收集這項資料,因此這是使用者在設定代碼時應輸入值的明確範例。
  • 事件名稱 en如上所述,事件名稱一律可直接取自 event_name 參數。不過,由於這個值是由使用者定義,因此建議提供覆寫名稱的功能 (如有需要)。
  • 網頁網址 l這個值可取自 page_location 參數,Google Analytics 瀏覽器代碼會在每個事件中自動收集這個參數。因此,您不應要求使用者手動輸入值。
  • 使用者 ID u在 Baz Analytics 伺服器代碼中,u 參數既不是使用者指定,也不是網頁上的代碼自動收集。而是儲存在瀏覽器 Cookie 中,以便在使用者多次造訪網站時進行識別。如下方的實作項目所示,是 Baz Analytics 伺服器代碼使用 setCookie API 設定 Cookie。也就是說,只有 Baz Analytics 代碼知道 Cookie 的儲存位置和方式。與 l 類似,u 參數應會自動收集。

代碼設定完成後,畫面應如下所示:

Baz Analytics 代碼的代碼設定快照。

導入廣告代碼

代碼設定完成後,即可在採用沙箱機制的 JavaScript 中實作代碼行為。

代碼需要執行四項操作:

  1. 從代碼設定取得事件名稱。
  2. 從活動的 page_location 屬性取得網頁網址。
  3. 計算使用者 ID。代碼會在名為「_bauid」的 Cookie 中尋找使用者 ID。如果沒有該 Cookie,代碼會計算新值並儲存,以供後續要求使用。
  4. 建構網址,並向 Baz Analytics 收集伺服器提出要求。

此外,也請花點時間思考代碼在整個容器中的定位。不同的容器元件扮演不同的角色,因此代碼也有不該或不應執行的動作。您的代碼:

  • 不應檢查事件,判斷是否應執行。這就是觸發程序的作用。
  • 不應使用 runContainer API 執行容器。這是客戶的工作。
  • 除了 Cookie 這個重要例外,它不應嘗試直接與要求或回應互動。這也是客戶的工作。

如果代碼範本執行上述任何動作,代碼使用者就會感到困惑。舉例來說,如果代碼會對傳入的要求傳送回應,用戶端就無法執行相同操作。這會讓使用者對容器的行為產生錯誤的預期。

請注意上述事項,以下是沙箱化 JS 中代碼的註解實作。

const encodeUriComponent = require('encodeUriComponent');
const generateRandom = require('generateRandom');
const getCookieValues = require('getCookieValues');
const getEventData = require('getEventData');
const logToConsole = require('logToConsole');
const makeString = require('makeString');
const sendHttpGet = require('sendHttpGet');
const setCookie = require('setCookie');

const USER_ID_COOKIE = '_bauid';
const MAX_USER_ID = 1000000000;

// The event name is taken from either the tag's configuration or from the
// event. Configuration data comes into the sandboxed code as a predefined
// variable called 'data'.
const eventName = data.eventName || getEventData('event_name');

// page_location is automatically collected by the Google Analytics tag.
// Therefore, it's safe to take it directly from event data rather than require
// the user to specify it. Use the getEventData API to retrieve a single data
// point from the event. There's also a getAllEventData API that returns the
// entire event.
const pageLocation = getEventData('page_location');
const userId = getUserId();

const url = 'https://www.example.com/baz_analytics?' +
    'id=' + encodeUriComponent(data.measurementId) +
    'en=' + encodeUriComponent(eventName) +
    (pageLocation ? 'l=' + encodeUriComponent(pageLocation) : '') +
    'u=' + userId;

// The sendHttpGet API takes a URL and returns a promise that resolves with the
// result once the request completes. You must call data.gtmOnSuccess() or
// data.gtmOnFailure() so that the container knows when the tag has finished
// executing.
sendHttpGet(url).then((result) => {
  if (result.statusCode >= 200 && result.statusCode < 300) {
    data.gtmOnSuccess();
  } else {
    data.gtmOnFailure();
  }
});

// The user ID is taken from a cookie, if present. If it's not present, a new ID
// is randomly generated and stored for later use.
//
// Generally speaking, tags should not interact directly with the request or
// response. This prevents different tags from conflicting with each other.
// Cookies, however, are an exception. Tags are the only container entities that
// know which cookies they need to read or write. Therefore, it's okay for tags
// to interact with them directly.
function getUserId() {
  const userId = getCookieValues(USER_ID_COOKIE)[0] || generateRandom(0, MAX_USER_ID);
  // The setCookie API adds a value to the 'cookie' header on the response.
  setCookie(USER_ID_COOKIE, makeString(userId), {
    'max-age': 3600 * 24 * 365 * 2,
    domain: 'auto',
    path: '/',
    httpOnly: true,
    secure: true,
  });

  return userId;
}

這樣就完成代碼導入作業。您必須先正確設定 API 權限,才能使用代碼。前往範本編輯器的「Permissions」(權限) 分頁,然後指定下列權限:

  • 讀取 Cookie 值:_bauid
  • 讀取事件資料:event_namepage_location
  • 傳送 HTTP 要求:https://www.example.com/*
  • 設定 Cookie:_bauid

您也應該為代碼編寫測試。如要進一步瞭解範本測試,請參閱範本開發人員指南的測試部分。

最後,別忘了至少按一次「執行程式碼」按鈕,執行代碼。這樣可避免許多簡單的錯誤進入伺服器。

您已完成建立、測試及部署新代碼的所有工作,因此沒有理由不與他人分享。如果您認為新代碼對其他人也有幫助,不妨提交至社群範本庫。

結論

在本教學課程中,您已瞭解如何為伺服器容器編寫代碼的基本概念。並瞭解:

  • 用於讀取事件資料、傳送 HTTP 要求,以及在瀏覽器中設定 Cookie 的 API。
  • 設計代碼設定選項的最佳做法。
  • 使用者指定資料與自動收集資料的差異,以及區分兩者的重要性。
  • 容器中代碼的角色;代碼應執行的動作和不應執行的動作。
  • 何時及如何將代碼範本提交至社群範本庫