YouTubeを動画再生時間までトラッキングする方法
JMUGの皆様こんにちは。マルケトの大里です。
普段からテッキーな投稿が多いですが、今回は普段の2割り増しでテッキーですw
「元エンジニアですか?」とよく聞かれますが、HTMLという存在を知ったのが6年前で
JavaScriptなどのプログラムを独学で勉強して4年目くらいです。
本当はテクニカルな話よりもコピーライティングとかが大好きな人種でございます。
さて、雑なコーディングに対する期待値を下げる作業はここまでにして本題に移りたいとおもいます。
Webサイトに埋め込んだそのYouTube動画、どのくらい再生されたか知りたいですか?
ほんどの方が「そりゃそうだ、知りたい」と思うでしょうが、一部の方は「そんなのYouTube アナリティクスで見ればいいよ」という言うかもしれません。
そうです、YouTube アナリティクスを使えば「どの動画がもっとも再生されているか」「どの動画が最後まで見られているか」データから把握することが可能です。
YouTube動画を活用していて、まだYouTube アナリティクスを見たことがない方はぜひ見てみてください。
[参考リンク]
YouTube アナリティクスの概要 - YouTube ヘルプ
ざっくり言うと、
・動画の分析がしたいのであれば YouTube アナリティクス
・動画を再生した人が誰なのか把握したいのであれば、Marketo
データの分析対象は何か?
よくある話ですがデータの分析対象(主語)が明確でないと欲しいデータを集めることができず分析もできなくなります。
今回、ご紹介するするのは「リードがYouTube動画をどこまで再生したのか?」を把握するための手法です。
動画自体を分析をするためのテクニックではございません。
■実装方法
Step1:jQueryを読み込んでおく
・jQueryをWebサイトで読み込んでいる場合はこのステップは飛ばしていただいて構いません。
・MarketoのLPにjQueryを読み込む場合は、ランディングページの下書きの編集で
[ アクション > ページのMetaタグの編集 > カスタムHEAD HTML ]に下記のコードを追加
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

