コンテンツごとの接触管理


Google Analyticsを含む大抵のアクセス解析ツールでは、サイトごとでユーザーの新規訪問、再訪問を判別することが可能です。また、ほとんどのツールでは、そのサイトへの訪問回数まで取得することができます。

しかし、場合によってはサイト単位ではなく、コンテンツ単位・ディレクトリ単位で新規・再訪や訪問回数を取得したい場合があります。ツールによってはプロファイルを分けることで、取得可能な場合もありますが、多くのツールではコンテンツ単位・ディレクトリ単位で新規・再訪を取得することは実質的に不可能です。

代替案として、JavaScriptとCookieを使って、コンテンツの接触を管理していくことができます。この方法を採ることで、各コンテンツの新規・再訪や訪問回数を取得することが可能です。
(なぜ、代替案なのかというと、セッションの管理が解析ツール側とは、どうしても異なってしまうからです。完璧にツール側とセッションの定義を合わせることは難しいです。)

接触履歴の管理方法

実際にどのようなプログラムを走らせるのかを簡単に説明します。

まずコンフィグセクションで、計測対象とするグループを正規表現で指定します。
初めてサイトへ訪れたとき、初期化処理が走ります。
計測対象とするグループの数を判断して、接触履歴管理用の「箱」を2つ作り、cookieへ保存されます。例えば、5つのグループを計測対象とする場合は、
「a0_b0_c0_d0_e0」という箱が2つ作られます。1つはセッションcookieで、もう1つは永続cookieです。

「a」に該当するコンテンツへ訪れた場合、セッションcookie、永続cookieの両方とも値がインクリメントされ、
「a1_b0_c0_d0_e0」
となります。
もう一度、「a」に該当するコンテンツを訪問してもインクリメントされないようになっています。インクリメントされるのはセッションで1回のみです。そのため、セッションcookieのa~eの後に続く数字は1以上にはならないようになっています。
当然、「b」に該当するコンテンツを訪問した場合、「b」がインクリメントされて、
「a1_b1_c0_d0_e0」

2回目以降のセッションでは、永続cookieはそのまま保持されていて、セッションcookieはセッションの初めに初期化され、
「a0_b0_c0_d0_e0」
となります。
永続cookieの方は、前回「a」と「b」に訪問しているので、
「a1_b1_c0_d0_e0」
のままです。
また、「a」のコンテンツへ訪問した場合、
セッションcookieと永続cookieの両方がインクリメントされて、
セッション:「a1_b0_c0_d0_e0」
永続:「a2_b1_c0_d0_e0」
となります。

このようにして、各コンテンツの接触履歴を管理していきます。
ちなみに各コンテンツの訪問回数MAXは「9」なので、10回以上訪問してもインクリメントされないようにしています。(16進法使うとかありますけど、面倒なだけなので)

プログラム使い方

一応、プログラムを載せておきますが、そのまま使えるかどうかは保証できません。

このプログラムはセッションの開始時のみ、グローバル変数「window.gnrResult」に「a1_b1_c0_d0_e0」のような箱を返すようにしています。これは初回訪問時には、「a0_b0_c0_d0_e0」という空の箱が返され、初回以外では前回セッションの最後の永続cookieの値が返されます。セッション開始時以外は「false」が帰ってきます。

Google Analyticsで利用する場合は、セッション管理に「__utmb」と「__utmc」を使っていますので、必ず計測タグより前の位置でこのプログラムを読み込むようにしてください。

あとは普通に、
if(window.gnrResult){
_gaq.push(["_setCustomVar", 1, window.gnrResult, 2]);
}
みたいな感じで書けば、セッションの最初のみ箱の値がカスタム変数で送信されます。スコープはセッションが良いと思います。

アドバンスドセグメントを使えば簡単に、各セグメントごとの新規再訪でセグメント化することができます。(正規表現「^a0_.+」でセグメントを作れば「a」のコンテンツへの新規訪問者のみのセグメントが抽出される)
各コンテンツへの訪問回数を知りたい場合は。。。気合で集計してください!!

ちなみに、このプログラムはlocation.pathnameでURLを判断しているだけですけど、「リファラー」とか「URLパラメータ」とかで判断できるようにしてしまえば。。。。

group_new_return.js

/*************************************
グループ単位での訪問回数をカウントするスクリプト。

セッション開始時:
cookieから「箱」を読み込んで、グローバル変数「gnrResult」に入れて返す。
cookieがない場合は新規に新しい箱を作って、gnrResultに入れて返す。
箱:a0_b0_c0_d0_e0_f0_g0_h0_i0_j0

通常時:
対象URL群を閲覧した時に、セッションで1度だけ箱の中身をインクリメントする。
セッションで2回以上、対象URL群を踏んでもインクリメントしないように、
クッキーで制御している。
セッション開始時以外は、gnrResultにfalseを入れて返す。
(セッションはga用のcookie(_utmb, _utmc)で判別。)

****************************************/



