更新時間:2024年09月05日
如果網站上的影片不是YouTube或Vimeo,而是直接使用 HTML5 <video> 標籤嵌入的影片,那麼GA4預設並不會自動追蹤這些影片的播放行為。
這時候就需要透過GTM自行監聽影片事件,再將資料傳送到GA4。
本文將介紹如何利用GTM追蹤 HTML5(H5)影片的:
- 播放(Play)
- 暫停(Pause)
- 播放進度(25%、50%、75%、100%)
- 播放完成(Complete)
並將這些資料送GA4進行分析。
為什麼需要追蹤HTML5影片?
許多網站會將產品介紹、教學影片、品牌宣傳影片直接放在自己的伺服器上,而不是使用YouTube或Vimeo。
例如:
- 產品介紹影片
- 課程教學影片
- 線上研討會錄影
- 品牌形象影片
若沒有額外設定GA4,你將無法得知:
- 有多少人播放影片?
- 使用者看到哪個進度就離開?
- 哪些影片最受歡迎?
- 影片是否有助於提升轉換率?
因此建議將影片互動行為納入GA4事件追蹤。
HTML5 影片追蹤原理
整體流程如下:
- 使用JavaScript監聽影片播放行為
- 當影片播放、暫停或播放到指定進度時
- 透過
dataLayer.push() 發送事件
- GTM接收事件後送到GA4
H5影片追蹤範例
添加H5影片監聽代碼
Step 1:建立 HTML5影片偵測變數
由於頁面不一定都有影片,因此建議先建立一個變數判斷當前頁面是否存在 HTML5 Video。
在GTM中點擊「變數」——「新增」——「請選擇變數類型以開始設定…」——「自訂 JavaScript」,命名為 “cjs – is HTML5 Video on a page”, 然後做如下設定:

此變數的用途檢查頁面中是否存在<video>,如果存在返回true,不存在返回false,後續觸發器會利用這個變數來避免在沒有影片的頁面執行監聽程式。
function () {
var video = document.getElementsByTagName('video').length;
if (video > 0) {
return true;
}
else {
return false;
}
}
Step 2:建立影片監聽觸發器
在GTM中點擊「觸發條件」—「新增」—「選擇一個觸發條件類型以開始設定」——「網頁瀏覽 – 視窗已載入」,命名為“Pageview – HTML5 Video Player is Present”,然後做如下設定:

使用視窗已載入可以降低監聽程式過早執行而找不到影片元素的問題。
Step 3:建立HTML5 Video Listener
接下來要建立負責監聽影片事件的JavaScript。
在GTM中點擊「代碼」—「新增」—「請選擇代碼類型以開始設定…」——「自訂HTML」,命名為“cHTML – HTML5 Video Listener”,然後做如下設定:

此程式負責監聽播放、監聽暫停、監聽觀看進度,並透過 dataLayer.push() 傳送事件
<script>
// Let's wrap everything inside a function so variables are not defined as globals
(function() {
// This is gonna our percent buckets ( 25%-75% )
var divisor = 25;
// We're going to save our players status on this object.
var videos_status = {};
// This is the funcion that is gonna handle the event sent by the player listeners
function eventHandler(e) {
switch (e.type) {
// This event type is sent everytime the player updated it's current time,
// We're using for the % of the video played.
case 'timeupdate':
// Let's set the save the current player's video time in our status object
videos_status[e.target.id].current = Math.round(e.target.currentTime);
// We just want to send the percent events once
var pct = Math.floor(100 * videos_status[e.target.id].current / e.target.duration);
for (var j in videos_status[e.target.id]._progress_markers) {
if (pct >= j && j > videos_status[e.target.id].greatest_marker) {
videos_status[e.target.id].greatest_marker = j;
}
}
// current bucket hasn't been already sent to GA?, let's push it to <a href="https://www.haranhuang.com/tag/gtm" title="查看更多关于GTM的文章" target="_blank">GTM</a>
if (videos_status[e.target.id].greatest_marker && !videos_status[e.target.id]._progress_markers[videos_status[e.target.id].greatest_marker]) {
videos_status[e.target.id]._progress_markers[videos_status[e.target.id].greatest_marker] = true;
dataLayer.push({
'event': 'video',
'video_status': 'progress',
'video_provider' : 'generic html5 video player',
'video_percent': videos_status[e.target.id].greatest_marker,
// We are sanitizing the current video src string, and getting just the video name part
'video_title': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
});
}
break;
// This event is fired when user's click on the play button
case 'play':
dataLayer.push({
'event': 'video',
'video_status' : 'play',
'video_provider' : 'generic html5 video player',
'video_percent': videos_status[e.target.id].greatest_marker,
'video_title': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
});
break;
// This event is fied when user's click on the pause button
case 'pause':
if (videos_status[e.target.id].greatest_marker < '75') {
dataLayer.push({
'event': 'video',
'video_status' : 'pause',
'video_provider' : 'generic html5 video player',
'video_percent': videos_status[e.target.id].greatest_marker,
'video_title': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
});
}
break;
// If the user ends playing the video, an Finish video will be pushed ( This equals to % played = 100 )
case 'ended':
dataLayer.push({
'event': 'video',
'video_status' : 'complete',
'video_provider' : 'generic html5 video player',
'video_percent': '100',
'video_title': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
});
break;
default:
break;
}
}
// We need to configure the listeners
// Let's grab all the the "video" objects on the current page
var videos = document.getElementsByTagName('video');
for (var i = 0; i < videos.length; i++) {
// In order to have some id to reference in our status object, we are adding an id to the video objects
// that don't have an id attribute.
var videoTagId;
if (!videos[i].getAttribute('id')) {
// Generate a random alphanumeric string to use is as the id
videoTagId = 'html5_video_' + Math.random().toString(36).slice(2);
videos[i].setAttribute('id', videoTagId);
}// Current video has alredy a id attribute, then let's use it <img draggable="false" class="emoji" alt="?" src="https://s.w.org/images/core/emoji/2/svg/1f642.svg">
else {
videoTagId = videos[i].getAttribute('id');
}
// Video Status Object declaration
videos_status[videoTagId] = {};
// We'll save the highest percent mark played by the user in the current video.
videos_status[videoTagId].greatest_marker = 0;
// Let's set the progress markers, so we can know afterwards which ones have been already sent.
videos_status[videoTagId]._progress_markers = {};
for (j = 0; j < 100; j++) {
videos_status[videoTagId].progress_point = divisor * Math.floor(j / divisor);
videos_status[videoTagId]._progress_markers[videos_status[videoTagId].progress_point] = false;
}
// On page DOM, all players currentTime is 0
videos_status[videoTagId].current = 0;
// Now we're setting the event listeners.
videos[i].addEventListener("play", eventHandler, false);
videos[i].addEventListener("pause", eventHandler, false);
videos[i].addEventListener("ended", eventHandler, false);
videos[i].addEventListener("timeupdate", eventHandler, false);
videos[i].addEventListener("ended", eventHandler, false);
}
})();
</script>
設定H5影片事件
Step 1:建立Data Layer變數
從Listener程式碼中可以看到會推送以下參數:video_status、video_percent和video_provider,因此需要建立對應的Data Layer Variable。
在GTM中點擊「變數」——「新增」——「請選擇變數類型以開始設定…」——「資料層變數」,命名為 “dlv – video_status”, 然後做如下設定:

同理設定video_percent和video_provider。
Step 2:建立H5影片事件觸發器
從JavaScript裡,可以知道推送的事件名稱為video。
在GTM中點擊「觸發條件」—「新增」—「選擇一個觸發條件類型以開始設定」——「自訂事件」,命名為“Custom – Video Interaction”,然後做如下設定:

Step 3:建立GA4事件代碼
最後就是設定代碼。
在GTM中點擊「代碼」—「新增」—「請選擇代碼類型以開始設定…」——「Google Analytics(分析):GA4 事件」,命名為“Event—H5 Video Tracking”,做如下設定:

測試設定是否成功
GTM裡預覽測試是否成功,測試沒問題才發佈。
在GA4註冊自訂定義
即使事件已經送達 GA4,也不代表可以直接在報表中使用,還需要在自訂定義裡新增事件層級的自訂維度:
| 維度名稱 |
事件參數 |
| Video Status |
video_status |
| Video Percent |
video_percent |
| Video Provider |
video_provider |
完成後約需 24~48 小時才會出現在標準報表中。
常見問題(FAQ)
為什麼GA4看不 video_percent?
通常是因為尚未建立自訂維度。
GA4只有在事件參數被註冊後,才能於探索報表或自訂報表中使用。
一個頁面有多支影片可以追蹤嗎?
可以。
只要監聽程式支援多個 <video> 元素,即可同時追蹤多支影片。
總結
HTML5(H5)影片不像YouTube影片可以直接透過GTM內建功能追蹤,因此需要額外透過JavaScript監聽影片事件。
Referral