広告の費用対効果、正しく測れていますか?
Google広告やSNS広告を出稿していると、こんな悩みに直面しがちです。
「問い合わせは来ているけど、どの広告から来たのか分からない」
広告管理画面のクリック数は見える。フォームの送信件数も分かる。でも「この問い合わせは、どのキャンペーンの、どの広告文をクリックした人なのか?」までは紐付かない。これでは広告のA/Bテストも、キーワードごとの費用対効果の判断もできません。
この記事では、GTM(Google Tag Manager)のdataLayerという仕組みを使って、広告のUTMパラメータをフォーム送信データに自動で紐付ける方法を解説します。実際に起きた「8つのパラメータのうち2つだけ欠落していた」という事例をもとに、修正の全体像をお伝えします。
修正量はコード4行の追加と、GTM管理画面での2クリック。小さな作業ですが、広告計測の精度が大きく変わります。
データの流れを俯瞰する
まず、広告クリックからフォーム送信までのデータの流れを整理します。
① ユーザーが広告をクリック→ URLに ?utm_source=google&utm_campaign=brand&utm_content=ad_a ... がつく
② GTMのカスタムHTMLタグがURLを読み取る→ dataLayer(一時メモ帳)に書き込む
③ DLV変数がdataLayerから値を取り出す→ GTMの他の機能が使える「付箋」になる
④ Injectorタグがフォーム(iframe)に値を自動注入→ フォーム送信データにUTMパラメータが含まれる
登場するGTM機能は3つです。
・メモ帳に書く → カスタムHTMLタグ(たとえるなら:レストランの注文伝票)・付箋を貼る → DLV変数(たとえるなら:ノートに貼った付箋)・フォームに渡す → Injectorタグ(たとえるなら:料理をテーブルに届ける配膳)
この3つのどれか1つでも欠けると、パラメータはフォームに届きません。今回の事例では、3つすべてで同じ2項目(utm_content と utm_term)が抜けていました。
パート1:dataLayerへの書き込み ── メモ帳に書く
【dataLayerとは】
dataLayer(データレイヤー)は、GTMが用意している一時的なメモ帳です。Webページ上のさまざまな情報を、GTMの各機能が共有するための仕組みで、JavaScriptの配列として存在しています。dataLayer.push() で情報を追加します。
【実装:URLパラメータを読み取ってdataLayerに書き込む】
広告リンクをクリックすると、ランディングページのURLにはこのようなパラメータがつきます。
https://example-clinic.com/lp?gclid=abc123&utm_source=google&utm_medium=cpc&utm_campaign=brand&utm_content=ad_variation_a&utm_term=keyword_x
GTMのカスタムHTMLタグで、これらを読み取ってdataLayerに書き込みます。コードの全体像は以下のとおりです。
// URLからパラメータを取得する関数
function getParam(name) {
var match = location.search.match(
new RegExp('[?&]' + name + '=([^&]*)')
);
return match ? decodeURIComponent(match[1]) : '';
}
// 8つのパラメータを読み取る
var params = {
gclid: getParam('gclid'),
utm_source: getParam('utm_source'),
utm_medium: getParam('utm_medium'),
utm_campaign: getParam('utm_campaign'),
utm_content: getParam('utm_content'),
utm_term: getParam('utm_term'),
yclid: getParam('yclid'),
fbclid: getParam('fbclid')
};
// ★ dataLayerに書き込む
dataLayer.push({
'event': 'utm_params_ready',
'gclid': params.gclid || localStorage.getItem('gclid') || '',
'utm_source': params.utm_source || localStorage.getItem('utm_source') || '',
'utm_medium': params.utm_medium || localStorage.getItem('utm_medium') || '',
'utm_campaign': params.utm_campaign || localStorage.getItem('utm_campaign') || '',
'utm_content': params.utm_content || localStorage.getItem('utm_content') || '', // ← 追加
'utm_term': params.utm_term || localStorage.getItem('utm_term') || '', // ← 追加
'yclid': params.yclid || localStorage.getItem('yclid') || '',
'fbclid': params.fbclid || localStorage.getItem('fbclid') || ''
});※ 実際にはlocalStorageとCookieへの保存処理も含まれます(再訪時の復元用)。
【欠落していた箇所】
修正前のコードでは、URLからは8つのパラメータを読み取っていたのに、dataLayer.push の中には6つしか書かれていませんでした。utm_content と utm_term が抜けていたのです。
レストランでたとえるなら、ホールスタッフがお客さんから8品の注文を聞いたのに、キッチンへの伝票には6品しか書かなかった状態。注文は聞いたのに伝票に書き忘れたので、2品が永遠に届きません。
この2つが欠けると、具体的にどう困るか。
・utm_content:同じキャンペーン内のどの広告文・バナーかを識別するパラメータ。欠けるとA/Bテストの効果が判定できない。・utm_term:どの検索キーワードで来たかを識別するパラメータ。欠けるとキーワードごとのCVR(成約率)が追えない。
修正はシンプルで、dataLayer.push のオブジェクトに2行追加するだけです。
パート2:DLV変数の作成 ── 付箋を貼る
【DLV変数とは】
DLV(Data Layer Variable)変数は、dataLayerの中から特定の値を取り出す仕組みです。
dataLayerが「大きなノート」だとすると、DLV変数は「そのノートの特定のページに貼った付箋」にあたります。
なぜ付箋が必要なのか。GTMの他の機能(GA4の設定タグなど)は、ノート(dataLayer)を直接めくって読むことができません。付箋(DLV変数)を通じて「ここに欲しい値が書いてあるよ」と教えてあげる必要があります。
【作成手順(コード不要)】
DLV変数の作成は、GTMの管理画面上の操作だけで完了します。
① GTMの管理画面を開く② 左メニューの「変数」をクリック③ 「ユーザー定義変数」の「新規」をクリック④ 変数タイプで「データレイヤーの変数」を選択⑤ 「データレイヤーの変数名」に utm_content と入力⑥ 変数名を dlv - utm_content などにして保存
同じ手順で utm_term 用のDLV変数も作成します。
【既存のDLV変数との関係】
今回の環境では、すでに8つのうち6つのDLV変数が存在していました。
✅ dlv - gclid✅ dlv - utm_source✅ dlv - utm_medium✅ dlv - utm_campaign❌ dlv - utm_content ← 今回作成❌ dlv - utm_term ← 今回作成✅ dlv - yclid✅ dlv - fbclid
パート1でdataLayerに書き込んだ値も、ここでDLV変数を作らなければGTMの他の機能からは参照できません。パート1とパート2はセットではじめて意味を持ちます。
パート3:フォームへの自動注入 ── フォームに渡す
【iframe埋め込みフォームの課題】
多くのWebサイトでは、お問い合わせフォームをiframe(インラインフレーム)で埋め込んでいます。外部のフォームサービスを使いつつ、見た目は自サイトに溶け込ませる方法です。
ただし、iframeは「額縁の中の別世界」。親ページ(自サイト)のJavaScriptからiframe内のフォームに直接データを渡すことは、セキュリティ上できません。
ではどうするか。フォームのURLにクエリパラメータとして値を付与する方法を使います。
【URL書き換えによるデータ受け渡し】
通常、iframe内のフォームURLはこうなっています。
<変更前>iframe src="https://form.example.com/12345"
GTMのInjectorタグが、このURLを動的に書き換えます。
<変更後>iframe src="https://form.example.com/12345?gclid=abc123&utm_source=google&utm_campaign=brand&utm_content=ad_a&utm_term=keyword_x"
フォームサービス側に「URLパラメータを隠しフィールドに自動取得する」設定があれば、この書き換えだけでフォーム送信データにパラメータが含まれます。
【Injectorタグの修正】
Injectorタグのコードでは、DLV変数の値を読み取ってフォームURLのクエリパラメータに追加しています。
var mapping = {
'gclid': '{{dlv - gclid}}',
'utm_source': '{{dlv - utm_source}}',
'utm_medium': '{{dlv - utm_medium}}',
'utm_campaign': '{{dlv - utm_campaign}}',
'utm_content': '{{dlv - utm_content}}', // ← 追加
'utm_term': '{{dlv - utm_term}}', // ← 追加
'yclid': '{{dlv - yclid}}',
'fbclid': '{{dlv - fbclid}}'
};ここでも修正前は utm_content と utm_term が含まれていませんでした。2行追加するだけで修正は完了です。
3つの修正の関係 ── なぜ全部必要なのか
3つのパートは直列につながっています。
パート1:メモ帳に書く(dataLayer.push に2行追加) ↓ 値がdataLayerに入るパート2:付箋を貼る(DLV変数を2つ作成) ↓ GTMの他のタグから参照可能になるパート3:フォームに渡す(Injectorタグのmappingに2行追加) ↓ フォーム送信データに含まれる
どれか1つでも欠けると、パラメータはフォームに届きません。裏を返せば、今回の原因は1つだけ。「utm_content と utm_term を追加し忘れた」という同じミスが、3箇所すべてに波及していたということです。
修正後の動作確認
GTMのプレビューモード(Tag Assistant)を使えば、公開前にデータの流れを確認できます。
① GTMの「プレビュー」ボタンをクリック② 対象サイトのURLを入力して接続③ テスト用URLにUTMパラメータをつけてアクセス 例:https://example-clinic.com/lp?utm_source=test&utm_content=ad_a&utm_term=keyword_x④ Tag Assistantの「Data Layer」タブで utm_content と utm_term が表示されることを確認⑤ フォームのiframeのURLにパラメータが付与されていることを、ブラウザの開発者ツールで確認
プレビューで問題がなければ、GTMの「公開」ボタンでバージョンを公開します。
まとめ
広告パラメータをフォーム送信に紐付ける仕組みは、GTMの3つの機能の連携で成り立っています。
・ステップ1「メモ帳に書く」→ カスタムHTMLタグ → dataLayer.push に2行追加・ステップ2「付箋を貼る」→ DLV変数 → 管理画面で変数を2つ作成・ステップ3「フォームに渡す」→ Injectorタグ → mappingオブジェクトに2行追加
修正量はコード4行の追加とGTM画面での2クリック。小さな変更ながら、「どの広告文が問い合わせにつながったか」「どの検索キーワードが成約に結びついたか」が可視化されます。
広告運用において「クリックされた」と「問い合わせにつながった」の間をつなぐデータは、費用対効果を判断するうえで欠かせません。GTMのdataLayerを正しく設定して、広告計測の精度を高めていきましょう。


