GAとsetAutoTrackOutbound

autoTrackOutBound

2010/01/08 この絵には間違いがある。setAutoTrackOutboundでは、javascriptによる遷移を行う関数が二個ある。ビーコンを飛ばした後に遷移処理がある。この絵では、それが書かれてない。(このトピックの最後で僕が書いたもので気づきました

google analytics には、公式documentがないけど、setAutoTrackOutboundというapiがある。

目的は、外部へのリンクを計測するためのもの。(documentが無いということは、使うなとう意味だと思う)

英語の方のhelp forumでは議論されているみたい。 で、なんでも、外部リンクの計測は二年前から言われてた事だと。

問題になっているのは、ga.jsの読み込みタイミングとか、hrefのrequestとpageTracker._trackPageviewのタイミングとかで、計測漏れなどの問題があるのかもしれないし、いろんな事情があるのかもしれない。

参考記事: Tracking Outbound Links — The Right Way

こちらは議論には関係ないけど、計測するのに参考になる記事: Google Analyticsで離脱リンクを自動計測する方法 (_trackEventを使ったもの。trackEventの方が利用状況を使って外部への離脱までの時間が計測できるので、有用かなと思います。)

利用方法(非推奨です)

2009/11/19 送ったデータは、レポートには反映されてなかった。tracking code側は動いても、レポートには反映されないよう。

ドキュメントに無いものなので、試す価値もないけど、調べたので、一応動かしてみた。

pageTracker._setAutoTrackOutbound([]);([]は、計測しないdomainを入れておく、今回はそのまま計測するので[])

した後に、

pageTracker._trackPageview();

とする。

これで、画面遷移前にビーコンが飛ぶ。

下図は、FireBugで見たビーコンのパラメータ(utmhn(ホスト名)と、utmeの中のurlのドメインが違う)

WS000002

具体的な処理は、冒頭の絵に留めて起きます。

使える設定としては、

  • 計測しないドメインの設定 (とりあえず、ビーコンが飛(ぶ/ばない)のは確かめた。)
  • onclickの処理の最後に、独自の関数を設定 (firefoxで確かめた)
  • linksを集める時の上限を設定???(ちょっと、ロジックが不明、utmbの値に関連するみたいだけど、毎回10にresetされる気がする、たぶん、1000回。試してないけど)

ぐらいができます。

*ちなみ、6はoutboundに割り当てられたkey(utmeに出てくる)だと思う。customVarやtrackEventにも使われれて、

  • 5 – trackEvent
  • 6 – outbound
  • 8 – name(customVar)
  • 9 –  value(customVar)
  • 11 – scope-level(customVar)

現状はそうなってます。

ドキュメントされてない機能は、情報もサポートもないので、おとなしくEventListenerに追加してく方が賢明なのは、言うまでもないです。

ga.jsのキャンペーン処理関連の動きを追う。

修正: 2009/11/16 16:45(いろいろ書き直しました)

前回の処理の続きです。

initData内の3つの処理を見るシリーズで、今回は3つめのutmzの処理(キャンペーンに関する部分)です。

  1. 新規セッションなのかどうか(utma, utmb, utmc)
  2. utmvの処理(setVar, setCustomVar)に関する所
  3. utmzの処理(referrerを、どうutmzに組み込むか) (この記事)

他の回と同様に、Ga.jsのコードを追います。(変数名は、私の独自定義です)

initData()の中で、

campaignManager = new Z.Camp(

b.domainhash, b.modifiedreferrer, b.time, defaultvalues);

という感じで、utmzを扱うオブジェクトを作っておいて、

b.Ta = campaignManager.cc(b.cookiemanager, b.isNewSession)

cookie全体の操作を扱うオブジェクトと,1の新規セッションかどうかを判定したフラッグ変数を引数に、メソッドを実行します。

返値は、””, utmcr=1, utmcn=1です。キャンペーンに関係なければ、””, nがnew campaignで、rがrepeart campaignだと思います。

それで、campaingManager.cc(b.cookiemanager, b.isNewSession)の動きです。

いろいろな条件分岐で、referrerとcookienのutmzの部分を見て、キャンペーンに関係のあるセッションか? 関係あるなら、新規キャンペーンか既存か?を判定しています。

最終的に、その判定を返り値で、メインのAPIを操作するオブジェクトのプロパティに返して、データ送信時に使います。

条件としては、以下の状態return “”になります。(3パラメータ条件=”id, source, gclid”のいずれかがある)

  1. pageTracker._linkのタイプで飛んだ先の場合、既にキャンペーンがあれば、return “”
  2. 3パラメータ条件を満たすけど、urlのパラメータにnooverride=1が入っていたら、return “”
  3. sourceに検索エンジンの値を入れる。このとき、無視するキーワード(自分host名とかにaddIgnoredOrganicで設定)なら、return “”
  4. 検索エンジンの値が無い+新規セッションの場合、sourceに参照サイトを入れる。無視する参照元なら、return “”
  5. 参照元もない+新規セッション+utmzの蓄えがない場合、sourceをDirectとする。
  6. 3パラメータ条件に当てはまらない場合には、return “”

で、上の条件で、return “”とならなかった場合には、

  1. (新規セッション Or utmzの値とreferrerからの値にズレ)  の時、utmcn=1を返す
  2. それ以外は、utmcr=1を返す

という作業になります。

これで、initDataの3つの処理は終わりになります。

その後、trackePageviewなら、特殊処理をして、requestを飛ばす作業に入るし、他の設定系のAPIの場合は、値を返したり、Setしたりする作業に移っています。

コードにつけたメモを付けておきます。(中身はあまり信用しないで下さい、指摘してもらえるとありがたいです)

       //initDataで呼ばれるもの
     //return "" or "&utmcn=1" or "&utmcr=1"
     //arguments g=>"cookiemanager, h=>"isNewVisit?"
     cmp.cc = function (cookiemanager, newsession) { //?, h
       var k = "",
       n = "-",
       r, a = 0,
       d, l, domainhash = cmp.c;
       if (!cookiemanager) return "";
       l = cookiemanager.getCookieStr(); //lにcookie値を入れる
       k = cmp.getSearchTerm(dfvls.a["location"]); //kにはsearchが入る
       //_linkで遷移してきて、validataに通った場合
       if (dfvls.allowLinker && cookiemanager.verify()) {
         n = cookiemanager.na(); //utmzに関する値が、cookiemanager内変数のutmzArにあるか?
         //linkで飛んだ先に、既存のcampaignがあれば、return ""
         if (!NoVl(n) && !GaIndexOf(n, ";")) { //nに値があり、;がきちんとあれば、
           cookiemanager.Ga(); //utmzの値をcookieに書き込み
           return ""; //campaignには関係なしと
         }
       }
       n = Q(l, "__utmz=" + domainhash + ".", ";"); //nには今までのcookieにあるutmzが入る
       r = cmp.setAndGetDataHolder(k); //rに$.Camp.DataHolderオブジェクトがはいる, kはlocation.searchパ\
ラメータ

       //nooverride=1の時
       if (cmp.L(r)) {
         k = Q(k, dfvls.utm_nooverride + "=", "&"); //nooverrideの値を取得
         if ("1" == k && !NoVl(n)) return ""; //1で utmzに値があれば、""
       }

       //無視する検索ワードの場合に return ""
       if (!cmp.L(r)) { //id, source, gclidのどれもない
         r = cmp.setOrganic(); //new Z.Camp.DataHolder()が入る
         if (!NoVl(n) && cmp.isIgnoredTerm(r)) return ""; //追加の無視キーワードであれば
       }

       //新規セッションなら、referrerを調査して、無視する検索キーワードならreturn ""
       if (!cmp.L(r) && newsession) {
         r = cmp.setReferral(); //referralをsetしたcmp.DataHolderが入る
         if (!NoVl(n) && cmp.isIgnoredRef(r)) return ""; //無視する参照元なら、""
       }

       //新規セッションで、cookieが""なら直接参照をset
       if (!cmp.L(r)) if (NoVl(n) && newsession) r = cmp.setDirect(); //utmzが空なら、直接参照

       //directでsetしたなら、return ""
       if (!cmp.L(r)) return "";

       //utmzに値があれば、referrerのものと比較
       if (!NoVl(n)) {
         //a [ <domainhash><birth-time><num_of_session><num_of_camp> + csr]
         a = n.split(".");
         d = new Z.Cmp.DataHolder;
         d.setValueFromStr(a.slice(4).join("."));//utmzのutmc値から、dオブジェクトに値をset
         d = ToLower(d.getStr()) == ToLower(r.getStr()); //dオブジェクトの値を文字列化して、比較
         a = a[3] * 1; //aにはキャンペーンセッション回数
       }
       if (!d || newsession) {//cookieとreferrerが違うか、newsessionなら
         //utmaの値を取得
         newsession = Q(l, "__utma=" + domainhash + ".", ";");
         //最後の"."の場所を取得
         l = newsession.lastIndexOf(".");
         //session回数を取得 l>9にならない場合があるのか? domain-hashが1でも、session-idがあるし?
         newsession = l > 9 ? GaSubstr(newsession, l + 1) * 1 : 0;
         a++; //campain-counterを++
         //0を1に。他はそのまま
         newsession = 0 == newsession ? 1 : newsession;
         //referrerからの値で、cookiemanagerに値をSet
         cookiemanager.wb([domainhash, cmp.timenow, newsession, a, r.getStr()].join("."));
         cookiemanager.Ga(); //書き込み
         return "&" + "utmcn=1";
       } else return "&" + "utmcr=1"; //repeartの場合は、utmzは変更しない
     };
   };