Step2:YouTube計測用のJSを呼び出す
<script>
'use strict';
(function () {
$(function () {
var idx = '';
var $target = $('[id *= "player_"]');
// idを取得
$target.each(
function(i){
var tempId = $(this).attr('id').replace('player_', '');
if( i >= 1){
idx += ',';
}
idx += tempId;
}
)
// youtube API
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
window.onYouTubeIframeAPIReady = function() {
addYoutubePlayer( idx );
}
var playerArr = {}; // player obj
// playerを生成
function addYoutubePlayer( videoIDs ) {
if( videoIDs === undefined ){
throw new Error('videoIDs is not defined!');
}
var tmpIdArr = videoIDs.split(",");
for(var i in tmpIdArr){
var videoID = tmpIdArr[i];
var playerID = 'player_' + videoID;
var player = new YT.Player(
playerID, {
videoId: videoID,
events: {
onReady : onPlayerReady,
onStateChange : onPlayerStateChange
},
playerVars: {
rel :0,
showinfo :0,
controls :1
}
}
);
//
var tempObj = {
player : player,
startFlg : false,
send25per : 0,
send50per : 0,
send75per : 0,
totalSeconds : 0,
second30Flg : false,
intervalId : 0,
oldTime : 0,
currentTime : 0,
send25Flg : false,
send50Flg : false,
send75Flg : false,
send100Flg : false
}
playerArr[videoID] = tempObj;
}
}
function onPlayerReady( event ) {
var id = event.target.getVideoUrl().replace(/https?:\/\/www\.youtube\.com\/watch\?v=/, '');
var totalSeconds = event.target.getDuration() - 1;
playerArr[id].totalSeconds = totalSeconds;
playerArr[id].send25per = totalSeconds * 0.25;
playerArr[id].send50per = totalSeconds * 0.50;
playerArr[id].send75per = totalSeconds * 0.75;
}
function onPlayerStateChange(event) {
var eventNum = event.data;
var id = event.target.getVideoUrl().replace(/https?:\/\/www\.youtube\.com\/watch\?v=/, '');
switch ( eventNum ) {
case YT.PlayerState.ENDED: // 0 (再生終了(=最後まで再生した))
playerArr[id].startFlg = false;
playerArr[id].second30Flg = false;
clearInterval( playerArr[id].intervalId );
break;
case YT.PlayerState.PLAYING: // 1 (再生中)
if( !playerArr[id].startFlg ){
playerArr[id].startFlg = true;
// playを飛ばす
sendGA( id, 'play', '', '0%');
}
//
playerArr[id].intervalId = setInterval(function(){
playerArr[id].oldTime = playerArr[id].currentTime;
playerArr[id].currentTime = event.target.getCurrentTime();
var range = Math.abs( playerArr[id].currentTime - playerArr[id].oldTime );
// seekの判断
if( Math.floor(range) >= 2 ){
// seek後も同じ計測エリアの場合はフラグを戻さない
// 25per
if( playerArr[id].oldTime >= ( playerArr[id].send25per ) &&
playerArr[id].oldTime <= ( playerArr[id].send50per ) &&
playerArr[id].currentTime >= ( playerArr[id].send25per ) &&
playerArr[id].currentTime <= ( playerArr[id].send50per )
){
playerArr[id].send25Flg = true;
} else {
playerArr[id].send25Flg = false;
}
// 50per
if( playerArr[id].oldTime >= ( playerArr[id].send50per ) &&
playerArr[id].oldTime <= ( playerArr[id].send75per ) &&
playerArr[id].currentTime >= ( playerArr[id].send50per ) &&
playerArr[id].currentTime <= ( playerArr[id].send75per )
){
playerArr[id].send50Flg = true;
} else {
playerArr[id].send50Flg = false;
}
// 75per
if( playerArr[id].oldTime >= ( playerArr[id].send75per ) &&
playerArr[id].oldTime <= ( playerArr[id].totalSeconds ) &&
playerArr[id].currentTime >= ( playerArr[id].send75per ) &&
playerArr[id].currentTime <= ( playerArr[id].totalSeconds )
){
playerArr[id].send75Flg = true;
} else {
playerArr[id].send75Flg = false;
}
playerArr[id].send100Flg = false;
}
// 30秒のフラグ
if( playerArr[id].currentTime >= ( 30 ) &&
playerArr[id].currentTime <= ( 30 + 1 ) &&
!playerArr[id].second30Flg
){
sendGA( id, '', '30秒突破', '');
playerArr[id].second30Flg = true;
}
// 25%のフラグ
if( playerArr[id].currentTime >= ( playerArr[id].send25per ) &&
playerArr[id].currentTime <= ( playerArr[id].send50per ) &&
!playerArr[id].send25Flg
){
sendGA( id, '', '', '25%');
playerArr[id].send25Flg = true;
}
// 50%のフラグ
if( playerArr[id].currentTime >= ( playerArr[id].send50per ) &&
playerArr[id].currentTime <= ( playerArr[id].send75per ) &&
!playerArr[id].send50Flg
){
sendGA( id, '', '', '50%');
playerArr[id].send50Flg = true;
}
// 75%のフラグ
if( playerArr[id].currentTime >= ( playerArr[id].send75per ) &&
playerArr[id].currentTime <= ( playerArr[id].totalSeconds ) &&
!playerArr[id].send75Flg
){
sendGA( id, '', '', '75%');
playerArr[id].send75Flg = true;
}
// 100%のフラグ
if( playerArr[id].currentTime >= ( playerArr[id].totalSeconds ) &&
!playerArr[id].send100Flg ) {
sendGA( id, 'finish', 'complete', '100%');
playerArr[id].send100Flg = true;
}
// loopFunc( event.target );
}, 250);
break;
case YT.PlayerState.PAUSED: // 2 (一時停止された)
clearInterval( playerArr[id].intervalId );
if(playerArr[id].currentTime >= playerArr[id].totalSeconds ) {
return;
}
sendGA( id, 'stop', '', '' );
break;
case YT.PlayerState.BUFFERING: // 3 (バッファリング中)
if( !playerArr[id].startFlg ){
playerArr[id].startFlg = true;
sendGA( id, 'play', '', '0%');
}
break;
case YT.PlayerState.CUED: // 5 (頭出しされた)
break;
case -1: // 動画未再生
break;
}
}
function sendGA( id, label, time1, time2 ) {
// console.log( 'id : ' + id, ' / label : ' + label, ' / time-1 : ' + time1, ' / time-2 : ' + time2 );
var url = 'id:'+ id + '_label :' + label + '_time-1:' + time1 + '_%_:' + time2
/*
dataLayer.push({
'event' : 'Click',
'category' : 'YouTube',
'action' : id,
'label' : label, // 'play' / 'finish'
'time-1' : time1, // 30秒 / complete
'time-2' : time2 // percent
});
*/
Munchkin.munchkinFunction('clickLink', {
'href': url
}
);
}
});
}());
</script>
このJSを読み込む方法はJSをファイル化してサーバーにアップして、それを読み込むでもいいですし
HTMLに直書きしてしていただいてもOKです。
また、このスクリプトは元々がYouTubeの動画の再生をログをGAに飛ばすために作ったものなので
sendGAというのがチラチラ見えると思いますがお気になさらずに。
Step3:YouTube動画埋め込む
ここがポイントでYouTubeの埋め込む際に「埋め込む」を選んではいけません。
この埋め込みはiFramで実装しますので、外側からアクセスことができなくなっています。

<iframe width="560" height="315" src="https://www.youtube.com/embed/PkiH7mjISw4" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
( ↑ この方法でHTMLに埋め込んではだめです)
ですので、YouTubeのAPIをJavaScriptでアクセスできるようにするには下記のように埋め込む必要があります。
<div id="player_PkiH7mjISw4">
</div>
idが「player_xxxxxxx」となっていますが、xxxxxxxの部分に動画IDを入れます。
で、このIDの取得方法ですがYouTubeのURLのパラメータから取得します。

このIDをdiv idの所に入れればOKです。
Step4:動作確認をする
きちんと再生時間等などがMarketoのアクティビティログに入っているかチェックします。
色々なチェック方法がありますが、Chromeのコンソールでチェックするのが簡単なのでおすすめです。
[ 開発者ツール > Network > 検索ボックス:mchNC > ビーコン(リクエスト)の中身をチェック ]
▼再生開始

▼25%以上再生
Step5:ローンチ
きちんと検証作業をした後にローンチをしてください。
注意点
・YouTubeのAPIの仕様に依存しますので、仕様変更等が合った際にはエラーが怒る可能性があります。
・数年前に作ったプログラムなので、バージョンが古いかもしれません
・大里が趣味で作ったスクリプトなので動作保証はございません。自己責任でご利用ください。
・弊社サポートにて本カスタマイズに対するお問い合わせには対応ができません。
お気付きの点があれば、JMUGの皆様のお力で改善およびブラッシュアップしていければ嬉しいです。