ページ遷移レポートの自動配信を実現する

前回、スクロール計測のレポートを自動配信する話を書いたのですが、今回は、Google Analtyicsのページ遷移データをグラフ化してメール配信する話です。

同じく、google apps script + google chart api でのメールによるレポート配信です。

AuthSubでの作成も作りました。試してみてください。

Google Analyticsにおけるページ遷移のデータ

あるページにおける、遷移上の前後のページは、WEBのレポート画面で見ることができます。ナビゲーションサマリーですね。ナビゲーションサマリーの数字の見方は、以前Wikiの方に書きました。

WEB上のレポート画面では、重複ページの回数を抜いて、パーセンテージにして表示してます。(移動先のデータ(nextPage)のデータがよく分かってないのですが、、)

今回は、Data Export APIでデータを持ってくるので、重複ページを抜かないとと思っていたら、uniquePageviewの数字がそのままの数字なので、端折って、uniquePageviewの数字を使いました。uniquePageviewを使う妥当性について、Forumなどで質問があったみたいですが、数値を見る分には大丈夫そうなので、uniquePageviewを使います。単に重複を抜くためだけですが。(もう少し考えてみた。けっこう注意が必要かも)

とにかく、ディメンジョンに, “priviousPagepath”と”nextPagePath”。指標に uniquePageviewを使います。

Google Chart APIの GraphViz Chart

前回のデータを表示する時に、chart apiの文書を見てたら、おもしろいチャートの種類を見つけました。 Connectivity graphsとかいてあります。日本語だと 連結グラフ?

これも、パラメータを指定するだけで、グラフをimageにして返してくれます。またしても、パラメータの設定が難しかったのですが、PDFの説明書みたいなのを見ながら設定してみました。微妙に chart apiでの記述と、h本家の記述と違う部分もあると思います。subGraphも設定できるみたいで、それでクラスター表示みたいなのをしようと思ったけど、Google Chart Api側で、動くように設定する方法がわかりませんでした。(* google chart apiでの方法を知っていたら教えてください。)

前回も書きましたが、http://code.google.com/apis/chart/docs/chart_playground.htmlでできるチャート図を確認しながら、設定をいじれるので、便利です。

とりあえずの例

それで、実際にこのサイトのデータで生成してみました。メールレポートの場合は、google apps scriptでHTMLメールを使って、scriptの自動実行時間を指定すれば良いです。参考に、ちょっと違うけど、フォーム受付けを自動返信する話です。今回は、これを時間指定にするだけです。

できたimage画像です。 (画像クリックでできたURLそのものに遷移します)

閲覧開始数のベスト8ページのデータと、ページ遷移の組み合わせで数が多かったベスト10のデータを抜き出してます。頭に数字があるのは、そのページの期間内の閲覧開始数です。矢印線上にある数字がページ遷移の数です。 数字だけの奴(_108_)は、indexページです。閲覧開始数が108でした。

(自分自身に返ってる奴は、データの初期段階でパラメータが違うものをカットしたせいです。処理が粗いです。説明もゴニョゴニョですが、、)

サイトオーバーレイもいいですが、サイト全体のユーザーの動きはコチラのほうがイメージし易いと思います。

気を付ける点としては、上のリンク先の記事でも説明してるのですが、セッションベースのデータでないので、遷移の数は、ランディングからすぐに遷移した数ではないです。 secondPagePathもデータとしてはあるので、そちらでもグラフはかけそうではあるのですが、、、

あと、chart apiで生成できるピクセル数の大きさは、縦×横で、300000pxまでなのですが、このgraphVizでできるデータはそれを超えてます、、、、また、これはexperimentのマークがついてるので、仕様変更の可能性もありそうではあります。

それでも、自動化できたので、データを見せていただける方には、メールで日次配信します(コメントで遷移図希望と書いて下さい)。今回のは、Google Analtyisの初期設定で取れるデータなので、閲覧権限をもらえれば、それでOKです。 Auth認証でのデータ表示に対応するのは、詳しい人なら簡単にできそうなので、そういう人に任せます。

google apps scriptと chart apiを使ったレポート自動化

今回は、アクセス解析の話ではないのですが、データとして GAを使ったので、ここに書きます。

