GTMカスタムHTMLタグ3つで作る、広告クリック→フォーム送信のリード追跡パイプライン

Written by
John Doe
公開日
2026-03-25

目次

広告クリックIDが「消える」問題

Google広告をクリックしたユーザーがフォームを送信する。その間にgclidは失われる。

広告プラットフォームはクリックIDをURLパラメータとして付与する。だがサイト内でページ遷移が起きた時点で、そのパラメータはURLから消える。外部フォームサービスを埋め込んでいる場合はなおさらだ。フォーム送信データにクリックIDが含まれなければ、CRM上のリードと広告クリックを紐付ける手段がない。

この記事では、GTM(Googleタグマネージャー)のカスタムHTMLタグ3本だけで、広告クリックからフォーム送信までを1つのIDで追跡するパイプラインを構築する方法を解説する。サーバーサイドの開発は不要。GTMの管理画面だけで完結する。

全体アーキテクチャ: 3タグ構成

パイプラインは3つのカスタムHTMLタグで構成される。

┌─────────────────────────────────────────────────┐
│  GTM Container                                  │
│                                                 │
│  [Tag 1] UUID生成         ← Initialization      │
│    └→ localStorage + Cookie に保存              │
│    └→ dataLayer.push / window.__lead_uuid       │
│                                                 │
│  [Tag 2] クリックID・UTM取得 ← Initialization   │
│    └→ gclid / fbclid / yclid / UTM を抽出      │
│    └→ localStorage + Cookie(90日)に保存       │
│    └→ ランディングページURLを初回のみ記録       │
│                                                 │
│  [Tag 3] フォーム自動注入   ← DOM Ready         │
│    └→ iframe[src] にクエリパラメータを付与      │
│    └→ MutationObserver で遅延読み込み対応       │
│                                                 │
└─────────────────────────────────────────────────┘
         ↓
┌─────────────────────────────────────────────────┐
│  外部フォームサービス                            │
│  hidden field で lead_uuid / gclid 等を受け取り │
│  → CRM / スプレッドシートに記録                 │
└─────────────────────────────────────────────────┘

タグ1とタグ2はInitializationタイミングで発火し、タグ3はDOM Readyで発火する。タグシーケンス(発火順序)でTag 1 → Tag 2 → Tag 3の順を保証する。

タグ1: UUID生成

全訪問者に対して一意のリードIDを発行する。UUID v4形式を使う。

設計方針

  • 初回訪問時にUUIDを生成し、再訪問時は既存値を再利用する
  • localStorageとCookieの二重保持でITP(Intelligent Tracking Prevention)に備える
  • crypto.randomUUID()を優先し、非対応ブラウザにはフォールバックを用意する

コード例

<script>
(function() {
  var STORAGE_KEY = 'lead_uuid';
  var COOKIE_DAYS = 390;

  // Cookie読み書きユーティリティ
  function getCookie(name) {
    var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
    return match ? decodeURIComponent(match[2]) : null;
  }

  function setCookie(name, value, days) {
    var expires = new Date(Date.now() + days * 864e5).toUTCString();
    document.cookie = name + '=' + encodeURIComponent(value)
      + ';expires=' + expires
      + ';path=/;SameSite=Lax';
  }

  // UUID v4 生成(フォールバック付き)
  function generateUUID() {
    if (typeof crypto !== 'undefined' && crypto.randomUUID) {
      return crypto.randomUUID();
    }
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      var r = Math.random() * 16 | 0;
      return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
  }

  // 既存値を探す(localStorage優先 → Cookie)
  var uuid = null;
  try { uuid = localStorage.getItem(STORAGE_KEY); } catch(e) {}
  if (!uuid) uuid = getCookie(STORAGE_KEY);

  // なければ新規生成
  if (!uuid) uuid = generateUUID();

  // 二重保持で書き戻す
  try { localStorage.setItem(STORAGE_KEY, uuid); } catch(e) {}
  setCookie(STORAGE_KEY, uuid, COOKIE_DAYS);

  // 後続タグから参照できるようにする
  window.__lead_uuid = uuid;
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    lead_uuid: uuid
  });
})();
</script>

ポイント

  • Cookieの有効期限は390日。Chromeの1st Party Cookieの上限(400日)に収まる範囲で最大化している
  • SameSite=Laxを指定することで、クロスサイトリクエストでは送信されない1st Party Cookieになる
  • window.__lead_uuidに格納することで、後続のタグ2・タグ3からグローバル変数として参照できる
  • dataLayer.pushしておけば、GA4のイベントパラメータとしても取得可能になる

タグ2: クリックID・UTM取得

URLパラメータから広告クリックID(gclid, fbclid, yclid)とUTMパラメータを抽出し、保存する。