ga.js: 新規セッション管理部分

コードのコメントをそのまま載せておく形式で書きます。

この処理の部分は、initDataの中のb.pcが担当なんだけど、(bとかpcは、compile化された後の変数なのでsourceで名前は不明)

* ga.jsのversionは、4.5.9

initDataの前提として、

  • そのinitDataが呼ばれるのは、
    • trackePageview, GASO, trackEvent, CustomVar関連, link, setAutoTrackBound(使われてない)、、などなど
  • 処理の中身は、3つに分けられる。
    1. 新規・既存セッションの判別・処理(b.pc)
    2. utmv(CustomVar)に関する処理(n.tc)
    3. utmz(Campaign)に関する処理(c.mm)

となっているのですが、

この記事では、1番の新規・既存セッションの判別・処理部分(b.pc)を見ていきます。

やっていることは、(コードの流れとはずれますが)

  1. pageTracker._linkなどのurl渡しのcookieデータが来た時の処理
  2. ドメインハッシュが一致しているか?(不一致で、新規セッション)
  3. urlからcookieへの値の設定
  4. utmb, utmcでの新規・既存check
  5. 新規なら、utmaをset, 既存ならutmbをsetする(utmbのpageview部分がcountされるのは、送信直前処理)
  6. 実際にcookieに書き込み

