Googleアナリティクスで同一URLでフォーム遷移する場合のページビュー計測


計測URLを正規化する、1ページは1URLに集約してページビュー計測することが望ましいことは
https://www.marketechlabo.com/send-ga-pageview-canonicalized-url/
で取り上げたが、この「1ページで複数URL」とは逆に「複数のページで1URL」になるパターンの対応法を取り上げる。

よくあるのはフォームの遷移などで、同一URLで異なる内容のページが表示されることがある。

入力フォーム→確認画面→完了画面

これらが画面遷移はあるものの1URLで完結しているケースである。
ひどい場合は完了画面までもが同一URLになるため、コンバージョンの計測すらできない。

これをステップごとに異なる仮想URLを発行して計測する(ga('send', 'pageview', {'page': 'ステップの仮想URL'}))のだが、中にはフォームのシステム側で仮想URLを発行させ、それをGoogleアナリティクスのトラッキングコードに挿入する実装指示書もある。

そうなるとシステムの改修のコスト、手間がかかってしまうため、システムの改修は極力回避したい。

今回は純粋にHTMLの範囲だけでこの問題を解決する方法を取り上げる。通常

  1. ステップに応じてtitleタグの内容が異なる場合と、
  2. ステップに応じて見出しの内容が異なる場合と、
  3. URLもtitleタグの内容も同じだが、ページ内で表示している画像が異なる場合

のいずれかに当てはまることが多いので、これらのパターンを想定して実装する。

ステップに応じてtitleタグの内容が異なる場合

あらかじめ

  • 共通になるURL(パス名)と
  • titleのテキストと付ける仮想URL(パス名)の組み合わせ

を設定しておく。

// トラッカーの呼び出し(デフォルトのトラッキングコード)
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXX-Y', 'auto');

// 設定
// 共通になるパス
var strCommonPath = '/service/form.php';
// 仮想パス名をキー、titleのテキストを値にとる連想配列
var steps = {
    '/service/form/1_input': '会員情報入力フォーム',
    '/service/form/2_confirm': '登録内容の確認',
    '/service/form/3_thanks': '登録ありがとうございました',
};

// 処理
// パス名が共通の場合
if (window.location.path == strCommonPath){
    // すべてのステップを走査し、titleがマッチした場合に仮想パス名をsend pageviewする。
    var matched = false;
    for (var i in steps){
        if (!matched && steps[i] == document.getElementsByTagName('title')[0].innerText){
            ga('send', 'pageview', {'page': i});
            matched = true;
            break;
        }
    }
    // どれにもマッチしない場合、仕方なく共通のパス名を採用
    if(!matched){
        ga('send', 'pageview');
    }
// パス名が共通でなければデフォルトの動作を採用
}else{
    ga('send', 'pageview');
}

ステップに応じて見出し(<h1>)の内容が異なる場合

あらかじめ以下を設定しておく。

  • 共通になるURL(パス名)と
  • 各ステップの見出し(<h1>)に固有に含まれるテキストと付ける仮想URL(パス名)の組み合わせ

たとえば見出しが

  • 会員情報入力画面
  • 会員情報確認画面
  • 会員登録完了

という場合、

  • 入力
  • 確認
  • 登録完了

などが固有のテキストとなる。

// トラッカーの呼び出し(デフォルトのトラッキングコード)
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXX-Y', 'auto');

// 設定
// 共通になるパス
var strCommonPath = '/service/form.php';
// 仮想パス名をキー、h1に含まれる固有のテキストを値にとる連想配列
var steps = {
    '/service/form/1_input': '入力',
    '/service/form/2_confirm': '確認',
    '/service/form/3_thanks': '完了',
};

// 処理
// パス名が共通の場合
if (window.location.path == strCommonPath){
    // DOMから値を取得するのでDOM取得完了を待つ必要がある
    window.addEventListener('DOMContentLoaded', function(){
        // すべてのステップを走査し、h1の内容が部分一致した場合に仮想パス名をsend pageviewする。
        var matched = false;
        for (var i in steps){
            if (!matched && document.getElementsByTagName('h1')[0].innerText.indexOf(steps[i]) > -1){
                ga('send', 'pageview', {'page': i});
                matched = true;
            }
        }
        // どれにもマッチしない場合、仕方なく共通のパス名を採用
        if(!matched){
            ga('send', 'pageview');
        }
    }, false);
// パス名が共通でなければデフォルトの動作を採用
}else{
    ga('send', 'pageview');
}

<title>と同じ。document.getElementsByTagName()の引数が違うだけ。
今回は<h1>に含まれる固有のテキストで部分一致を探したが、それは<title>でも可能。

URLもtitleタグの内容も同じだが、ページ内で表示している画像が異なる場合

前提条件

  • URLが共通となるフォームの遷移にはクラス名「form」を持つ<div>が含まれる
  • 上記の<div class="form">直下の<img>タグがステップによって固有である
  • 画像ファイル名の拡張子を除いた部分を仮想URLとして付ける(拡張子は.jpg

というルールにする。

// トラッカーの呼び出し(デフォルトのトラッキングコード)
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXX-Y', 'auto');

// DOMから値を取得するのでDOM取得完了を待つ必要がある
window.addEventListener('DOMContentLoaded', function(){
    // <div class="form">の直下に<img>が来るパターンをdocument.querySelectorで探す
    var imgStep = document.querySelector('div.form > img');
    // そのパターンがあれば(フォーム遷移であれば)
    if (imgStep){
        // 画像ファイル名の拡張子(.jpg)を除いた部分を取得
        var imgMatched = imgStep.getAttribute('src').match(/([^/]+)\.jpg$/);
        if (imgMatched) {
            // 画像ファイル名の拡張子を除いた部分をパス名に付加してsend pageview
            if (imgMatched[1]) {
                ga('send', 'pageview', {'page': location.pathname + '/' + imgMatched[1]});
            // 例外(imgMatched[1]がない):仕方なく共通のパス名を採用
            } else {
                ga('send', 'pageview');
            }
        // 例外(画像ファイル名の拡張子が.jpgでない):仕方なく共通のパス名を採用
        } else {
            ga('send', 'pageview');
        }
    // それ以外のページであればデフォルトの動作を採用
    } else {
        ga('send', 'pageview');
    }
}, false);

Googleアナリティクス関連Tips

イベント計測

ページビュー計測

eコマース計測