設計方針

  • 初回のランディング時のみパラメータを取得する(上書き防止)
  • ランディングページURLも記録し、流入元の完全な情報を保持する
  • Cookieの有効期限は90日。広告のアトリビューションウィンドウに合わせる

コード例

<script>
(function() {
  var COOKIE_DAYS = 90;
  var PARAMS = ['gclid','fbclid','yclid','utm_source','utm_medium',
                'utm_campaign','utm_term','utm_content'];

  function getCookie(name) {
    var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
    return match ? decodeURIComponent(match[2]) : null;
  }

  function setCookie(name, value, days) {
    var expires = new Date(Date.now() + days * 864e5).toUTCString();
    document.cookie = name + '=' + encodeURIComponent(value)
      + ';expires=' + expires
      + ';path=/;SameSite=Lax';
  }

  function store(key, value) {
    try { localStorage.setItem(key, value); } catch(e) {}
    setCookie(key, value, COOKIE_DAYS);
  }

  function retrieve(key) {
    var v = null;
    try { v = localStorage.getItem(key); } catch(e) {}
    return v || getCookie(key);
  }

  var url = new URL(window.location.href);
  var stored = {};

  PARAMS.forEach(function(param) {
    var val = url.searchParams.get(param);
    if (val) {
      store(param, val);
      stored[param] = val;
    } else {
      var existing = retrieve(param);
      if (existing) stored[param] = existing;
    }
  });

  // ランディングページURL(初回のみ)
  if (!retrieve('landing_page')) {
    var lp = window.location.origin + window.location.pathname;
    store('landing_page', lp);
    stored.landing_page = lp;
  } else {
    stored.landing_page = retrieve('landing_page');
  }

  // グローバル変数に格納
  window.__lead_params = stored;
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push(stored);
})();
</script>

ポイント

  • URLにパラメータがある場合のみ上書きする。直接訪問やブックマーク経由では既存値を維持する
  • ランディングページURLはorigin + pathnameのみ保存する。クエリパラメータは含めない(個人情報やトークンが混入するリスクを避ける)
  • 90日の有効期限は、Google広告のデフォルトのアトリビューションウィンドウ(90日)に合わせた設定

タグ3: フォーム自動注入

ページ上の外部フォーム(iframe埋め込み)を検出し、リードIDとクリックIDをクエリパラメータとして自動注入する。

設計方針

  • iframe要素のsrc属性にクエリパラメータを追加する方式
  • ページ読み込み後に動的に挿入されるiframeにも対応する(MutationObserver)
  • フォームサービスのドメインで対象iframeを絞り込む

コード例

<script>
(function() {
  // 注入するパラメータを収集
  var params = {};
  if (window.__lead_uuid) params.lead_uuid = window.__lead_uuid;

  var leadParams = window.__lead_params || {};
  ['gclid','fbclid','yclid','utm_source','utm_medium',
   'utm_campaign','landing_page'].forEach(function(key) {
    if (leadParams[key]) params[key] = leadParams[key];
  });

  if (Object.keys(params).length === 0) return;

  var queryString = Object.keys(params).map(function(k) {
    return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);
  }).join('&');

  // 対象フォームのドメインを指定(環境に合わせて変更)
  var FORM_DOMAIN = 'form.example.com';

  function injectParams(iframe) {
    if (!iframe.src || iframe.src.indexOf(FORM_DOMAIN) === -1) return;
    if (iframe.dataset.paramsInjected) return;

    var separator = iframe.src.indexOf('?') === -1 ? '?' : '&';
    iframe.src = iframe.src + separator + queryString;
    iframe.dataset.paramsInjected = 'true';
  }

  // 既存のiframeに注入
  document.querySelectorAll('iframe').forEach(injectParams);

  // 遅延読み込みされるiframeにも対応
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(m) {
      m.addedNodes.forEach(function(node) {
        if (node.tagName === 'IFRAME') injectParams(node);
        if (node.querySelectorAll) {
          node.querySelectorAll('iframe').forEach(injectParams);
        }
      });
    });
  });

  observer.observe(document.body, { childList: true, subtree: true });
})();
</script>

ポイント

  • FORM_DOMAIN変数で対象のフォームサービスを絞り込む。無関係なiframe(YouTube埋め込み等)にパラメータが付与されるのを防ぐ
  • dataset.paramsInjectedフラグで二重注入を防止する
  • MutationObserverはページ全体を監視対象にしている。パフォーマンスへの影響は軽微だが、フォームが特定のコンテナ内にしか出現しない場合は監視範囲を限定してもよい

フォーム側の設定: hidden fieldの設計

フォームサービス側では、注入されたクエリパラメータをhidden field(非表示フィールド)として受け取る設定が必要になる。

設定の流れ

  • フォームにhidden fieldを追加する。フィールド名はlead_uuidgclidfbclid
  • 各hidden fieldの「デフォルト値をURLパラメータから取得する」オプションを有効にする
  • 多くのフォームサービス(Typeform, HubSpot Forms, Jotform等)はこの機能を標準で備えている