前回、スクロール率をgoogle analyticsで計測した話を書きました。 レポート部分は、エクセルでの表示だったんですが、今回、自動化のひとつの方法として、タイトルの方法をやったので、報告します。

Google Apps Script(GAS)は、かなりの便利ツール

データを外部から引っ張ってきて、加工して、メール配信というのが、割合簡単にできます。

今回は、google analyticsのデータを引っ張って、加工して、HTMLメールで配信という形の紹介です。

GASの記述は、javascriptです。 google analyticsの集計の設定も javascriptですので、 javascriptは習得しがいのある技術かもしれません。

手順としては、URLFetchで google analytics Data Export  Api からデータを取得して、それを google chart apiを使って、 HTMLメールで送る作業です。

Google Chart APIも、自動化ツールとして価値大。

URLを指定すれば、チャート画像を返してくれます。

ですので、変化する数字を自動的にグラフ化してレポーティングしたい場合に価値が高いです。

パラメータがたくさんあって、マニュアル(解説)が英語なのでとっつきにくいですが、データ、チャートタイプ、ラベル、軸、などの概念とapiでのパラメータが一致すれば、それなりに使えるのではと思ってます。

別サイトにメモみたいなのを書きましたが、、、あまり参考にならないかも。

GMailの問題?

いろいろいじって、なんとか自動化にこぎつけたのですが、GmailのHTML表示の時に、imageタグの部分が上手く表示されなくて、いろいろ探したのですが、結局あきらめました。 たぶん、文字数の問題のような気がしてるのですが、、、どうなんでしょう。 Yahoo Japanの Web mailなら問題なかったです。

出力画像と スクリプトを貼りつけます。

スクロール計測とそのレポート配信を試してみたい方は連絡下さい(コメントでスクロール計測希望と書いてくだい)。 設定して、週次 or 日次で、特定のディメンジョンで切ったスクロール率のよる閲覧割合をメールレポーティングします。無料です。 以下の画像のような形でのHTMLメールが送られます。

画像レポートの後に、参考に、GASのスクリプトを貼りつけておきます。 貼り付けた以外にも追加の定義(関数、代入式)などがあるので、全部ではないです。

2010-06-03から2010-06-15のセッション数上位3ページの精読率調査です。数字はセッション数です。

以下、レポート配信に使ったscriptの一部。

function CRReport(id,name,title,address){
    //id = "ga:21600568", name="shirai", title="wordpress", address="kimiyuki[at?]gmail.com";
    var startdate; var enddate; var dimensions = []; var metrics = []; var filters = ""; var segments = "";
    var entries; var sort;var data;
    var tmp;
    var siteurl;
    startdate = getMyDate(-15); enddate = getMyDate(-3);
    dimensions = ["ga:pagePath,ga:hostname"]; metrics=["ga:visits"]; sort=["-ga:visits"];
    entries =  getDataFromApi(id, startdate, enddate,dimensions, metrics, filters, segments, sort);
    pagePaths = [];
    entries.slice(0,3).forEach(function(entry){
        var el = entry.getElements("http://schemas.google.com/analytics/2009", "dimension");
        el.forEach(function(e){
            if(e.getAttribute("name").getValue() == "ga:pagePath") pagePaths.push(e.getAttribute("value").getValue());
            if(!siteurl && e.getAttribute("name").getValue() == "ga:hostname") siteurl = e.getAttribute("value").getValue();
        });
    });             
    
    data = {};
    var w1 = [null,null, null]; var w2 = [];
    pagePaths.forEach(function(path){
        Utilities.sleep(500);
        w1 = [null,null,null], w2=[];
        var dim_sg = "ga:medium";
        dimensions = ["ga:eventCategory", "ga:eventAction", "ga:pagePath",dim_sg]; metrics = ["ga:uniqueEvents"]; sort = null;
        filters="ga:eventCategory==CompRead0523B;ga:pagePath==" + path;
        segments=null;
        entries = getDataFromApi(id, startdate, enddate, dimensions, metrics, filters, segments, sort);
        entries.forEach(function(entry){
            var ds = entry.getElements("http://schemas.google.com/analytics/2009", "dimension");
            var es = entry.getElements("http://schemas.google.com/analytics/2009", "metric");
            var w = new Array();
            ds.forEach(function(e){
                if(e.getAttribute("name").getValue()=="ga:eventAction") w1[1] = parseInt(e.getAttribute("value").getValue().replace("z",""));
                if(e.getAttribute("name").getValue()== dim_sg){w1[0] = e.getAttribute("value").getValue();}
            });
            es.forEach(function(e){
                if(e.getAttribute("name").getValue() == "ga:uniqueEvents") w1[2] = parseInt(e.getAttribute("value").getValue());
            });
            w2.push([w1[0], w1[1],w1[2]]); //値にして設定するため
            w1 = [null,null, null];
        });
        w2 = w2.sort(function(a,b){return a[1] > b[1]});
        if(data[path] == null) data[path] = [];
        data[path] = w2.map(function(x){return x});
        //data[path] = w2.map(function(e){return [e[0], Math.floor((e[1]/total)*100)]});
    });
    // Logger.log(data);
    html = outputChart(data, startdate, enddate, siteurl);
    Logger.log(html);
    MailApp.sendEmail(address, "CompRead","html mail", {cc: "kimiyuki[aat]gmail.com", htmlBody: html});
}