(function(){

var groupNewReturn = function(conf){
  this.data = conf.data;
  this.cookieName = conf.cookieName;
  this.cookieName2 = conf.cookieName + "_tmp";
  this.c_expires = conf.expires;
  this.MAXLENGTH = 15;
  this.useGA = conf.useGA;
  conf.trackername ? this.trackername = conf.trackername + "." : this.trackername = "";
}

groupNewReturn.prototype = {
    getCookie : function(key) {
    var cookies = document.cookie.split('; ');
      for (var i = 0; i < cookies.length; i++) {
        var part = cookies[i].split('=');
          if (part[0] === key && part[1] !== null) {
          return unescape(part[1]);
        }
      }
    return null;
  },
  setCookie: function(key, value, life_day) {
    var date = new Date();
    date.setTime(date.getTime() + (life_day * 1000 * 60 * 60 * 24));
    document.cookie = key + '=' + escape(value) + '; expires=' + date.toGMTString() + '; path=/';
  },
  makeContainer : function(flag, c_name){
    if(c_name){
      var cookieName = c_name;
    }
    if(flag){
      var cn = this.getCookie(cookieName);
    }else{
      var cn = "";
    }
    if(cn){
      var container = cn;
      return container;
    }else{
      var str = "a0_b0_c0_d0_e0_f0_g0_h0_i0_j0_k0_l0_m0_n0_o0";
      var num = this.data.length;
      if(num < this.MAXLENGTH + 1){
        var container = str.slice(0,(3 * num - 1));
        return container;
      }else{
        console.log("ERROR : too many groups");
        return false;
      }
    }
  },
  checkNew : function(flag){
    if(flag){
      //GA用
      if((!this.getCookie("__utmb"))||(!this.getCookie("__utmc"))){
        return true
      }else{
        return false;
      }
    }else{
      //通常用
      if(!this.getCookie(this.cookieName + "_flag")){
        this.setCookie(this.cookieName + "_flag", "1");
        return true;
      }else{
        this.setCookie(this.cookieName + "_flag", "1");
        return false;
      }

    }
  },
  process : function(){
    var container = this.makeContainer(true, this.cookieName);
    var container_tmp = this.makeContainer(true, this.cookieName2);
    var cont_arr = container.split("_");
    var cont_arr_tmp = container_tmp.split("_");
    var myPath = location.pathname;
    for(var i = 0; i < this.data.length; i++){
      if(myPath.match(this.data[i])){
        if(this.checkIncre(cont_arr_tmp[i])){
         cont_arr[i] =  this.makeIncre(cont_arr[i]);
         cont_arr_tmp[i] = this.makeIncre(cont_arr_tmp[i]);
        }
      }
    }
   var cont_str = cont_arr.join("_");
   this.setCookie(this.cookieName, cont_str, this.c_expires);
   var cont_str_tmp = cont_arr_tmp.join("_");
   this.setCookie(this.cookieName2, cont_str_tmp, this.c_expires);
  },
  checkIncre : function(tmp){
    if(tmp[1]==="0"){
      return true;
    }else{
      return false;
    }
  },
  makeIncre : function(str){
    if(str.length !== 2){
      console.log("Error: it should be 2 bytes");
      return str;
    }
    str1 = str[0];
    str2 = parseInt(str[1]);
    str2++;
    if(!str2){
        console.log("Error: not number, change to 1");
        str2 = 1;
      }else if(str2 > 9){
        str2 = 9;
      }
    return (str1 + str2);
  },
  go : function(){
    // セッション開始時(GA利用時はcheckNewの引数にtrueを使用)
    if(this.checkNew(this.useGA)){
      // クッキーの有無を判断
      //クッキーあり→クッキーの内容を読み込む
      //クッキーなし→空の箱を作成
      var req_container = this.makeContainer(true, this.cookieName);
      //console.log("sent: " + req_container);
      if(!this.getCookie(this.cookieName)){
        this.setCookie(this.cookieName, req_container, this.c_expires);
      }
      //制御用cookieを新規作成
      var st_container = this.makeContainer(false);
      this.setCookie(this.cookieName2, st_container, this.c_expires);
    }
    //通常時
    //マッチした場合、
    //制御用クッキーで、変化済みflagがあれば、動作させない
    //変化済みflagが無ければ、メイン・制御両方ともインクリメント
    this.process();

    //セッション開始時はreq_containerを返す、そうじゃない場合はfalseを返す
    if(req_container){
      return req_container;
    }else{
      return false;
    }
  }
}



//コンフィグセクション
  var config = {
    data : [
    //対象とするディレクトリを正規表現で指定してください。
      /^/enq_test//,
      /^/group/neko//,
      /^/group/usagi//,
      /^/group/inu//,
      /^/group//
    ],
    cookieName : "__utmbox",
    expires : 60,
    trackername : "",
    //GAを利用する場合は、trueにしてください。
    useGA : false
  }

  var gNR = new groupNewReturn(config);
  //グローバルオブジェクトに結果を代入
  window.gnrResult =  gNR.go();
  return  window.gnrResult;
})();

Leave a Reply