フォームサービスがURLパラメータの自動取得に対応していない場合は、フォーム内にJavaScriptを追加してクエリパラメータを手動でhidden fieldに注入する必要がある。

テスト手順

実装後は以下の手順で動作を確認する。

1. パラメータ付きURLでアクセスする

https://example.com/lp?gclid=test123&utm_source=google&utm_medium=cpc

2. ブラウザの開発者ツールで確認する

  • Console: window.__lead_uuidwindow.__lead_params を確認。値が格納されているか
  • Application > Local Storage: lead_uuid, gclid, utm_source 等のキーが保存されているか
  • Application > Cookies: 同じキーがCookieにも保存されているか

3. iframe注入を確認する

  • Elementsパネルでiframeのsrc属性を確認する。?lead_uuid=xxx&gclid=test123が付与されているか
  • GTMのプレビューモード(Tag Assistant)で3つのタグが正しい順序で発火しているか確認する

4. フォーム送信テスト

  • テスト送信を行い、フォームサービスの送信データにlead_uuid, gclid等が含まれているか確認する
  • 別のページに遷移してからフォームページに戻っても、値が維持されているか確認する

応用: GA4・BigQueryへの拡張

このパイプラインはフォーム送信の追跡だけにとどまらない。GA4やBigQueryと組み合わせることで、さらに高度な分析が可能になる。

GA4カスタムディメンション

  • タグ1でdataLayer.pushしたlead_uuidを、GA4のユーザースコープカスタムディメンションとして設定する
  • これにより、GA4上で特定のリードがサイト内でどのページを閲覧し、どのイベントを発火させたかを追跡できる

BigQueryエクスポートとの連携

  • GA4のBigQueryエクスポートを有効にすれば、lead_uuid付きの行動ログがBigQueryに蓄積される
  • CRMの成約データ(lead_uuidをキーにして)とJOINすることで、「どの広告キャンペーンから流入したリードが、最終的に成約したか」をSQLで分析できる

データフローの全体像

広告クリック → LP(UUID + gclid保存)
  → サイト回遊(GA4にlead_uuid送信)
  → フォーム送信(lead_uuid + gclid をフォームデータに含む)
  → CRM(lead_uuid + gclid で広告クリックと紐付け)
  → BigQuery(GA4行動ログ + CRM成約データをlead_uuidでJOIN)

まとめ

GTMのカスタムHTMLタグ3本で、広告クリックからフォーム送信までの追跡パイプラインを構築できる。要点を整理する。

  • タグ1: UUID v4を生成し、localStorage + Cookieの二重保持でITPに対応する
  • タグ2: gclid/fbclid/yclid/UTMをURLから取得し、90日間保持する
  • タグ3: iframe埋め込みフォームにクエリパラメータを自動注入する。MutationObserverで動的要素にも対応

サーバーサイド開発なしで、GTMの管理画面だけで完結する点がこの設計の強みだ。広告費のROIを正確に測定するための第一歩として、試してみてほしい。

Relation

関連記事

This is some text inside of a div block.

GTMカスタムHTMLタグ3つで作る、広告クリック→フォーム送信のリード追跡パイプライン

This is some text inside of a div block.
7 min read
This is some text inside of a div block.

GA4クロスドメイン計測の完全ガイド|設定手順からGCLID連携・BigQuery活用まで

This is some text inside of a div block.
7 min read
Googleタグゲートウェイの解説記事のサムネイル
This is some text inside of a div block.

Googleタグゲートウェイとは?広告計測タグを自社ドメイン経由で配信する無料の仕組み

This is some text inside of a div block.
7 min read
This is some text inside of a div block.

「自動化すべきか」の判断基準|KPIダッシュボードとSNS投稿で学んだ設計思想の違い

This is some text inside of a div block.
7 min read
This is some text inside of a div block.

GA4クロスドメイントラッキングの設定と落とし穴|広告LPから本サイトへのCV計測

This is some text inside of a div block.
7 min read
This is some text inside of a div block.

Lark Bitableを業務データベースとして外部連携する|API活用とNotionとの使い分け

This is some text inside of a div block.
7 min read

現在【毎月先着5社様】限定無料相談受付ます

大変申し訳ありません。私たちのリソースには限りがあり、一社一社に質の高いサービスを提供するため、現在【毎月先着5社様】限定で、この特別な条件(全額返金保証+無料相談)でのご案内とさせていただいております。

さらに、今このページをご覧のあなただけに、無料相談へお申し込みいただいた方限定で、通常5万円相当の【競合サイト分析&改善提案レポート】を無料でプレゼントいたします。

枠がすぐに埋まる可能性がありますので、お早めにお申し込みください。

プライバシーポリシーに同意し、まずは無料相談をおこないます
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.