function outputChart(data, startdate, enddate ,siteurl){
    var html = "
" + startdate + "から" + enddate + "のセッション数上位3ページの精読率調査です。数字はセッション数です。
"; for(e in data){ //Logger.log(e); //Logger.log(data[e] instanceof Array); //Logger.log(data[e].length); //Logger.log(data[e].toString()); //making dimentionable data var dimmed_data = data[e].reduce(function(r, x){ if(r[x[0]] == null){ r[x[0]] = x[2]; }else{ r[x[0]] += x[2]; } return r; }, {}); //Logger.log(dimmed_data.toSource()); var tmp = []; Logger.log("object="); Logger.log(dimmed_data.toSource() + "n"); for(c in dimmed_data){tmp.push(])}; dimmed_data = tmp.sort(function(a,b){ return a[1] < b[1]}); Logger.log("dimmed_data="); Logger.log(dimmed_data.toString()+"n"); var label = data[e].map(function(x){return x[1]}).unique(); var data1 = data[e].filter(function(x){return x[0] == dimmed_data[0][0]}).map(function(x){ return x[2]}); var data2 = data[e].filter(function(x){return x[0] == dimmed_data[1][0]}).map(function(x){ return x[2]}); var data3 = dimmed_data.length < 3 ? "" : data[e].filter(function(x){return x[0] == dimmed_data[2][0]}).map(function(x){return x[2]}); //Logger.log(label); //Logger.log(data1); //Logger.log(data2); //html += "" + e + "
" + data[e].map(function(x){return x[0] + '=>' + x[1]}).join(',') + ""; html += "
"; html += makeChart(label, data1, data2,data3, dimmed_data[0][0], dimmed_data[1][0], (dimmed_data.length > 2 ? dimmed_data[2][0] : "")); html += "
"; html += "" + e + "
"; html += "
  
" //全角空白を入れた。間隔を作るため } html += "
"; return html; } function makeChart(label, data1, data2, data3, dataLabel1, dataLabel2, dataLabel3){ var max = data1.concat(data2).reduce(function(r, e){return r > e ? r : e;}, 10); var chds = "chds=" + "0," + max; var chxr = "chxr=1,0," + max; var chco = "chco=4d89f9,c6d9fd" + (data3 != "" ? ",63C6DE" : ""); var chdl = "chdl=" + dataLabel1 + "|" + dataLabel2 + (dataLabel3 != "" ? "|"+dataLabel3 : ""); var chm = "chm=N,000000,0,,12,0,e|N,00FFFF,1,,12,0,e" + (data3 != "" ? "|N,0000FF,2,,12,0,e" : ""); var url = ""; //Logger.log(url); return url //.replace("&", "&"); }

ページのどこまで読まれたかを計測する

ウェブサイトのコンテンツをページングするのはユーザビリティを損なう事が多いと僕は思ってます。ユーザビリティの定義は知りませんが、読むこと以外に”意識”を取られると嫌な感じがします。 提供側の論理は知りません。ユーザビリティですから。

次のページへのリンクをクリックという行為は、

  1. そのアンカーテキストに目の焦点を併せる
  2. マウスを叩く
  3. リンク先のページがloadされる。

という順番で進むと思います。

速読の練習をした人はよく分かると思いますが、1の行為は、文字を探し・焦点を合わせるという、非常にコストのかかる行為です。読むという作業においては。。文脈を追う作業は超短期記憶のつなぎ合わせで、意識のallocation作業は天敵です。

一方で、アクセス数字を見たい人に取っては、ページ単位の計測が基本である以上、ページとコンテンツの粒度は一致してる方がいいと思ったりします。<h2> <h3>といった見出し単位での閲覧率を知りたいと思ったりすると思います。閲覧時間の方が知りたいかも、、、 とにかく、ページ閲覧量と滞在時間ではなくて、コンテンツ消費量とコンテンツ消化速度を知りたいとか思うと思います。

ヒートマップ使ったり、細かく計測タグを作れば、データは得られそうですが、面倒です。

で、とりあえずの一歩として、ページ全体でどの割合までページが表示されたかを、google analyticsで計測してみたので、その経過を書きます。

EventTrackで、表示領域割合をアクションとして送る。

当初、表示割合を計測するのに カスタム変数のページスコープ変数を使えばいいのかと思いました。上手く説明できないのですが、ページスコープは使いにくい機能(*)なので、前に使った手法(ページ別閲覧時間分布の作成)と同じような手法のtrackEventを利用する方法でやりました。

* ページスコープのカスタム変数を設定してtrackPageviewで送ったら、それは新規のページビューになってしまう。動的な行動記録をアトヅケで送れない。

それで、方針としは、

  1. 一秒毎に、画面の表示位置(割合)を取得。
  2. それが、そのページ閲覧中で最大値を超えていたら、trackEventする。
  3. 10%単位で区切る。google analyticsでは集計値しか取れないので、値は積み上げで送る。
    • 30%まで閲覧されたというデータを送る場合には、0, 10, 20, 30 と送る。
    • なんとなくだけど、データの連続送信制限があった気がしたので、少しsleepを入れておく。
    • このサイトのrs.jsという奴です。データを送る順番をコントロールするために、jsdeferred.jquery.js をいれました。このサイトの説明を参考にした

データを見る : totalEventsとpageviews

eventの数字を見るときは、totalEvents(イベント数)と uniqueEvents(ユニークイベント数)の二つを見ますが、uniqueEventは、セッション内の同一カテゴリ・アクション・ラベルを一つ(distinct)にします。

image

自作のDataViewerで見たところ。labelにページURL(path)を入れていたのですが、ディメンジョンとして pathPathも有効なので、labelは他の用途に振り向けてもいいかもしれません。

ちなみに、ABテスト別に見たい時は、カスタム変数を出してフィルタリングします。

ab_test_for_how_much_viewed_againt_content

ちなみにこの自作ツール、チョコチョコ改良してます。、カスタムレポートを組むより、操作時間は短いはずです。 日別のデータ作成には便利です。 GAのレポート画面だと、日別のデータをグラフにしてくれますが、数字で出すには、カスタムレポート組まないといけない。

レポート化

アクセス解析サミットで清水さんの講演を見て、スクロール計測のレポートの形式を真似ました。

image

画像にパーセントで線を入れるのにbookmarkletを実行、画像を撮って、エクセルでrept関数。

javascript:hg=document.height;wd=document.width;for(var i=1; i<10; i++){dv=document.createElement("div");dv.innerHTML= "<hr style=’color:#f00; background-color:#f00; height:5px;’/><strong>"+(i*10).toString()+"Percent==></strong>";dv.style.position="absolute";dv.style.top=parseInt((i/10)*hg).toString()+"px";dv.style.left="0";dv.style.width=wd+"px";dv.style.zIndex="1000";document.body.appendChild(dv.cloneNode(true));}

このbookmarkletは適当に作ったもの。 ページ全体画像撮りは、このchromeのextensionを使った

このレポートを自動化するには、

bookmarklet実行 + 画像収集 + データ抽出 + どこかで画像オブジェクトにする

という作業が必要。

Google Analtyicsで、trackEventを使って、ページのスクロールの割合を見て、レポートにするまで、でした。 アクションは知らない。