ブラウザの速度指標として、Paint Timing という指標があります。     
Google Analytics でもデフォルトでサイトの速度が取得できますが、おそらく Navigation Timing API の取得データを元にした値で、Paint Timing の情報は取得できません。      
Paint Timing API の値を カスタム速度として設定して、Google Analytics 上で閲覧できるようにしてみました。 
実施した内容を記載します。     
参考
- 
gtag.js を使用してカスタム速度をトラッキングする | ウェブ向けアナリティクス(gtag.js) | Google Developers
 - 
Web クライアントサイドのパフォーマンスメトリクス — Speed Index、Paint Timing、TTI etc… ::ハブろぐ
 - 
Paint Timing APIを使用してクライアントサイドのパフォーマンスを計測してみた - イノベーション エンジニアブログ
 
前提
実装における前提は以下になります。
- 
GTM 上で、customTask を設定する
GTM で、customTask を使い、timingTask を拡張します。
ドキュメントには以下のような記載があり、siteSpeedSampleRateの設定に従って、カスタム速度も計測したいため、timingTask に対して設定しています。
実際に動かしてみて気づいたのですが、Google Analytics の JavaScript はsiteSpeedSampleRateの値を元に、timingTaskで実行してくれるわけではなく、timingTask内でsiteSpeedSampleRateを判断して、計測を行う必要があります。トラッカーの siteSpeedSampleRate の設定に基づいて、サイトの速度 timing ヒットを自動的に生成します。
 - 
計測の対象
Paint Timing で測れる FP、FCP を計測対象にします。
TTI (Time to Interactive)、CFP (Component First Paint) も計測でき、計測結果を、Google Analyticsに送付してくれるPerfume.js というライブラリも存在することがわかったのですが、GTM から上手く動かなそうだったので使用していません。 
実装
GA PageView タグの設定
GTM の GA タグに siteSpeedSampleRate の値を設定します。    
これは、後述しますが、CustamTask 内で、siteSpeedSampleRate を取得するためです。       
変数 customTask には、以下の CustomTask 変数の JavaSctipt を設定します。    
    
GA CustomTask 変数
customTask の内容は以下の通りです。   
設定内容を説明します。     
function() {
    function str2Num(str) {
        var b = 1;
        var charCode = 0;
        var i;
        if (str) {
          for (b = 0, i = str.length - 1; 0 <= i; i--) {
              charCode = str.charCodeAt(i);   // 16位
              // 268435455 === 1111111111111111111111111111 (28位)
              b = (b << 6 & 268435455) + charCode + (charCode << 14);
              // 266338304 === 1111111000000000000000000000 (21位 + 7位)
              var c = b & 266338304;
              b = 0 != c ? b ^ c >> 21 : b;
          }
        }
        return b
    };
    return function(model) {
        // Custom Dimensionの設定 クライアントID
        model.set('dimension8', model.get('clientId'));
        // 元のタスクの退避
        var originalTimingTask = model.get('timingTask');
        model.set('timingTask', function(timingTaskModel) {
              // 元のタスクの実行
              originalTimingTask(timingTaskModel);      
              if ('pageview' != timingTaskModel.get("hitType")) {
                  return;
              }
              var siteSpeedSampleRate = model.get('siteSpeedSampleRate');
              if (str2Num(model.get("clientId")) % 100 >= siteSpeedSampleRate) {
                  return;
              }
              // 計測対象の場合は、load イベントで、GTM にカスタムイベントを送付する
              window.addEventListener("load", function(event) {
                  if (window.performance) {
                    window.dataLayer = window.dataLayer || [];
                    var performance = window.performance;
                    var performanceEntries = performance.getEntriesByType('paint');
                    performanceEntries.forEach(function(performanceEntry, i, entries) {
                        window.dataLayer.push({
                           event: "sendTiming",
                           timingCategory: "Paint Timing",
                           timingVar: performanceEntry.name,
                           timingValue: performanceEntry.startTime,
                           timingLabel: 
                        });
                    });
                  }
              });
        });
    };
}
- 
var siteSpeedSampleRate = model.get('siteSpeedSampleRate');について
siteSpeedSampleRateを取得します。デフォルトでは、1ですが、タグで変数を設定しないと、undefinedになります。
Google Analytics の デフォルトタスクでは デフォルト値を適用してくれますが、1GTM タグ上はこれを自前実装しないといけないため、デフォルト値の設定を行うようにしました。 - 
str2Num 関数について
GA的源码 analytics.js を参考に Google Analytics.js 内で実装されている関数を定義しています。 - 
if (str2Num(model.get("clientId")) % 100 >= siteSpeedSampleRate)について
GA的源码 analytics.js に記載されている、siteSpeedSampleRateを適用するか否かを判断する、関数です。アクセスの度にランダムで選択するのではなく、ユーザーの Cookie 値での判断になります。
速度送付の対象、非対称が Cookie の値で判断されることになります。動作確認時に、この動作で少しハマりました。
理想としては、毎回ランダムで対象を選択してもいいのかと思います。 - 
カスタム速度の送付について
Google Analytics のイベントではなく、GTM のカスタムイベントを発行して、カスタム速度を計測します。 - 
model.set('dimension8', model.get('clientId'));について
今回やりたいことは、カスタム速度送付ですが、元々のcustomTaskの仕事として、clientId の設定を行っています。 - 
window.addEventListener("load", function(event)によるイベントリスナーの設定
GA的源码 analytics.js の実装を参考に、timingTaskの設定値として送付したい内容を、load イベントのタイミングで送付するようにしています。 
カスタム速度送付タグの設定
GTMカスタムイベント sendTiming に対応する、カスタム速度送付タグを作成します。     
下記は、ラベルを設定していないですが、ラベルも設定したほうが、Google Analytics 上の表示は見やすいかと思います。   
     
まとめ
GTM から、customTask 変数を使って、First Paint API の結果をカスタム速度として設定しました。          
情報があまりなくて、思い思いの実装になりましたが、無事送付できました。      
もう少し、APIが進化して TTL、SpeedIndex 等の込み入った値も送付できるようになったらそのあたりも送付するようにしようかと思います。    
以上です。
コメント