拡張eコマース - アナリティクスのトランザクションが毎日3割欠落する問題への対処記録

#概要
Googleアナリティクスの拡張eコマースを実装している環境で毎日3割ほどのトランザクションが抜け落ちていました(ひいてはアナリティクスのROASに影響)。この対応に当たった過程を記します。

この記録から言えることは以下2点です。

 - データ収集の制約は意外と無視できない ([特定した要因はこちら](https://qiita.com/drafts/e6b0a38686577c42b9bb/edit#%E7%89%B9%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%9F%E8%A6%81%E5%9B%A0))
 - コンバージョンが中途半端にしか計測できない問題の原因特定と対処は想定をはるかに超えて時間がかかることがある


#何が起きたか？
 - トランザクション計測の抜け落ちが毎日2~3割発生している
  <img width="317" alt="transaction-gap-trend-between-analytics-vs-real.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/4a399e68-2a55-4dc1-4646-0e3d9e7d8b90.png">
 - そのため、アナリティクスレポートのROASの分子(収益)に影響を及ぼしている

  (アナリティクスを参照：集客≫Google広告≫キャンペーン≫クリックExplorerを参照)
<img width="887" alt="google-analytics-roas-by-click-explorer-ads-report.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/546a0070-1d8b-a773-394e-31ab357a14bc.png">


#問題の事前調査
①お客さんから実際のトランザクション履歴（トランザクションID・日付）をもらう（今回は過去3か月分）
②アナリティクスからトランザクション履歴をエクスポートする
(アナリティクスを参照：コンバージョン≫eコマース≫販売実績)
<img width="399" alt="enhenced-ecommerce-transaction-history.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/dc5f6ede-cb83-fc61-2be6-51eda7d01cf5.png">

③どのくらい差異が出ているかの傾向を分析する
今回はDBとしてBigqueryに両者のデータをインポートしてSQLを実行した。

```SQL
##どのくらい差異が出ているかの傾向を知るために実行するSQL
SELECT 
  alldata.transaction_datetime,
  without_ga.transactions_not_in_ga,
  alldata.all_transactions,
  ROUND(1.0*without_ga.transactions_not_in_ga/alldata.all_transactions,2) not_in_ga_rate
FROM(
  SELECT 
    r.transaction_datetime,
    COUNT(r.transaction_id) AS transactions_not_in_ga
  FROM ga_transaction_id g
  RIGHT OUTER JOIN real_transaction_id r
  ON g.transaction_id=r.transaction_id
  WHERE g.transaction_id IS NULL
  GROUP BY r.transaction_datetime) without_ga
RIGHT OUTER JOIN( 
  SELECT 
    transaction_datetime,
    COUNT(transaction_id) AS all_transactions
  FROM real_transaction_id
  GROUP BY transaction_datetime) alldata
ON
  without_ga.transaction_datetime=alldata.transaction_datetime
ORDER BY alldata.transaction_datetime DESC
```
#要因の詳細調査
##再現性の確認
 
 - 検証方法：購入方法を全パターン試した
 - 検証結果：正しくビーコン(HTTPリクエスト)がアナリティクスに送られている
 - 詳細な検証方法：以下の手順で確認した

①ブラウザ(今回はChrome)の「[デベロッパーツール≫ネットワーク](https://developers.google.com/web/tools/chrome-devtools/network)」で`collect`を検索
②`Request URL: https://www.google-analytics.com/j/collect?`の`RequestParameters`を確認する
③ビーコンの`ti`に対し、実際に払い出されたトランザクションIDがセットされているか確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/f6ac9bd1-7689-bdbd-adfe-ff72af902390.png)

##仮説1：埋め込まれているタグに誤りがある

 - 検証方法：ソースコードを確認した
 - 検証結果：ドキュメント通りのタグが埋め込まれていた

(ドキュメントを参照：拡張eコマース≫「[トランザクションの測定](https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce#transaction)」)

 - 詳細な検証過程：以下のソースコードを確認した

```thanks.html
<script>
//基本のアナリティクスタグ
(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','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-****-2', 'auto');

//拡張eコマース用のコード
ga('require', 'ec');
</script>

...

<script type="text/javascript">
ga('ec:addProduct', {
id': '****',
name': '****',
category': '****',
brand': '****',
price': '****',
quantity': 1
});
ga('ec:setAction', 'purchase', {
id': '147570',
revenue': '****',
});
</script>

...

<script>
ga('send', 'pageview');
</script>
```

##仮説2：ビューの何らかのフィルタの影響を受けている

 - 検証方法：お客さんにフィルタなしの新しいビューを作ってもらった
 - 検証結果：傾向に変化はなかった

##仮説3：特定の商品を買うときのみサイトの動きが異なる

 - 検証方法：最も計測漏れが起きている商品で購入し、ビーコンを確認
 - 検証結果：問題は再現できなかった
 
（なお、トランザクションIDは完了画面のページで発行される=完了画面で生じる問題の可能性が高いため、この仮説が当てはまる可能性は元々とても低い）

 - 詳細な検証過程：以下手順で確認した
 
①アナリティクスで計測できていないトランザクションのID一覧をお客さんに渡す。そして、商品マスターDBの商品・商品カテゴリ情報をそのIDに紐づけてもらう。

```SQL
#アナリティクスで欠損しているトランザクションIDを抽出するためのSQL
SELECT 
    r.transaction_datetime,
    r.transaction_id transaction_id_not_in_ga
FROM ga_transaction_id g
RIGHT OUTER JOIN real_transaction_id r
ON g.transaction_id=r.transaction_id
WHERE g.transaction_id IS NULL
ORDER BY r.transaction_id DESC
```
②最も計測漏れが起きている商品でを抽出する
<img width="591" alt="spreadsheet-query-select-transaction-data-gap-of-analytics-vs-real.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/a67bf1fe-636b-4ba2-90d1-61436a0130f8.png">

```SQL
#SpreadsheetのQUERY関数でSQLを実行
=QUERY(A:F,"select A,B,count(A) where A is not null group by A,B order by count(A) desc",-1)
```
③最も頻度の高い商品で検証する


#結論
##特定された要因
上記までのように検証したがどれも仮説と合致せず、最終的には以下の結論に達した。

「[**アナリティクスのデータ収集上限**](https://developers.google.com/analytics/devguides/collection/analyticsjs/limits-quotas?hl=ja#universal_properties)に達しているセッション(**ヒット数が500を超えるセッション**)がある。」


- 検証方法：ヒット数が500を超えるセッションを抽出し、どのくらい影響を及ぼしているか推定する
- 検証結果：ヒット数が500を超えるセッションがなくなったときに解消が見込まれるトランザクション数は、実際に抜け落ちているトランザクションの数に近いため、この要因は尤もらしい
- 詳細な検証過程：以下手順で確認する

①データの収集上限に当てはまるセッションがどのくらいあるのかを見る
(セグメント≫条件)
<img width="655" alt="segment-sessions-having-over-500hits.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/3a178c68-e9da-18b2-9157-88c9b2c954d4.png">
→沢山あることが確認できた。
※500ヒット以上あるセッションが絞り込める（計測に問題が出るのは500ヒットを超えるセッションだが、500を超えるという条件は使えない）

②もう少し掘り下げてセッションやヒットの計測状況を見てみる
(カスタム≫カスタムレポート)
<img width="883" alt="transaction-gap-caused-by-many-hits-of-event.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/2210be35-ccf9-faf2-d517-69c88e14b7e4.png">
→イベントが大量に発火しているため、平均してPVの5倍のヒットがあるようだ。

③どのようなイベントが大量に計測されているのかを見る
→商品一覧画面でのイベント発火が全体の97%を占めている
<img width="522" alt="analytics-event-report-for-transaction-gap-research.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/32ef6789-e847-6cc7-3f09-987b63ed6849.png">

④対策した際の効果を推定する
上記のようなイベントが過度に発火する問題が解消されると、トランザクション数の抜け落ちはどのくらい解消されるのか？

<img width="824" alt="estimate-the-effect-of-handling-for-the-cause-of-transaction-gap.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/a7cfc2a8-0dad-8da1-afd9-8688dfacae76.png">

|#| セグメント       | データの種類       |データの総数    |
|:-----------------|:-----------------|:-----------------|:------------------:|
|①|全てのユーザー|URL「/products/list.php」のその月の総PV|724,839|
|②|全てのユーザー|本当のトランザクション数(お客さんからもらう)|3,808|
|③|500hit以上あるセッション|URL「/products/list.php」のその月の総PV|195,466|
|④|500hit以上あるセッション|トランザクション数の推定値(②÷①×③)|**1,026**|
→本記事の「[事象](https://qiita.com/drafts/e6b0a38686577c42b9bb/#%E4%BA%8B%E8%B1%A1)」で確認したところ、実際に生じているアナリティクスのトランザクションデータの欠損数が「**1035**」であるのに対し、本要因を解消したときに計測できるようになるトランザクション数の推定値が「**1026**」であるため、この要因は尤もらしい。

##要因の要因
なぜイベントによるヒットが大量に飛んでいるのか？をもっと詳しく見ていく。

商品一覧画面で各商品のインプレッションデータをアナリティクスに送信している(参照: [商品インプレッションの測定](https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce#product-impression))のだが、この際、一覧画面で出力される100個の商品データ全てを取得・送信しているため、ヒットが大量に計測されてしまっている。

 -  コード`ga('ec:addImpression', {...`で1つ1つの商品データをセットしている
 - 商品1つ1つに対しコード`ga('send', 'event', ...); `で商品データを送信している

##回避策
これを回避するために、以下の方法で送信するデータ回数を減らすことを検討する。

 - PCおよびスマホの画面に表示された商品のみ商品データをセット・送信すること＝送信する商品データをなるべくまとめること。

 
```HTML
<!--例 - (1スクロールで表示される商品数8つごとにデータを送信)-->
<!--{if (商品データのインデックス+1)%8 == 0}-->
 ga('send', 'event', '***', '***', '***', {'nonInteraction': 1});
<!--{/if}-->
```

 - それでもヒット数が上限を超えてしまうセッションが見られる場合、アナリティクスのプロパティを拡張eコマース用に分けること

###制約事項
拡張eコマースのイベント発火時、アナリティクスへのデータ送信(HTTPリクエスト)1回あたりのサイズが8000バイト以下である必要がある(参照: [Send Google Analytics Payload Length As Custom Dimension](https://www.simoahava.com/analytics/send-google-analytics-payload-length-as-custom-dimension/)) 

もし上記回避策で上限を超えてしまう場合、**SKU以外の商品データ(日本語の商品名など)を送信しない** という手段が考えられる。この場合そのままではレポートで一部商品のディメンションが使えなくなるが、[商品データをアナリティクスにインポートする](https://support.google.com/analytics/answer/6066852
)ことで回避することができる。ただし、GA360でなければ過去に遡ってデータを付与することはできず、ビューフィルタのようにそのインポート後のデータにのみ適用される。

**※関連記事**
なお、商品データを除外することに関してこちらでメモを書いた。
「[**拡張eコマース - 一部項目を取得しないとGAのレポートでどう見えるのか？**](https://qiita.com/MasatoEmata/items/b96a5ca8bd06177dca0a)」

#その後
ヒットの計測が激減し、**取れるトランザクションデータが70～75%→95%以上になった**。
（Googleに聞いても改善できなくて困っていたとお客さんに喜んでもらえて嬉しかった）

①データの収集上限に当てはまるセッション
<img width="236" alt="solve-the-problem-of-transaction-gap-caused-by-many-hits-of-event - 2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/f77372e8-4483-09aa-d2e3-81ed2c6fea25.png">

②セッションとヒットの計測状況
<img width="680" alt="solve-the-problem-of-transaction-gap-caused-by-many-hits-of-event.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521810/35a89f55-b26b-16d9-c1d8-f20d70b51b3d.png">

---
何かあればお手数ですが、本記事か以下アカウントでお知らせください！

**\ *Follow Me!* /**
**[*Qiitaアカウント*](https://qiita.com/MasatoEmata)**
**[*Twitterアカウント*](https://twitter.com/masatoemata)**