では、コードと、僕が付けたコメント

(変数名、関数名は、僕が勝手につけたので、他人が読む意味ないかもしれないけど、他に良い方法が見あたらない)

bがpageTracker変数が参照するオブジェクトになります。

 //セッションに関する処理を行う
   b.pc = function () {
     var timenow = b.r, //現在時間がb.rに入っている
     cookiemanager = b.cookiemanager,     //CookiManagerオブジェクト d
     cookievalue = cookiemanager.getCookieStr(),   //cookieの値を取得 l
     domainhash = b.domainhash + "", //t=b.domainhash ドメインハッシュ "none"なら1
     o = dfvls.e,     //dfvlsは初期値格納オブジェ、.eはwindowsオブジェになっている
     u = o ? o.gaGlobal : undefined, //たぶん、そのままwindowsオブジェクト
     y,           //アンカーで"#"を指定した場合に、アンカー以下のURIが入ってくる
     B = GaIndexOf(cookievalue, "__utma=" + domainhash + "."), //_utmaある?
     O = GaIndexOf(cookievalue, "__utmb=" + domainhash),       //_utmbある?
     ma = GaIndexOf(cookievalue, "__utmc=" + domainhash),     // _utmcある?
     G,          //_utmaの値を格納
     J = [],     //_utmbの値を配列で格納
     S = "",    //y+"&"
     ha = false; //gaGlobalの判別flag(ドメインハッシュが一致しない場合はtrue)
     //b.pcの内部変数宣言終わり

     //"-"とかを""にする
     cookievalue = NoVl(cookievalue) ? "" : cookievalue;

     //c.allowLinkerはsetAllowLinker(true)で1
     //urlから値を取得、この時に、utmkがハッシュでの改ざんcheckになる
     if (dfvls.allowLinker) {
       y = dfvls.a["location"] && dfvls.a["location"].hash ? dfvls.a["location"].href.substring(dfvls.a["location"].href.indexOf("#")) : "";
       //b.setAllowAnchorで設定, anchorでの文字列があれば、Sに代入
       if (dfvls.allowAnchor && !NoVl(y)) S = y + "&";
       //search部分も引っ付ける
       S += dfvls.a["location"].search;
       //Sに_utmaが含まれれば
       if (!NoVl(S) && GaIndexOf(S, "__utma=")) {
         debugger;
         cookiemanager.setValuesAndG(S); //Sの値をcookieに入れて、utmk値をGにSet
         //verifyで、gが未設定か、urlの値がきちんとcookieに入ったかをHashでcheck
         //失敗なら、gはundefinedに、utmA..Z設定用変数の中身もclear
         cookiemanager.verify() || cookiemanager.Sb();
         G = cookiemanager.ja(); //_utma設定用変数から値をGに Sb()を実行した場合には、G="-"となる
       }
       //utmxのsetter, getter, cookiewriter, true(Decodeする)
       //utmx をcookieに書き込み
       n(cookiemanager.ma, cookiemanager.vb, cookiemanager.Eb, true);
       //utmv をcookieに書き込み
       n(cookiemanager.la, cookiemanager.Aa, cookiemanager.Fa);
     }
     //以上でAllowLinkerがtrueの時の作業終わり

     //通常(linkでない)の場合と、上記でutmaがなかった場合
     if (NoVl(G)){
       //Bは、domainHashに対応したutmaのcheck-flag
       if (B){
         //utmb, utmcが無い場合、新規セッション
         if (!O || !ma) {
           //utmaの値を現在時間で更新して代入
           G = setUtmaArray(cookievalue, ";", timenow);
           //b.Fは、キャンペーン処理での新規セッション判定に使われる
           b.F = true;
         //継続セッションの場合
         } else {
           //utmaの値を取得
           G = Q(cookievalue, "__utma=" + domainhash + ".", ";");
           //utmbをset, 配列にいれておく
           J = GaSplit(Q(cookievalue, "__utmb=" + domainhash, ";"), ".");
         }
       //utmaのドメインハッシュが一致しない
       }else {
         //新規にutma用の配列を作る
         G = GaJoin([domainhash, b.jc(), timenow, timenow, timenow, 1], ".");
         //新規セッションflag
         ha = b.F = true; //haはGaGlobalで使う
       }
     //utmaがあるけど、utmb or utmcがない=>新規セッション
     }else if (NoVl(cookiemanager.C()) || NoVl(cookiemanager.ka())) { //utmb, utmcのどちらかが、"-"だったとき
       //値を現在時間で更新してGに入れる
       G = setUtmaArray(S, "&", timenow);
       //新規セッションflagをtrueに
       b.F = true;
     //utma, utmb, utmcあり
     } else {
       //utmbをset
       J = GaSplit(cookiemanager.C(), ".");
       //utmbの先頭要素がドメインハッシュに?
       domainhash = J[0];
     }
     //G(utma), J(utmb)の設定終わり

     G = G.split(".");

     //gaGlobalがある時
     if (o && u && u.dh == domainhash && !dfvls.namespace) {
       G[4] = u.sid ? u.sid : G[4];
       if (ha) {
         G[3] = u.sid ? u.sid : G[4];
         if (u.vid) {
           timenow = u.vid.split("."); //from string to array
           G[1] = timenow[0];
           G[2] = timenow[1];
         }
       }
     }

     //utmaの値を、クッキーマネージャーオブジェクトにset
     cookiemanager.tb(G.join("."));
     //utmbをsetしていく

     J[0] = domainhash;
     J[1] = J[1] ? J[1] : 0;
     J[2] = undefined != J[2] ? J[2] : dfvls.Jc; //dfvls.Jc = 10
     J[3] = J[3] ? J[3] : G[4]; //session開始時間

     //utmbをset
     cookiemanager.ya(J.join("."));
     //utmcをset
     cookiemanager.ub(domainhash);
     //クッキーマネージャーオブジェクトの変数gがなければ、
     //cookiemanager.setG(cookiemanager.getAllStr())でutmkの値を入れる
     NoVl(cookiemanager.lc()) || cookiemanager.setG(cookiemanager.getAllStrToHash());
     //utmaをcookieに書き込み
     cookiemanager.Cb();
     //utmbをcookieに書き込み
     cookiemanager.Ea();
     //utmcをcookieに書き込み
     cookiemanager.Db();
   };
    //End of b.pc()

