GTMで要素が表示されたときに発火するトリガーの設定方法
Googleタグマネージャー(GTM)を活用していると、「特定の要素がユーザーの画面に表示されたときにイベントを発火させたい」というニーズが出てきます。たとえば、フォーム送信後に表示されるメッセージ <p clas …
この記事のポイント
- GTMの「要素の表示」トリガーは、特定のCSSセレクタや要素IDを指定するだけで画面内への表示を検知できる標準機能である。
- フォーム完了メッセージやサンクスページ要素のような動的に出現する要素のイベント計測に、このトリガーが有効な手段となる。
- サイトの構造によっては標準トリガーが安定しないケースがあり、その場合はカスタムHTMLタグでMutationObserverを実装するのが定石である。
- MutationObserverを使う方法では、要素の追加や表示を監視し、条件を満たした時点でdataLayer.pushを実行してカスタムイベントを発火させる。
Googleタグマネージャー(GTM)を活用していると、「特定の要素がユーザーの画面に表示されたときにイベントを発火させたい」というニーズが出てきます。たとえば、フォーム送信後に表示されるメッセージ <p class="form_complete">お申込みありがとうございました。</p> を検知して、GA4や広告計測タグを発火させたいケースです。
しかし、この要素はJavaScriptで動的に表示されることが多く、単純なページビューやクリックトリガーでは計測できません。では、どうすればよいのでしょうか?
本記事では、GTMの「要素の表示」トリガーを使った標準的な方法と、うまく動作しない場合のためのカスタムスクリプト(MutationObserver)を使った応用方法を解説します。この記事を読めば、フォーム完了メッセージなど動的に表示される要素を正確にトラッキングできるようになります。
GTMの「要素の表示」トリガーを使う方法(推奨)
図1: 標準トリガーと代替実装の使い分け判断フロー
まずはGTMが提供する標準機能「要素の表示(Element Visibility)」トリガーを利用しましょう。フォーム完了後に表示される以下の要素を検知する例を考えます。
<p class="form_complete">お申込みありがとうございました。</p>
設定手順
STEP
トリガーを作成
以下の設定に従ってトリガーを作成します。
- 種類:要素の表示
- 選択方法:CSS セレクタ
- セレクタ:
p.form_complete - 最小表示率:1%
- 発火タイミング:1回のみ or 要素が表示されるたび(要件に応じて選択)
- DOM変更を監視:オン
STEP
条件を追加する(任意)
同じクラスが別用途で使われている場合は、テキスト内容を変数化して条件判定するのがおすすめです。
- 変数 > 新規 > カスタム JavaScript
function () {
var el = document.querySelector('p.form_complete');
return el ? (el.textContent || '').trim() : '';
}
- 変数名例:
JS - 完了メッセージ - トリガー条件で「
JS - 完了メッセージ 等しい お申込みありがとうございました。」を指定
STEP
タグと接続
タグに作成したトリガーを紐づけます。今回はGA4イベントタグと紐づけていますが、広告のコンバージョンタグに紐づけることで、フォーム送信完了を広告のコンバージョンとしてカウントすることもできます。
- GA4イベントタグを作成し、イベント名を
form_complete_visibleとする - パラメータに
message: {{JS - 完了メッセージ}}を設定すると後で分析に便利
標準機能で動作しない場合:MutationObserverを使う方法
図2: MutationObserverによるイベント検知フロー図
サイトの仕組みによっては「要素の表示」トリガーが安定しない場合があります。その場合は、カスタムHTMLタグで要素の追加や表示を監視し、要素が現れたら dataLayer.push() を実行してカスタムイベントを発火させます。
サンプルコード
<script>
(function() {
var fired = false;
function isVisible(el) {
if (!el) return false;
var rect = el.getBoundingClientRect();
var inViewport = rect.bottom > 0 && rect.top < window.innerHeight;
var style = window.getComputedStyle(el);
return inViewport && style.display !== 'none' && style.visibility !== 'hidden';
}
function check() {
var el = document.querySelector('p.form_complete');
if (!el) return;
var text = (el.textContent || '').trim();
if (!fired && text === 'お申込みありがとうございました。' && isVisible(el)) {
fired = true;
window.dataLayer.push({
event: 'formCompleteVisible',
message: text
});
}
}
var observer = new MutationObserver(check);
observer.observe(document.documentElement, { childList: true, subtree: true });
window.addEventListener('scroll', check);
window.addEventListener('resize', check);
document.addEventListener('DOMContentLoaded', check);
window.addEventListener('load', check);
})();
</script>
GTM側の設定
- トリガー:カスタムイベント
- イベント名:
formCompleteVisible - 条件:
{{message}} 等しい お申込みありがとうございました。
この方法なら、フォーム送信後にメッセージが表示されたタイミングを確実に捉えられます。
まとめ
本記事では「GTMで要素が表示されたときに発火するトリガー」を実装する方法を解説しました。
- 標準機能(要素の表示トリガー)
- セレクタ指定
p.form_complete - DOM変更を監視をオンにする
- テキスト一致条件で精度を高められる
- セレクタ指定
- 安定しない場合の解決策
- カスタムHTMLタグ + MutationObserver
dataLayer.push()でカスタムイベントを発火
動的に表示される要素を正確に計測できれば、フォーム完了の正しいCV計測や、ユーザー行動の深掘り分析に役立ちます。ぜひプロジェクトに応じて適切な方法を導入してみてください。
発火しているかどうかを確認する場所
トリガーを設定したあと、「そもそも発火しているのか」を確かめる場所は大きく3つあるかなと思います。
1. GTMのプレビューモード(Tag Assistant)
GTM管理画面右上の「プレビュー」からサイトを開くと、左側にイベントの時系列が並びます。要素の表示なら Element Visibility、クリックなら Click といったイベントが積まれていくので、まずそのイベント自体が発生しているかを見ます。イベントが出ていないならトリガーの条件以前の問題で、リスナー側(組み込み変数や監視対象)を疑うことになります。
イベントは出ているのにタグが「Tags Not Fired」側にいる場合は、そのタグをクリックすると各条件の判定結果が表示されます。どの条件が false になっているかまで見えるので、ここが一番効率のいい確認ポイントだと思います。
2. 変数タブで実際の値を見る
条件がズレる原因の多くは「指定した値と実際の値が違う」です。該当イベントを選んだ状態で「Variables」タブを開くと、その瞬間の Click Classes や Click Text、カスタムJavaScript変数の戻り値が確認できます。全角スペースや末尾の改行が混ざっていて「等しい」が通らない、というのはありがちなパターンです。
3. GA4のDebugView
GTM側でタグが発火していても、GA4に届いているかは別の話です。Tag Assistantで接続中は debug_mode が付くので、GA4管理画面の「DebugView」でイベントの到達とパラメータを確認できます。GTMは発火、GA4には来ない、という場合は測定IDや同意設定あたりを見ることになるかなと。
クリックイベントが発火しないときによくある原因
クリック系のトリガーは、設定自体は簡単な割につまずきどころが多い印象です。
- 組み込み変数が無効のまま:
Click ElementClick ClassesClick IDClick TextClick URLなどのClick系変数は初期状態でオフです。有効化していないと、トリガー条件を書いても常に空文字と比較することになります。 - トリガーの種類が合っていない:「すべての要素」は
gtm.click、「リンクのみ」はgtm.linkClickと、発生するイベントが別物です。<a>以外のボタンやdivを「リンクのみ」で拾おうとしても発火しません。 - クリックされたのが子要素:
<button class="cv"><span>送信</span></button>のような構造だと、実際にクリックされるのはspanです。Click Elementを「CSSセレクタに一致」にして.cv, .cv *のように子孫も含める書き方にすると安定しやすいです。 - ページ遷移が先に起きる:リンククリックで即遷移すると、タグが送信される前にページが離脱してしまうことがあります。「リンクのみ」トリガーの「タグの配信を待つ」を使うか、GA4であればビーコン送信に任せる形になります。
- iframe内の要素:外部フォームツールなどをiframeで埋め込んでいる場合、親ページのGTMからは中のクリックを取得できません。この記事のMutationObserverも同様に届かないので、フォーム側が提供するコールバックやpostMessage、リダイレクト先のサンクスページでの計測に切り替える必要があります。
stopPropagation()で止められている:GTMのクリックリスナーはdocumentまでイベントが上がってくる前提なので、途中で伝播が止められていると検知できません。この場合はカスタムHTMLタグで対象要素に直接リスナーを付け、dataLayer.push()する形が現実的だと思います。
プレビューでは発火するのに本番で発火しないとき
プレビューで動いたのに本番で計測されない、という相談もよく見かけます。原因はだいたい限られていて、順に潰していくのが早いかなと。
まず公開(Submit)していないケース。プレビューはワークスペースの内容を参照するので、公開前でも動いてしまいます。バージョンが公開済みかを確認するのが最初です。
次にコンテナスニペットの設置漏れ。完了ページだけテンプレートが別で、<head> のGTMコードが入っていない、というのは起こりがちです。本番ページのソースで gtm.js の読み込みを確認しておくと早いです。
それから同意管理(CMP)や広告ブロッカー。同意モードを入れている場合、ユーザーが同意するまでタグが待機、あるいは配信されない設計になっていることがあります。プレビュー中の自分は同意済みでも、本番の一般ユーザーは違う、という差が出ます。
最後にトリガー条件がプレビュー環境と本番でズレているパターン。Page Path や Page URL に開発環境のドメインやパラメータ付きURLを条件として書いていると、本番で一致しません。条件のURLは「含む」で緩めに書いておくと事故が減ると思います。
「要素の表示」トリガー自体が反応しないときの確認ポイント
クリック系の原因は上で整理しましたが、要素の表示トリガーは別のところでつまずきやすいです。プレビューに Element Visibility が一度も出てこない場合、次のあたりを疑うことになると思います。
- セレクタが実際のDOMと一致していない:クラス名が動的に付け替えられていたり、JavaScriptで表示される前と後で構造が変わっていたりします。ブラウザのコンソールで
document.querySelectorAll('p.form_complete')を実行して、表示後に要素が取れるかを先に確かめておくと早いです。 - 「DOMの変更を監視」がオフ:ページを読み込んだ後に追加される要素は、この設定がオフだと監視対象になりません。
- 要素のサイズがゼロ:
display: noneのままの要素や、高さ0で中身だけ出すような実装だと、「画面に表示された」と判定されないことがあります。見た目には出ていても、実際に表示されているのは親要素というパターンもあるので、セレクタを親に変えると拾えることもあります。 - 最小表示時間を長くしすぎている:「画面上での最小表示時間」を設定していると、その時間より早くメッセージが消える実装では発火しません。
- ページ読み込み時点で既に画面内にある:この場合は読み込み直後に発火するので、フォーム送信前に誤って発火していないかも一緒に見ておいた方が良いと思います。
発火しすぎる・二重に計測されるとき
「発火しない」の逆で、同じイベントが何度も計測される相談もよく見かけます。CVが実際より多く出てしまうので、広告の最適化にも影響しやすいところです。
見直すところは主に3つあるかなと思います。
1. トリガー側の発火タイミング 要素の表示トリガーには「1ページにつき1度」「1要素につき1度」「要素が画面に表示されるたび」があります。「表示されるたび」にしていると、スクロールで要素が画面から出て、また戻ってきただけで再発火します。CV計測なら「1ページにつき1度」が扱いやすいと思います。
2. タグ側の配信オプション タグの詳細設定にある「タグ配信オプション」で「1ページにつき1度」を選ぶと、複数のトリガーが条件を満たしてもタグは1回だけ配信されます。トリガーを複数紐づけている場合の保険として使えます。
3. 同じ計測が別経路でも入っている GTMのタグと、サイトに直書きされたgtag.jsの両方でイベントを送っている、GA4の「拡張計測機能」のフォーム操作と自前のイベントが重複している、というケースもあります。GA4のDebugViewで同じタイミングに同じイベントが2つ届いていないかを見ると、切り分けやすいと思います。
なお、SPA(ページ遷移なしで画面が切り替わるサイト)では「1ページにつき1度」の「ページ」がリロードされるまで続くので、画面を切り替えても再発火しないことがあります。その場合は履歴の変更トリガーを組み合わせるなど、サイトの作りに合わせた調整が必要になるかなと。
- アクセス解析
【GTM/GA4】Cookie同意バナーの実装で使う「同意モード」「同意の初期化トリガー」とは何か?その仕組みと実装のポイントを徹底解説
Googleタグマネージャー(GTM)を活用したCookie規制対応の第一歩として、「同意モード(Consent Mode)」の理解と正しい実装は欠かせません。とくに近年、GDPRやePrivacyなどの個人情報保護規制 […]
- アクセス解析
GTMのフォーム送信トリガーが発火しない原因と対処|Contact Form 7・Ajax送信・埋め込みフォームの切り分けと代替トリガー
GTMのフォーム送信トリガーが発火しない原因を、Ajax送信・iframe埋め込み・トリガー条件の3型で切り分け。プレビューモードでの1分判定、Contact Form 7のwpcf7mailsentを使う設定、要素の表示やpostMessageなど代替トリガーの選び方、誤発火と二重計上の確認まで当日中に進められる手順でまとめました。
- アクセス解析
GA4のクロスドメイン設定が効かない・_glパラメータが付かない原因と確認手順|設定・リンク形式・リダイレクトの3層切り分け
GA4のクロスドメイン設定をしたのに_glパラメータが付かない・途中で消える・セッションが切れる原因を、設定・リンク形式・リダイレクトの3層で切り分け。遷移先URLを見る1分テストから、ボタンやフォームで効かない理由、Networkタブでの消失箇所の特定、修正後の検証まで当日中に確認できる手順でまとめました。