【GTM】GTGとsGTMを利用した場合のリクエストURLの変化

突然ですが GoogleTagManager(以下GTM) は使われてるでしょうか?
根拠なしの筆者の体感ですが、タグの管理ツールとして
ほとんどの企業で Google の GTM か Adobe の DataCollection (Adobe Launch) を使われている気がします。
その中でも GTM は無料で使えることもあり
多くの企業に愛用されているのではないでしょうか。
そんな GTM の本体スクリプトである gtm.js と gtag.js/GA4 についてのお話になります。
目次
gtm.js とは
GTMを利用する時、サイトにGTMタグを貼ると思います。
GTMの管理画面から以下のようなタグをコピペして使うアレですね。

これは何をしているかというと
gtm.js という GTMを動かすコアのコードをくださいとリクエストを投げて
そのレスポンスとして gtm.js をブラウザが受け取るということやっています。
リクエストURLは、先程添付した画像にも記述がありますが
https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX
というURLになります。
試しに、GTM-XXXXXの部分を、普段皆様が使われている GTMの測定IDに変更して
ブラウザのアドレスバーに打ち込んでみてください。
するとブラウザ上にとんでもないコードの羅列が表示されると思います。

これが、GTMのタグ配信エンジン(本体スクリプト)である gtm.js の中身です。
非エンジニアの方が見るとワケわからない文字列だと思いますが
エンジニアが見ても minify化 + ビルド最適化などが行われているので
ぱっと見ただけではワケわかりません。
なお、id=GTM-XXXXX のクエリパラメータを付与しないとうまくいかないことから分かるように
gtm.js の中身はGTMコンテナ内の設定によって変わります。
リクエストを受け取ったGTMサーバーが GTMのUIでの設定を加味してビルドして
gtm.js を作成してレスポンスとして返しているため、動的に変わるわけですね。
今は、www.googletagmanager.com というドメインにリクエストを投げた形ですが
実はこのドメインを 自社ドメインにすることが可能なんですね。
それが、GoogleTagGateway(以下GTG)と呼ばれる方法だったり
ServerSideGTM(以下sGTM)経由で配信する方法だったりあります。
広い意味ではsGTMを使う方法も TagGatewayではあると思いますが
本記事では分けて考えることにします。
これらの設定をすることで
例えば www.googletagmanager.com ではなく ex-ture.com/metrics/ にリクエストをなげれば
先程と同様に gtm.js がレスポンスとして返ってくるような状況を作れるわけです。
また、方法によっては Cookie発行元の IPアドレスを
WEBサーバーの IPアドレスと 同じにしたりできるわけです。
というわけで前段が長くなってしまったのですが
今回の記事は GTGや sGTM の設定解説・・・・
ではなく
それらは出来ている前提で
GTG や sGTM経由での配信を行った際の
各タグのリクエストURLがどうなるかを見ていきたいと思います。
(gtm.jsのリクエストURLだけでなく、GTM内で設定されている各タグのリクエストURLです)
GTGやsGTMの設定方法などは別の記事や公式の説明に譲ることにします。
また、この記事では GTGやsGTMを使うことのメリットや「何が嬉しいの?」という話は全くしていません。
技術的視点の話だけですのでその点ご了承ください。
gtm.js配信をGTGやsGTM経由にすると何が変わる?
最初に記載したようにデフォルトでは
https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX
にリクエストを投げて、そのレスポンスとして gtm.js を受け取ります。
この時、GTMの中に設定してある Googleタグや GA4イベントタグのリクエストURLはどうなっているでしょうか。
gtag.js ロードのリクエストURLはhttps://www.googletagmanager.com/gtag/js?id=G-YYYY
になります。
page_viewなどGA4イベントの送信先URLは 条件によって多少分岐はありますが基本的にはwww.google-analytics.com/g/collect〜
もしくはanalytics.google.com/g/collect〜
のどちらかになるはずです。
(具体的には GA4 の Googleシグナルの収集が有効[※詳細は最後の補足] かつ 同意モードの ad_storage と analytics_storage が granted であれば後者のドメインに、それ以外の場合は前者のドメインになります。 そもそもGTMで同意モード設定していない場合はデフォルトで ad_storage と analytics_storageは grantedになるので、実質 Googleシグナル収集が有効かどうかで決まります。)
さて、GTGなどの設定をすると、gtm.js のリクエストURLを自社ドメインにできると話しました。
https://ex-ture.com/metrics/?id=GTM-XXXXX
などですね。
これはなんでこうなるかというと、
至極単純な話でこの形に書き換えるからですね。
何を言っているかというと、元々デフォルトでは
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
// URLに注目: www.googletagmanager.com/〜
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-XXXXX');というコードですが、それを物理的に
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != "dataLayer" ? "&l=" + l : "";
j.async = true;
// URLに注目: ex-ture.com/metrics/〜
j.src = "https://ex-ture.com/metrics/?id=" + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, "script", "dataLayer", "GTM-XXXXX");と書き換えるわけですね。
自分たちで書き換えているのだから
当然 gtm.jsのリクエストURLは 変わりますね、という話です。
面白いのはここからでして、
実は gtm.js のリクエストURLを自社ドメインにすると
GTMのUIで設定している他のGoogleサービス関連の一部のリクエストURLも
自社ドメイン経由にすることができるんですね。
自分たちで書き換えたのはgtm.js の リクエストURLだけなのに、
GTMのUIで設定しているGoogle系タグについても内部で自動でドメインやパスを構築して
自社ドメインにしてリクエスト投げるって面白くないでしょうか。
(まぁそれが GTG の “ウリ” でもあるわけですが)
さらに、GTGとsGTMの設定が混ざり合うと、「gtag.jsのロード先」と「GA4イベントの送信先」が全く別のパスに分岐するという、さらに非直感的で面白い現象も発生します。
この記事では Googleタグ(gtag.js のロードリクエストURL)と
GA4イベントタグ(GA4各種イベントの送信リクエストURL)を見ていきたいと思います。
面白いと思った方は続きをどうぞ!
※Google広告の場合などはもっと複雑な動きをするため本記事では言及しておりません。
GTGとsGTM経由の配信の違い
gtm.js は動的にビルドされて配信されているという話を先ほどしました。
実は gtm.js の内部の記述で
自分(=gtm.js) が GTG経由で配信されたのか?
それとも sGTMのクライアント経由で配信されたのか?
などを判別するフラグが立っています。
具体的には gtm.js 内の最初に定義してある、dataオブジェクトの中の blobプロパティにフラグあります。
blob[47]:GTG経由かどうかのフラグ。true であれば その gtm.js は GTG経由の配信である。
blob[50]:sGTM経由かどうかのフラグ。true であれば その gtm.js はsGTM経由の配信である。
(blob[18]:GTGのパスプレフィックス。今までの例でいうと https://ex-ture.com/metrics/ の /metrics/の部分)
このフラグを違いから、後続の処理が色々と分岐をしていくことになります。
用語整理
本題に行く前に少しだけ用語の整理をしたいと思います。
以降の内容で表の左側の言葉が出てきたら、右側の意味だと解釈してください。
用語 | 意味 |
|---|---|
GTG 有効 | GTG の設定が完了し、gtm.js が GTG 経由で配信されている状況 |
sGTM 設定済 | sGTM を利用できる設定が完了している状況 |
sGTM 経由配信 | gtm.js が sGTM 経由で配信されている状況 |
ex-ture.com/metrics/(パスに /metrics/) | GTG の影響による自社ドメイン利用を示す |
ex-ture.com/sgtm/(パスに /sgtm/) | sGTM の影響による自社ドメイン利用を示す |
server_container_url 設定有効 | GA4 イベントタグや Google タグのイベントパラメータ(・構成パラメータ)に server_container_url が設定されていること |
GTGの場合は「GTG有効」と書くだけで、「GTGが利用できる設定が完了している」かつ「gtm.jsもGTG経由で配信している状況」という意味だと思ってください。
sGTMの場合は「sGTM設定済」は「sGTMが利用できる設定が完了している」という状況です。(gtm.js をsGTM経由で配信しているかどうかは問いません)
「sGTM経由配信」といったら「gtm.js を sGTM経由で配信している状況」ということになります。
少しややこしいですが、以降の説明のために sGTMは分けた方が説明がしやすいため、ご了承ください。
gtag.jsのロードリクエスト
gtag.js ロードのリクエストURLはどのようになるでしょうか?
結論
まず結論から見ていきましょう。
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | GTG 有効 |
|
優先2 | sGTM 設定済 + sGTM 経由配信 + server_container_url 設定有効 |
|
優先3 | 上記以外(デフォルト) |
|
というわけで、結論は上記の表のように優先度が決まっています。
GTG有効であれば、その時点で gtag.js のリクエストURLは ex-ture.com/metrics/?id=G-YYYY のような GTG経由のドメインパスになります。
つまり、gtm.js を ex-ture.com/metrics/?id=GTM-XXXX でロードしていたら、その時点で
gtag.js の リクエストURLも ex-ture.com/metrics/?id=G-YYYY に決まります。
GTGが有効でない場合は
sGTM設定済 かつ gtm.js をsGTM経由でロードしている、かつ Googleタグのイベント(構成)パラメータに server_container_url の設定をしている場合は、gtag.js のリクエストURLは ex-ture.com/sgtm/gtag/js?id=G-YYYY のようにsGTM経由のドメインパスになります。
それ以外の場合はデフォルトのURLから gtag.js をロードします。
リクエストURLを構築する内部コード
コードは概ね以下のようになっております。
実際はもう少し複雑なことをしていますが、本記事で示したいことから大きく横道にそれてしまいそうな箇所は省略しています。
function createRequestUrl(destinationId, transportUrl, loadAsGtag, context) {
var queryStr = createQueryString(destinationId);
// createQueryString() が行うこと:"?id=G-YYYY& などのパラメータ部分の組み立て
var scriptPath = loadAsGtag ? '/gtag/js' : '/gtm.js';
// ══════════════════════════════════════
// 分岐1: GTG有効(blob[47] = true)
// ══════════════════════════════════════
if ( blob[47] (=GTG有効) ) {
loadScript(blob[18] (='/metrics/' ) + queryStr);
// sGTM関連や server_container_url はこの時点では全く見られていない
}
// ══════════════════════════════════════
// 分岐2: GTG 無効(blob[47] が存在しない場合)
// ══════════════════════════════════════
else {
scriptUrl = getScriptUrl(serverContainerUrl, scriptPath + queryStr);
// serverContainerUrl:設定なしなら undefined
// scriptPath + queryStr = "/gtag/js?id=G-YYYY&..."
if (!scriptUrl) {
// getScriptUrl() が undefined を返した(= server_container_url 未設定)のでフォールバック
var base = 'www.googletagmanager.com' + scriptPath;
scriptUrl = 'https://' + base + queryStr;
}
loadScript(scriptUrl);
}
}このように、GTG有効の時点で gtag.js ロードのリクエストURLは決定し
そのURLに対して loadScript(リクエストを投げる)ことをします。
一方、GTGが無効の場合は、getScriptUrl の関数が重要そうですね。見ていきましょう。
function getScriptUrl(serverContainerUrl, pathAndQuery) {
// serverContainerUrl : createRequestUrlの server_container_url の値(未設定なら undefined)
// pathAndQuery : /gtag/js?id=G-YYYY&...'
if ( blob[50] (=sGTM経由配信) && serverContainerUrl) {
// serverContainerUrl が falsy なら if ごとスキップ → return なし → undefined
var reqUrl = "https://" + serverContainerUrl + pathAndQuery;
return reqUrl
// → 'https://ex-ture.com/sgtm/gtag/js?id=G-YYYY&...'
}
// if が false( sGTM経由で配信されていない または serverContainerUrl が falsy ) → return なし → undefined
// → 呼び出し元 createRequestUrl() の !scriptUrl が true になりフォールバックへ
}getScriptUrl で sGTM経由配信 かつ server_container_url が設定されているかを判定して
true であれば sGTMのドメインパス(ex-ture.com/sgtm/gtag/js?id=G-YYYY) が gtag.js のリクエストURLになります。
一方、「sGTM経由配信」 と 「server_container_url設定」のいずれか片方でも falsy の場合は
if 文に入らず undefined が 返されます。
undefinedの場合は最初の関数 (createRequestUrl) の scriptUrl が falsy なので !scriptUrl は true になり
以下のフォールバックのブロックに入り、デフォルトURLが構築されるわけです。
if (!scriptUrl) {
// getScriptUrl() が undefined を返した(= server_container_url 未設定)のでフォールバック
var base = "www.googletagmanager.com" + scriptPath;
scriptUrl = "https://" + base + queryStr;
}gtag.js ロードまとめ
ざっくりまとめると gtag.js ロードの リクエストURLがどのようになるかは
以下の優先度に従う、ということでした。
GTG → sGTM → デフォルト
そのため、GTG有効であればその時点で gtag.js も GTGのドメインパスになります。
GTG無効であれば、sGTMやserver_container_urlの設定次第で、sGTMドメインパスになったり
デフォルトのドメインパスになったりします。
GTGの場合は「設定完了している」かつ「gtm.js をGTG経由で配信」という条件だけでOKでしたが
sGTMの場合は、「設定完了している」かつ「gtm.js をsGTM経由で配信」かつ「Googleタグでserver_container_urlの設定」が必要ということになります。
GA4イベントの送信リクエスト
次は gtag.js のロードではなく、GA4イベント(page_viewや add_to_cart や purchaseなど)を送信するときのリクエストURLがどう分岐していくかを見ていきましょう。
結論
こちらもまずは結論を見ていきましょう。
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | MerchantCenter 発行の Google タグ経由 | /metrics/mc/collect (GTG 有効時) |
優先2 | sGTM 設定済 + server_container_url 設定有効 | ex-ture.com/sgtm/g/collect?v=2&… |
優先3 | GTG 有効 | ex-ture.com/metrics/ga/g/c?v=2&… |
優先4 | 上記以外(デフォルト) | www.google-analytics.com/g/collect?v=2&… |
こちらも上記のように優先度が決まっています。
優先1は MerchantCenter単体で発行したGoogleタグの話で本記事からそれるため詳細は割愛します。
面白いのは優先2からですね。
GA4イベント送信は GTGよりも sGTMが優先されます。
また、条件をよく見て欲しいのですが、gtag.js のロード優先度は以下のような形でした。
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | GTG 有効 |
|
優先2 | sGTM 設定済 + sGTM 経由配信 + server_container_url 設定有効 |
|
優先3 | 上記以外(デフォルト) |
|
sGTMに関わるところを見てみると
gtag.js のとき sGTMのURLが使われる条件は 「sGTM設定済 + sGTM経由でgtm.js をロードする + server_container_ur設定有効」でした。
一方、GA4イベントのリクエストURLを sGTM経由にするのであれば
「sGTM設定済 + server_container_url設定有効」の条件でこと足ります。
つまり、gtm.js を sGTM経由でロードする必要はないってことですね。
これは、例えばMeta広告でコンバージョンAPIを sGTMで設定したことがある方などはしっくりくる話かと思います。
gtm.js ロードのリクエストURLを変更するのはオプションであり
基本的には sGTMが使える設定をして、あとは GA4イベントタグで server_container_url を設定すれば問題なくコンバージョンAPIは動きますからね。
(※オプションではありますが、設定した方がブラウザ上の様々なブロックから逃れられる確率は上がります。)
リクエストURLを構築する内部コード
リクエストURLを構築するコードは概ね以下のようになっています。
createEventUrl = function (config) {
// config = GA4 タグの設定オブジェクト(gtag('config', ...) で渡された値を含む)
// ─ 優先1: Merchant Center ──────────────────────
if ( MerchantCenterのフラグがtrue ) return { url: ".../mc/collect", endpoint: 20 };
// ─ 優先2: sGTM設定済 + server_container_url ─────────────
var serverUrl = Normalize(server_container_url, "/g/collect");
// Normalize(base, path):
// base を正規化(http/https補完、末尾/除去)して path を結合
// → "https://ex-ture.com/sgtm/g/collect"
if (serverUrl) return { url: serverUrl, endpoint: 16 }; // endpoint: 16
// ─ 優先3: GTG ドメインパス or フォールバック ────────────
var endpoint = [Googleシグナル有効(※詳細は最後の補足)] && [ad_storageがgranted] && [analytics_storageがgranted] ? 17 : 16;
// endpointの番号を発番
// ↑ Google シグナル有効 かつ 同意済み → 17
// それ以外 → 16
return { url: getEndpoint(endpoint), endpoint: endpoint };
// getEndpoint(endpoint)
// GTG 有効 → blob[18](/metrics/) + "/ga/g/c" or "/ag/g/c"
// GTG 無効 → "https://www.google-analytics.com/g/collect" or "https://analytics.google.com/g/collect"
};優先3 の endpointについては以下の形になります。
sGTM については Googleシグナル関連の URL分岐処理はサーバーサイドで sGTMが肩代わりするので、クライアント側では分岐しません。(常に ex-ture.com/sgtm/g/collect〜 という形)
条件 | endpoint | URL |
|---|---|---|
GTG 有効 | 17 | /metrics/ag/g/c (相対パス、GTG ドメイン) |
GTG 有効 | 16 | /metrics/ga/g/c (相対パス、GTG ドメイン) |
GTG 無効 | 17 | https://analytics.google.com/g/collect |
GTG 無効 | 16 | https://www.google-analytics.com/g/collect |
というわけで、コードからも、GTGドメインパスよりも、sGTM( + server_container_url) の設定が優先されることが分かります。
GA4イベントまとめ
gtag.js と同様にざっくりまとめると GA4イベントの リクエストURLは以下の優先度に従います。
(Merchant Center) → sGTM → GTG → デフォルト
sGTMの設定完了しており、GA4イベントタグのイベントパラメータに server_container_url が設定してあれば、
仮に GTG有効だったとしても、sGTM経由のドメインパスがリクエストURLになります。
gtag.js ロードの場合は「設定完了している」かつ「gtm.js をsGTM経由で配信」かつ「Googleタグでserver_container_url の設定」が必要でしたが、GA4イベントについては「設定完了している」かつ「GA4イベントタグで server_container_url の設定」という条件でOKなのでした。
イベント(構成)パラメータについて補足
イベントパラメータについて少し補足です。
ご存知の方も多いと思いますが、GA4のイベントタグが発火したとき、そのイベントには以下の3つの取得元から入手したパラメータが付与された状態で送信されます。
①イベントタグ自体が持っている(設定している)パラメータと値
②イベントタグより先に発火したGoogleタグ が持っているパラメータと値
③手動設定なしでも自動送信されるパラメータ(page_location, page_title など)
この記事の文脈で重要なのは「②」で、GA4イベントタグが発火した際には、自身に設定してあるパラメータだけでなく、同じページ内で直近で発火したGoogleタグのパラメータも引き継いで利用します。
つまり、Googleタグで server_container_url を設定したら、GA4イベントタグでもそれが利用されます。
sGTM経由で gtm.js をロードしていて、gtag.js も sGTM経由でロードしたいとなったら、Googleタグに server_container_url を設定するわけですが、そうすると自動で後続のGA4イベントタグも sGTM のドメインパスになるということですね。
あまりない需要だとは思いますが、gtag.js は sGTM経由でロードしたいけど
イベントは sGTM経由にしたくない場合は、イベントパラメータの server_container_url の値の欄を何も入力しなければGoogleタグの設定が引き継がれません。
※これは server_container_url の場合だけで、通常のイベントパラメータで未入力(空文字)にするとそのまま空文字がヒットパラメータとして送られるのでお気をつけください。

なお、server_container_url のフィールド自体を設定しなかった場合は undefined とみなされ、その場合は Googleタグの設定を引き継ぐことになります。
また、通常は page_view も Googleタグで送信されますから、Googleタグに server_container_url を設定する時点で、page_viewも sGTM 経由になります。これを避けたい場合は、Googleタグに send_page_view : false のフラグを設定しておいて、GA4イベントタグで別途 page_view のイベントを作り、上記のように server_container_url の値を空にしましょう。
実例を見てみる
以下、GTGもsGTMも利用可能な設定は完了している、という前提で見ていきます。
ケース1: gtm.js を GTG経由でロードする(sGTM関連未設定)
gtm.js を GTG経由でロードするので、GTMのスニペットは以下のようになります。
<!-- Google Tag Manager GTG -->
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://ex-ture.com/metrics/?id=' + i + dl; // GTG経由でロード
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-XXXXX');
</script>
<!-- End Google Tag Manager -->Googleタグは以下

GA4イベントタグは以下です

GoogleタグもGA4イベントタグも特にパラメータは設定していません。
ネットワークを見てみましょう。
gtm.js のロード

ex-ture.com/metrics/?id=GTM-XXXX というGTGの設定ドメインパスになります。
このように自分たちでスニペットを書いたのでこれは当然ですね。
gtag.js のロード

gtag.js ロードのリクエストURLも ex-ture.com/metrics/?id=G-YYY&... となり
GTGの設定ドメインパスになっています。
GA4イベント

page_view, view_item ともに ex-ture.com/metrics/ga/g/c?v=2&... となっていて
これも前述したように GTGの設定ドメインパスですね。
このように、gtm.js のロードを GTG経由で行う(かつ、sGTM関連の設定がされていない)と
GTMのUIで設定したGoogleタグや GA4イベントタグにも反映され
gtag.js ロードのリクエストURLも GA4イベントの送信リクエストURLもGTGのドメインパスになります。
ケース2: gtm.js をsGTM経由でロード & server_container_url設定(GTG関連未設定)
gtm.js を sGTM経由でロードするので、GTMのスニペットは以下のようになります。
<!-- Google Tag Manager sGTG -->
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://ex-ture.com/sgtm/gtm.js?id=' + i + dl; // sGTM経由でロード
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-XXXXX');
</script>
<!-- End Google Tag Manager -->Googleタグは以下

GA4イベントタグは以下です

GoogleタグもGA4イベントタグも server_container_url を設定しています。
ネットワークを見てみましょう。
gtm.js のロード

ex-ture.com/sgtm/gtm.js?id=GTM-XXXX というsGTMの設定ドメインパスになります。
これも自分たちでスニペットを書いたので当然です。
gtag.js のロード

gtag.js ロードのリクエストURLも ex-ture.com/sgtm/gtag/js?id=G-YYY&... となり
sGTMの設定ドメインパスになっています。
GA4イベント

page_view, view_item ともに ex-ture.com/sgtm/g/collect?v=2&... となっていて
これも前述したように sGTMの設定ドメインパスですね。
gtm.js のロードを sGTM経由で行い(かつ、GTG関連は未設定)
Googleタグ/GA4イベントタグに server_container_url の設定をすると
gtag.js ロードのリクエストURLも GA4イベントの送信リクエストURLも、sGTMのドメインパスになります。
ケース3: gtm.js をGTG経由でロード & sever_container_url設定
gtm.js を GTG経由でロードするので、GTMのスニペットは以下のようになります。
<!-- Google Tag Manager GTG -->
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://ex-ture.com/metrics/?id=' + i + dl; // GTG経由でロード
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-XXXXX');
</script>
<!-- End Google Tag Manager -->Googleタグは以下

GA4イベントタグは以下です

gtm.js のロードは GTG経由ですが
GoogleタグもGA4イベントタグには server_container_url の設定をしています。
ネットワークを見てみましょう。
gtm.js のロード

ex-ture.com/metrics/?id=GTM-XXXX というGTGの設定ドメインパスになります。
gtag.js のロード

gtag.js ロードのリクエストURLも ex-ture.com/metrics/?id=G-YYY&... となり
GTGの設定ドメインパスになっています。
GA4イベント

page_view, view_item ともに ex-ture.com/sgtm/g/collect?v=2&... となっていて
これは sGTM設定のドメインパスになっていますね。
これは何が起きているのでしょうか?
gtag.js のロードと GA4イベントの優先度を思い出してみましょう。
↓gtag.jsロードの優先度↓
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | GTG 有効 |
|
優先2 | sGTM 設定済 + sGTM 経由配信 + server_container_url 設定有効 |
|
優先3 | 上記以外(デフォルト) |
|
GTG有効(=GTG設定済 & gtm.js をGTM経由でロード )の時点で
gtag.js のロードも GTG設定のドメインパスになるのでした。
そのため、server_container_url はUI上設定はされているのですが、内部的には一切見ておらずGTGのドメインパスが使われます。
一方で、↓GA4イベントの優先度↓
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | MerchantCenter 発行の Google タグ経由 | /metrics/mc/collect (GTG 有効時) |
優先2 | sGTM 設定済 + server_container_url 設定有効 | ex-ture.com/sgtm/g/collect?v=2&… |
優先3 | GTG 有効 | ex-ture.com/metrics/ga/g/c?v=2&… |
優先4 | 上記以外(デフォルト) | www.google-analytics.com/g/collect?v=2&… |
server_container_url が設定していある時点で、こちらのURLが優先されます。
※sGTM 設定済 + server_container_url 設定有効 と記載していますが、server_container_urlの設定がある時点で、リクエストURLとしてこの値が使われます。ただし、sGTM側の設定が完了してなければそもそもsGTMが動かずに計測が出来ません。
というわけで、GA4イベントの方は、server_container_url が優先されており、
GTG有効(=GTG設定済 & gtm.js をGTM経由でロード ) だとしても、GTGのドメインパスが使われることはありません。
そのため、一見不思議なことが起きているわけですね。
gtag.js ロードのリクエストURLは ex-ture.com/metrics/?id=G-YYYY とGTG経由、
GA4イベントの送信リクエストURLは ex-ture.com/sgtm/g/collect?v=2&... とsGTM経由になるわけです。
ケース4: gtm.js をデフォルトロード & server_container_url設定
gtm.js を デフォルトでロードするので、GTMのスニペットは以下のようになります。
<!-- Google Tag Manager デフォルト -->
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js/?id=' + i + dl; // デフォルトロード
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-XXXXX');
</script>
<!-- End Google Tag Manager -->Googleタグは以下

GA4イベントタグは以下です

gtm.js のロードは デフォルトURLですが
GoogleタグもGA4イベントタグには server_container_url の設定をしています。
ネットワークを見てみましょう。
gtm.js のロード

デフォルトでのロードなので www.googletagmanager.com/gtm.js?id=GTM-XXXX というリクエストURLになります。
gtag.js のロード

gtag.js ロードのリクエストURLもwww.googletagmanager.com/gtag/js/?id=G-YYY&... となり
デフォルトのドメインパスになっています。
GA4イベント

page_view, view_item ともに ex-ture.com/sgtm/g/collect?v=2&... となっていて
これは sGTM設定のドメインパスになっていますね。
これも何が起きているのか見ていきましょう。
しつこいですが優先度の表を再掲します。
↓gtag.jsロードの優先度↓
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | GTG 有効 |
|
優先2 | sGTM 設定済 + sGTM 経由配信 + server_container_url 設定有効 |
|
優先3 | 上記以外(デフォルト) |
|
このケースでは GTGは無効なので 優先1 には引っかかりません。
優先2はどうでしょうか。「sGTM設定済」と「server_container_url設定有効」 の2つは満たしていますが
gtm.jsのロードが sGTM経由配信ではないため、優先2にも引っかかりません。
結果としてデフォルトのドメインパスが使われることになります。
該当部分のコードも再度確認してみると
if ( blob[50] (=sGTM経由配信) && serverContainerUrl) {
// serverContainerUrl が falsy なら if ごとスキップ → return なし → undefined
var reqUrl = "https://" + serverContainerUrl + pathAndQuery;
return reqUrl
// → 'https://ex-ture.com/sgtm/gtag/js?id=G-YYYY&...'
} となっており、if文の中に分岐するためには server_container_url の設定だけではなく
sGTM経由でのgtm.jsロードが必須条件になっていることが分かります。
GA4イベントの優先度は
優先 | 条件 | リクエスト URL |
|---|---|---|
優先1 | MerchantCenter 発行の Google タグ経由 | /metrics/mc/collect (GTG 有効時) |
優先2 | sGTM 設定済 + server_container_url 設定有効 | ex-ture.com/sgtm/g/collect?v=2&… |
優先3 | GTG 有効 | ex-ture.com/metrics/ga/g/c?v=2&… |
優先4 | 上記以外(デフォルト) | www.google-analytics.com/g/collect?v=2&… |
GA4イベントの場合は、前述のように、sGTM経由でgtm.js をロードしているかどうかは関係なく、server_container_url が設定していある時点で、こちらのURLが優先されます。
そのため、GA4イベントの方は、server_container_url のURLが利用されます。
これも、一見不思議かもしれませんが
gtag.js ロードのリクエストURLは wwww.googletagmanager.com/gtag/js?id=G-YYYY とデフォルトのドメインパス、
GA4イベントの送信リクエストURLは ex-ture.com/sgtm/g/collect?v=2&... とsGTM経由になるわけです。
まとめ
いくつかのケースで条件をまとめると以下のような形になります。
条件 | gtm.js | Googleタグ(gtag/js) | GA4イベント(g/collect) |
|---|---|---|---|
デフォルト | www.googletagmanager.com | www.googletagmanager.com | www.google-analytics.com |
GTG 有効 | ex-ture.com/metrics | ex-ture.com/metrics | ex-ture.com/metrics |
sGTM設定済 | ex-ture.com/sgtm | ex-ture.com/sgtm | ex-ture.com/sgtm |
GTG 有効 | ex-ture.com/metrics | ex-ture.com/metrics | ★ ex-ture.com/sgtm |
gtm.js デフォルト配信 | www.googletagmanager.com | www.googletagmanager.com | ★ ex-ture.com/sgtm |
★ gtag.js ロードと GA4 イベント送信のリクエストドメイン/パス が異なるケース。gtag.js は GTG 優先 / デフォルトになる一方、GA4 イベントは server_container_url が優先されるため。
いかがでしたでしょうか?
筆者個人的には、可能であるならば GTG/sGTM 双方使える環境を整えた上で、
gtm.js と gtag.js のロードは GTG経由で配信し(つまり gtm.js を GTG経由でロードする)
GA4イベントについては sGTM経由で送るというのが、ITPを始めとした様々なしがらみをある程度突破しつつ、コストパフォーマンスの観点でも良いのかなと思います。(上の表でいうと下から2番目。前述の実例でいうとケース3。)
※GA4のpage_viewなど含めてすべてのヒットをサーバー経由計測したい場合の話であり、コンバージョンAPIのようにコンバージョンポイントでのみサーバー経由にしたい場合は他の選択肢もありだと思います。
最後に、GA4イベントに関して、server_container_url がなぜ優先されるのか?
これも個人的な推測ですが、GA4イベントタグは 「GA4イベントの計測」だけに使われるわけではないからですね。
例えば、記事の途中でも少し言及しましたが、Metaや LINEヤフー、TikTokなどのコンバージョンAPIを設定しようとしたとき、設定方法の1つとして ウェブコンテナの「GA4イベントタグを使って」sGTMにデータを飛ばす方法がポピュラーです。
これは「GA4イベントタグを“”使う””」だけで、「GA4のサーバーにはデータを飛ばしません」。
「GA4イベントタグを“”使って””」sGTMにデータを飛ばして、そのイベントデータを料理するのは sGTMです。
Metaのサーバーに投げて MetaコンバージョンAPIを実装することも出来ますし
TikTokのサーバーに投げて TikTokのイベントAPIを実装することもできるわけです。
そのため、GA4だけで使うものではないので、イベントに関しては server_container_url を設定したら sGTMに飛ばしたもらわないと困るわけですね。
以上になります。
補足 – Googleシグナルについて
この記事でところどころ「Googleシグナルが有効」の場合という条件を記載しています。
これは、日本ではほとんどの場合で正しいのですが
厳密には若干異なるため簡単に補足説明します。
まず、gtm.js や gtag.js のコード内で使われている Googleシグナル系の条件としてis_google_signals_enabled と is_google_signals_allowed の2つが存在します。
is_google_signals_enabled は シンプルに GA4の管理画面で「Googleシグナルのデータ収集」をオンにしていたら true になります。
基本的には、is_google_signals_enabled が true であれば is_google_signals_allowed も trueです。
本記事で「Googleシグナルが有効」と書いている場面の『条件』は厳密にはis_google_signals_enabled ではなく is_google_signals_allowed を求めていますが、日本ではほぼ同義なので「Googleシグナルが有効」と書かせてもらっています。
ここでは、『ほぼ同義とはいえ、is_google_signals_enabled が true なのに is_google_signals_allowed は false になることがあるんでしょ?それはどういうときなの?』という話を軽くしたいと思います。
結論、3つあります。
①パラメータで明示的に false を渡す
例えばgtag('set', {'allow_google_signals': false}); やgtag('config', 'G-YYYY', {'allow_google_signals': false});
などのように allow_google_signals のパラメータに 明示的に false を渡す場合です。
このとき、GA4の管理画面で「Googleシグナルのデータ収集」が有効になっていても(is_google_signals_enabled が true でも) is_google_signals_allowed は false になります。
②CMP(Consent Management Platform:同意管理プラットフォーム)を利用している場合
GDPRなどの対応でCMPを導入しているサイトでは
ユーザーが特定の項目を拒否すると is_google_signals_allowed は false になります。
③地理的な制限
ページロードのタイミングで gtm.js あるいは gtag.js がロードされる際に、blob[22] に geo系の情報が入っています。
サーバー側がIPなどから判断して gtm.js などをビルドするときに挿入していると思われます。
そしてこの blob[22] には geo制限のフラグも含まれており、
特定の地域などでは地理的にGoogleシグナル利用に制限がかかります。
このgeo制限フラグが true の場合も is_google_signals_allowed は false になります。
かなり余談ですが、この blob[22] のgeo系の情報は
実は window.google_tag_data.xcd.ip_geo_data_cache の中にも格納されており、get() メソッドを呼ぶことで取得が可能です。

このオブジェクトの index が「2」の箇所が、geo制限フラグです。
上記のキャプチャだと {"0": "JP", "1", "", "2": false, ・・・} となっていますが、この "2": false のところですね。
ここが true なら geo制限に引っかかるということです。false であれば制限されません。
以上です!
Bye, bye.