ga.jsの中のtrackePageview()

ga.jsの理解メモ。わかる所からOutPutすることにします。アドバイスのある方は、指摘をお願いします。

ga.jsのオブジェクト

中にあるものを列挙する。

  • $:       windowsオブジェクトに入る。他のオブジェクトの名前空間?上の親になる
  • $.Fb:    初期値が設定されているオブジェクト。
  • $.Kb:   $.getTracker(propety-id)を呼ぶと作られる。APIを提供する。trackePageviewとか、trackeEventとか、setCustomVarとか
  • $.$:     cookie情報をマネージする。中で、$.Gbを動かす
  • $.Gb:    $.$の元で、実際のcookieの読み出し、書き込み、を行う。
  • $.Jb:    データをサーバーに送るリクエスト部分を仕事にしている
  • $.Hb:   cookieへの処理$.$に命令する。setCustomVarとかもやることになる。
  • $.m:    utmz周りの管理。$.m.wは、campaignの値をプロパティに持つオブジェクト。
  • $.n:     ecommerce周りのデータの管理。$.n.Mbとかはデータ保持用?
  • $.Eb:   システムやブラウザ情報を取得するオブジェクト
  • $.N:    trackEvent関連の処理。customVarの値にも関連する(独自にデータを送らなくなったので)

