Google Analyticsのブロックを検知する方法 -通信編-

# Overview

Google Analytics(以降、GA)をブロックされること困ることがある。
ブロックされている場合に機能制限をかけるため、ブロックされているかどうかを検知する方法を紹介する。

# Target reader

- GAのブロックを検知したい方。

# Prerequisite

- 日常的にGAを利用し、GAの基本操作をマスターしている。
- WEB APIをコールできる。
- `gtag.js`を利用しているものとする。

# Body

## GAのブロックを無視してはいけない

まず最初に断っておきたいのは、ユーザーがGAへの送信を拒否している場合、それを迂回等してGAに送信してはいけません。
ブロックを検知して、無理やりGAに送信するようなことは控えましょう。

https://marketingplatform.google.com/about/analytics/terms/jp/
> お客様は本サービスに含まれるプライバシー機能（オプトアウトなど）を一切回避してはなりません。

ただし、GAを拒否するならこの先は進ませないというのはサービス提供者の自由です。
よくあるのがサイト訪問時、この先のページを進んだらCookie利用に同意したものとするというメッセージが出るあれですね。

## GAのブロック検知パターン

GAのブロックを検知するには以下のパターンがあると考えます。
なお、`gtag.js`のオブジェクトを差し替える、リクエストのレスポンスを差し替える等の偽装系は除外します。

1. `https://www.googletagmanager.com/gtag/js`のスクリプトのロードをブロックしていることを検知する  
    `https://www.google-analytics.com/analytics.js`を含む
2. `gtag.js`のロード状態やプライバシー機能を利用してブロックしていることを検知する  
    Google アナリティクス オプトアウト アドオン => https://tools.google.com/dlpage/gaoptout?hl=ja
3. `https://www.google-analytics.com/collect`への送信ブロックを検知する

`1.`の`js`ファイルをブロックするパターンについては、`2.`のロード状態でも検知できますし、`3.`でも`https://www.google-analytics.com`へのブロックが検知できるため判断可能です。
`2.`のSDKのロード状態やプライバシー機能の有無でチェックするパターンにおいては、`3.`のブロックパターンの場合を検出できない場合があります。これについては今後別の記事で掲載予定です。
`3.`の通信によるブロック検知は、`2.`のオプトアウトアドオンを利用される等による、SDKがリクエストを送信しなくなるパターンを検知できません。
本記事では`3.`のパターンについて考えます。

## SDKによる送信結果取得は不可

イベントを送信する場合、`gtag()`を利用します。
`gtag()`は何をしているか、公式ドキュメントを参照します。

https://developers.google.com/gtagjs/devguide/snippet?hl=ja

>
```javascript
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
```

JSへの理解があればすぐにわかりますが、`dataLayer`という配列にデータをプッシュしているだけです。
適時`dataLayer`からデータを取得して送信していると思われますが、少なくとも戻り値で呼び出し元から送信結果を得ることはできません。
ドキュメントも見ましたが、送信結果の取得については見つかりませんでした。

## 送信可能の判定方法を決める

ここで改めて何を知りたいのかを思い返します。
SDKの処理結果が欲しいのか？違います、欲しいのは送信できるかどうかです。
それならばSDKからは離れて、送信できるかに焦点を当てます。
ではどこに送信すればいいのでしょうか？その答えはSDKが利用するAPIにあります。

SDKに関するドキュメントを見ます。
https://developers.google.com/analytics?hl=ja

Measurement Protocolというのが中で呼び出しているAPIになります。
https://developers.google.com/analytics/devguides/collection/protocol/v1?hl=ja

パラメータリファレンスのページでは、いつもGAで見ているディメンションたちが掲載されています。
https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters?hl=ja

## 最も手軽にブロックを検知する

通信がブロックされていると仮定した場合、WEB APIをコールしてその結果で判断すればいいことはわかりました。
どれでは何をコールすればいいでしょうか？ページビューですか？カスタムイベントですか？
SDKで処理するものと、WEB APIで処理するものが混在すると面倒に感じないでしょうか？
WEB APIのパラメータが変化すると対応も必要になるでしょう。

そのような事情から、お手軽に通信をチェックできないか調べたところ、ヒットの検証をいういいやつが見つかりました。

https://developers.google.com/analytics/devguides/collection/protocol/v1/validating-hits?hl=ja

> 重要: Measurement Protocol 検証サーバーに送信されたヒットは、レポートには表示されず、デバッグにのみ使用されます。

ドキュメントでは無効なイベント送信を行っていますので、こちらでは正しいイベントの送信を行います。

```
https://www.google-analytics.com/debug/collect?v=1&tid=<your-tracking-ID>&cid=fake&dp=%2Ffoo
```

これを`Fetch API`を利用し、POSTメソッドで送信すると、`hitParsingResult`の配列が返ってきます。
その中の`valid`がtrueなら正しく送信できたと判断すればいいかと思います。

### 注意事項

#### 場合によってはすり抜ける可能性がある

ヒットの検証は通常利用するパス`/collect`ではなく`/debug/collect`に送信します。
そのため、ユーザーが`https://www.google-analytics.com/collect`のみをブロックしている場合には、送信できないのに送信可能という誤判定になります。
(`/collect/debug`なら誤判定にならなかったのに…)
ユーザーが`https://www.google-analytics.com`のドメイン指定でブロックしていると想定している検出方法のため、正確性を求める場合には、本番用の`https://www.google-analytics.com/collect`に送信したいところです。
しかし、残念なことにヒットの検証とは異なり本番用は送信結果を2xxで返すためレスポンスコードでの判定は困難です。(imageのバイト配列？が来る)
`Fetch API`が応答を受けれずに失敗するようなブロックの仕方をしていることを願うばかりです。

#### GooglebotはGAをブロックする

GooglebotはGAをブロックするため、Googlebotの判定をせずに排除すると、Googleの検索からサイトが消滅します:scream:
GAを判定する場合は、以下の公式ドキュメントを参考に実施してください。
https://support.google.com/webmasters/answer/80553?hl=ja


# Conclusion

`https://www.google-analytics.com/debug/collect`を利用したお手軽ブロック検出を紹介しました。
万能ではありませんが、公式のWEB APIを利用した判定方法のため、手軽な割に信頼性は高いと思います。
今後掲載予定のSDKによるブロックも併用することで、ある程度のブロックは検知可能になります。

Have a great day!