YouTubeを動画再生時間までトラッキングする方法 | Community
Skip to main content
July 4, 2018

YouTubeを動画再生時間までトラッキングする方法

  • July 4, 2018
  • 4 replies
  • 794 views

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の皆様のお力で改善およびブラッシュアップしていければ嬉しいです。

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.

4 replies

Level 2
August 6, 2018

@Norio Osato​さん

Sunity西田です。いつも記事ありがとうございます。

本記事に触発されたため、丁度動画を埋め込んだLPを作成していたのでやってみました。

GTMを使うと簡単にYoutube関係のイベントが拾えるようです。

  [参考URL] GoogleTagManagerだけで完結。サイト埋め込みのYouTube再生行動をGoogle アナリティクスで取得する方法 – KOBIT

参考までに私が設定したGTMの概要を共有します。

サイト上のYouTubeタグはこんな感じです。Munchkinタグも埋まっています。

<iframe src="https://www.youtube.com/embed/4d5Qzct710s" id="ifr" frameborder="0" allow="encrypted-media" allowfullscreen></iframe>

手順1:動画関連変数を有効にする

手順2:YouTubeトリガーの作成

ここで設定したタイミングでトリガーが発生します。

下記例だと再生開始・終了・シークバーが25/50/75/90%に達したときにトリガーが発生します。

手順3:Marketoのトラッキングタグ作成

上で作成したトリガーを使ったトラッキングタグを埋め込みます。

下記の例ではvisitWebPageを使っています。

(大里さんのようにclickLinkのほうがいいかもです。)

ここで手順1で有効にした変数が利用可能です。

変数にどのような値が入るかについてはこちらの記事が参考になりました。

※{{キャンペーングループ名}}という変数は関係ないので気にしないでください。

手順4:テスト&リリース

必ずテストした上でリリースしてください。

■注意・補足

・一応だいたいのブラウザでは計測できたことを確認しましたが、動作保証はいたしかねます。

西田

August 6, 2018

西田さん

どもです。

おっ!GTMで取れるようになってたんですねー。

(やばい、キャッチアップ遅れてますね・・・)

どのプロダクトも進化が激しいので情報についていくのが大変っすね。

貴重な情報ありがとうございましたー。

Koki_Enomoto
Level 3
June 3, 2019

いつもお世話になっております。GEです。

 

途中に

「このIDをdiv idの所に入れればOKです。」

と記載がございますが、どこのdivのことでしょうか?

 

お手数ですが、ご回答よろしくお願いいたします。

June 15, 2022

本投稿、非常に参考になりました。

Step2の「YouTube計測用のJSを呼び出す」のJSを実装し、再生率(50%、75%など)をMarketoのアクティビティログへ反映させることに成功しました。

 

ただし、ログがクエリパラメータへ記録されているわけではないため、例えば、75%以上視聴された方のスマートリストを作成する、といったことができません。

 

こちら、JSへ何らかのスクリプトを記述することでクエリパラメータへ再生率を反映させることは可能なのでしょうか。

どなたかご存知であれば教えていただけますと幸いです。