これだけ。

pageTracker._trackPageview()の流れ

順にいくと、

  1. ga.jsがloadされて、実行される。
  2. windowオブジェクトに、_gat($オブジェクト)という参照ができる。
  3. _gatには、上に挙げたオブジェクトのconstructorと、_getTrackerという関数が、プロパティとして作られる。
  4. _gat._getTracker(property-id)で、APIが定義されている$.Kbが newされ、pageTracker変数を作り参照させる。
  5. pageTrackerのAPIのひとつ、_trackPageviewを実行させる。

で、で、5の_trackPageview。大きく見ると、二つの実行式がある。ちなみに、bはpageTrackerオブジェクト。

  1. b._initData()
  2. b.Kc;

で、で、で、1の b._initData()

これは、他の多くのAPIでも、最初に呼ばれるメソッド。以前はAPIのリストに入っていたけど、今は内部で働くメソッドとして扱われている。最初に説明したコンストラクターが、あちこちでnewされている。

b._initData()の流れ。

  1. b.A = new $.Eb(); b.A.bc();
    • ここで、システム情報やブラウザ情報を取得している。
  2. b.d = b.fc();
    • ドメインチェック。setDomainName(“none”)なら、1が入る。そうでなければ、ドメインハッシュ。
  3. b.i = new $.$(c)
    • クッキーの値を管理するオブジェクトが入る。cは、$.Fbで作られる初期化オブジェクト。APIの設定をすれば、このcのプロパティに値を設定しとける。
  4. b.g = new $.N()
    • setKeyやらValueやらのメソッドが定義される。
  5. n = new $.Hb(c, b.d, b.i, b.g)
    • ここまでで、作ったプロパティの値と、c=(new $.Fb())の値を引数にして、
    • $.Hb()で、実際にcookieへの読み書きを$.$に指示する。
    • ちなみに、n.Mは、utm[abcxzv]がそれぞれ配列で入る。
  6. b.rc()
    • 中で、k = new $.Jb(c)として、送信用のオブジェクトを作っておく。
  7. b.pc()
    • ここで、セッション判定に関わる処理をする関数を呼ぶ。utma,utmb,utmcとかを見る。
  8. n.tc()
    • 5で作ったnのメソッドを実行。utmvの処理など。cookieなどへの書き込みも。
  9. b.ga = b.Yb(b.Za)
    • referral情報の取得
  10. b.Ra = (new $.m(b.d, g.ga, b.r, c)).cc(bi, b.F)
    • utmzの処理をするオブジェクトを作る。キャンペーン管理の。ccではutmzの処理が行われる。
    • 引数のb.iは、クッキー管理オブジェクトの$.$。b.Fは、新規セッションならtrue,じゃなければfalse。
  11. b.ab = new $.N()
    • new $.N()は二回目の実行(二個目のオブジェクト)。これはtrackEvent用。
  12. p = s
    • sはtrueなので、pをtrueにする。9-11はp==falseが条件。重複処理を避けるためか、initDataはあちこちで呼ばれるし。
  13. $.gb || b.sc()
    • Gasoオーバレイ関連の処理 $.gbはb.scの実行でtrueになる。一度initDataが実行されれば、b.sc()は呼ばれない。

initDataはこんな感じ。

b.Kc(a)の中

trackPageviewのもう一つの実行式のb.Kc(a)。

引数のaは、trackPageview(a)のa。pagePathをでっち上げる時に指定する引数。

短いのでコードを出す。

 b.Kc = function (a) {
   if (b.J()) {
      var d = "";
      if (b.g != w && b.g.G()[y] > 0) d += "&utme=" + T(b.g.G());
      d += b.ua(a);
      k.H(d, b.s, b.d);
   }
};

順に見てく。

  1. if(b.J())
    • これは、b.J=function(){return b._visitCode() % 10000 < c.U * 100} b._visitCodeはutmaのなかの二番目を値(sessionユニーク値)を返す。c.Uはサンプルレート。デファルトで100。なので、通常100%でb.J()はtrue。
  2. if(b.g.G(),,,,,
    • b.gは、$.Nオブジェクト。追えてない。utmeはtrackEventの値を送信するのに使われるものなので、その辺りに関係しそう。
  3. d+=b.ua(a);
    • データ送信用文字列作成。b.Aやc( $.Fb初期化オブジェクト)、キャンペーンかどうかとか(utmcr(n))など。
  4. k.H(シス情報, アカ情報, 現在時刻)
    • kは(new $.Jc()); initDataの処理の中で作られている。
    • k.H()は送信処理。$.Jbオブジェクトの中で、<img>タグを作ってDomに埋め込む作業が行われている。

これで、b.kc(a)は、終わり。

trackPageviewの処理の流れ(b.initData(), b.Kc())は、以上。

表面をなぞっただけだし、目的のセッション判別や、キャンペーンの値の処理などまで、届かなかった。

次回に、その辺りを書く。