Article

GA4でのコンバージョントラッキング設定方法:移行後の必須知識

高田晃太郎
GA4でのコンバージョントラッキング設定方法:移行後の必須知識

Universal Analyticsのデータ処理停止は2023年7月1日に実施され、GA4への完全移行は既定路線となりました。¹ 移行自体は完了していても、コンバージョンの欠測や二重計測、アトリビューションの不一致に悩む組織は少なくありません。イベントベースの計測思想に変わったこと、推奨イベントのパラメータ要件、そして同意管理とモデリングを前提にした精度担保の考え方まで、一つでも取りこぼすとビジネス指標が揺らぎます。特にGA4ではゴールの概念が廃止され、「特定イベントをコンバージョンとして昇格」する運用が基本です。³この記事では、CTOやエンジニアリングマネージャがチームに伝えやすい形で、設計・実装・検証・運用までを流れるように整理します。実装コードはgtag.js、GTM、Measurement Protocol、Consent Mode、SPAでのページビュー、データ検証まで網羅し、「GA4 コンバージョン設定」「コンバージョントラッキング」の要点にフォーカスして解説します。

GA4のコンバージョン基礎設計:イベント発想に切り替える

最初に押さえるべきはモデルの違いです。GA4はセッション中心のUAと異なり、ユーザー行動をイベントとパラメータで表現します。² ここでのイベントは「起きた事象(例:generate_lead、purchase)」、パラメータは「その詳細(例:value、currency、transaction_id)」という理解で十分です。フォーム送信や申込完了、B2BのMQL到達、SaaSのトライアル開始など、意思決定に直結する行動をイベント名として定義し、必要なメタデータをパラメータで添えるのが原則です。Googleが公開する推奨イベントに沿うとレポートと広告連携の恩恵を受けやすく、例えばリード獲得はgenerate_lead、購入はpurchaseが該当します。² purchaseではtransaction_idが重複排除に不可欠になり、⁴ generate_leadでは価値評価をするならvaluecurrencyを付与して意思決定に耐える数値を残します。²

UAの目標種類やファネル設定をそのまま移植するのではなく、まずイベント命名規約と必須・任意パラメータを合意し、データガバナンスの観点からスキーマをバージョン管理します。組織的には、コンバージョンとして昇格するイベントは標準プロパティで最大30件という上限を前提に、意思決定に直結する最小集合に絞り込むと運用が安定します。³ 計測後の不一致を避けるために、アトリビューション(コンバージョン貢献度の配分)設定はデータドリブンを前提にしつつ、比較用としてラストクリックのビューも常備し、BI側での差分検証の習慣を作るとよいでしょう。⁵ この「設計→実装→検証→運用」の一貫性が、GA4のコンバージョン設定全体の品質を左右します。

gtag.jsでの基本実装:推奨イベントを素直に送る

ウェブ直実装では、計測IDの初期化とイベント送信を明示的に記述します。ページ単位の遷移が少ないサービスLPや小規模サイトではオーバーヘッドが小さく、トラブルシュートもしやすいのが利点です(GA4タグ=gtag.jsの基本形)。「GA4 コンバージョン設定」の最小構成として次を出発点にします。

<!-- GA4 gtag.js -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX', { send_page_view: true });

  // 例: リード獲得(フォーム完了)
  function onLeadSubmitted(leadValue){
    gtag('event', 'generate_lead', {
      value: leadValue,           // 例: 1000
      currency: 'JPY',            // 例: 日本円
      debug_mode: true            // DebugViewで確認したい場合
    });
  }
</script>

デバッグ中はdebug_modeを付けるとDebugView(リアルタイム検証画面)で即時に可視化しやすくなります。⁶ 本番では冗長なパラメータは省き、命名規約と型の整合性を優先します。コンバージョン昇格は後述の管理画面で行い、コード側は「正しいイベントを適切なタイミングで送る」ことに集中します。

GTM運用に向くケース:非エンジニア更新やA/B配信

複数ドメインでのタグ統制、マーテック連携、ノーコードでの一部調整を重視するならGTMが扱いやすくなります。データレイヤー(アプリからタグへ渡す標準的なデータの置き場)をインターフェースにして、アプリケーションから意味のあるペイロードだけを渡します。

<!-- GTMコンテナ -->
<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-XXXXXXX');</script>

<!-- アプリ側:フォーム完了時にpush -->
<script>
  window.dataLayer = window.dataLayer || [];
  function onLeadSubmittedDL(leadValue){
    window.dataLayer.push({
      event: 'generate_lead',
      value: leadValue,
      currency: 'JPY'
    });
  }
</script>

GTM側ではGA4イベントタグを作成し、トリガーにカスタムイベントgenerate_leadを指定します。命名はアプリ側のイベントと1対1で合わせ、タグ側で無闇に名前変換を行わないと、ログ基盤との突合が容易になります。これにより「GTMによるGA4コンバージョントラッキング」の再現性が高まります。

現場で起きる実装の落とし穴と回避策

移行後のトラブルの多くは、イベントの二重送信、SPAでのページビュー欠測、同意管理との不整合に収斂します。まず二重送信は、gtagとGTMを併用し同一イベントを両方から送ってしまう構成で起きがちです。どちらがソースオブトゥルースかを決め、片側に統一します。SPAでは仮想遷移でURLが変わっても自動検出されないため、ルーターのフックで明示的に送信します。同意管理ではConsent Mode v2の適切な初期化順序を守らないと、モデリング対象のシグナルが欠落します。⁸ これらは「GA4 コンバージョン設定の基本のき」として最優先で整えます。

SPAでのページビューとコンバージョン送信

ReactやVueなどのSPAでは、履歴APIによる画面遷移時にpage_viewを明示してからコンバージョンを送信します。以下はReact Router v6の例です。⁷

// React 18+, Router v6, gtag.js想定
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function useGa4Pageview(measurementId) {
  const location = useLocation();
  useEffect(() => {
    if (!window.gtag) return;
    window.gtag('config', measurementId, {
      page_path: location.pathname + location.search,
      page_title: document.title
    });
  }, [location.pathname, location.search, measurementId]);
}

export function AppTracking({ measurementId }){
  useGa4Pageview(measurementId);
  return null;
}

// 例: ある画面でのリード送信
export function LeadComplete(){
  const handle = () => {
    if (window.gtag) {
      window.gtag('event', 'generate_lead', { value: 1000, currency: 'JPY' });
    }
  };
  return <button onClick={handle}>Submit</button>;
}

ページビューはconfigで送り、コンバージョンはeventで送るという棲み分けを崩さないことが重要です。⁷ SPAでは必要に応じて初期設定のsend_page_viewをfalseにし、手動送信で統一する設計も検討すると、二重カウントの予防になります。

同意管理と計測を両立させるには、タグ読み込みより前に既定値を設定し、同意UIの選択に応じて更新します。Consent Modeは同意未取得時でも匿名化された信号を活用し、推定(モデル化)コンバージョンの精度を保つ仕組みです。既定値が遅れるとモデリング精度が下がり、広告連携や推定コンバージョンの質に直結します。⁸

<!-- gtag読込より前 -->
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('consent', 'default', {
    ad_storage: 'denied',
    analytics_storage: 'denied',
    functionality_storage: 'granted',
    security_storage: 'granted',
    personalization_storage: 'denied'
  });
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');

  // 同意UIで許諾後に更新
  function onConsentAccept(){
    gtag('consent', 'update', {
      ad_storage: 'granted',
      analytics_storage: 'granted'
    });
    // Googleの新拡張シグナル
    gtag('consent', 'update', {
      ad_user_data: 'granted',
      ad_personalization: 'granted'
    });
  }
</script>

GA4管理画面のクロスドメイン設定や内部トラフィック除外も、同意の前提が崩れない範囲で先に整備しておくと、コンバージョン率の急変に過度に振り回されなくなります。ここまで整えると「Consent Mode v2 を前提にしたGA4 コンバージョントラッキング」の土台が固まります。

サーバー送信とデータ検証:欠測に強い計測を作る

クライアント由来の欠測を最小化するには、バックエンドからのMeasurement Protocol送信を併用します。これはサーバーから直接GA4にイベントを送るHTTP APIで、広告ブロッカーや通信断の影響を受けにくくなります。クライアントとサーバーの二重送信はtransaction_idやイベントID(event_id)で重複排除できるように設計し、⁹ ⁴ BIやDWH側ではユニーク制約で整合性を担保します。以下はPythonでのサーバー送信例です。

import requests
import uuid

MEASUREMENT_ID = "G-XXXXXXXXXX"
API_SECRET = "YOUR_API_SECRET"
ENDPOINT = f"https://www.google-analytics.com/mp/collect?measurement_id={MEASUREMENT_ID}&api_secret={API_SECRET}"

# Webクライアントと同一ユーザーを結びたい場合はuser_id、
# もしくはclient_id(_gaから抽出)を用いる

def send_generate_lead(client_id: str, value: float):
    payload = {
        "client_id": client_id,
        "events": [
            {
                "name": "generate_lead",
                "params": {
                    "value": value,
                    "currency": "JPY",
                    "event_id": str(uuid.uuid4())
                }
            }
        ]
    }
    try:
        resp = requests.post(ENDPOINT, json=payload, timeout=5)
        resp.raise_for_status()
    except requests.RequestException as e:
        # ログに残してリトライキューへ
        print(f"GA4 MP error: {e}")

# 例: 実行
# send_generate_lead("12345.67890")

クライアントIDはCookieの_gaから抽出します。プライバシー要件からサーバー側で直接Cookieに触れない設計を取る場合は、クライアントで取得してAPIに渡し、バックエンドからMeasurement Protocolへ送る中継方式が扱いやすくなります。⁹

Node.js(Fetch)でのMeasurement Protocol送信

Node 18+でfetchが標準化され、サーバー側からの非同期送信が簡潔に書けます。

// Node 18+
const MEASUREMENT_ID = 'G-XXXXXXXXXX';
const API_SECRET = 'YOUR_API_SECRET';
const endpoint = `https://www.google-analytics.com/mp/collect?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`;

async function sendPurchase({ clientId, value, currency, transactionId }) {
  const body = {
    client_id: clientId,
    events: [
      {
        name: 'purchase',
        params: {
          value,
          currency,
          transaction_id: transactionId
        }
      }
    ]
  };
  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 5000);
    const res = await fetch(endpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
      signal: controller.signal
    });
    clearTimeout(timeout);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
  } catch (e) {
    console.error('GA4 MP error', e);
  }
}

// sendPurchase({ clientId: '12345.6789', value: 12000, currency: 'JPY', transactionId: 'ORDER-10001' });

購入系はtransaction_idを必ず付け、クライアント送信とサーバー送信の重複をプロパティ側で自然に排除できるようにしておくと、決済後の通信断にも強くなります。⁴

管理画面でのコンバージョン昇格とAPIによる自動化

イベントが流れ始めたら、GA4管理で対象イベントをコンバージョンに昇格します(管理画面で該当イベント名のトグルをON)。大規模プロパティでは、人手の操作ミスを避けるためにAdmin APIで自動化すると安全です。以下はPythonでConversionEventを作成する例です(Beta世代のクライアントを利用)。

from google.analytics.admin import AnalyticsAdminServiceClient
from google.analytics.admin_v1beta.types import ConversionEvent

# 認証はサービスアカウント。環境変数GOOGLE_APPLICATION_CREDENTIALSを設定しておく。

def create_conversion_event(property_id: str, event_name: str):
    client = AnalyticsAdminServiceClient()
    parent = f"properties/{property_id}"
    conv = ConversionEvent(event_name=event_name)
    return client.create_conversion_event(parent=parent, conversion_event=conv)

# 例: create_conversion_event('123456789', 'generate_lead')

管理画面の操作とAPIの整合を保つため、IaCの感覚でイベント定義をコード化し、リポジトリでトラッキングする運用が有効です。これにより「GA4 コンバージョン設定」の変更管理が明確になります。

検証と継続運用:DebugView、探索、そしてDWH

実装の良し悪しは検証の習慣で決まります。開発環境ではDebugViewでイベントの到達とパラメータの整合を秒単位で確認し、⁶ 本番では探索レポートでコンバージョン率とイベントの関係を可視化します。広告との整合はアトリビューションの違いで差が出るため、GA4のレポートだけで結論を出さず、DWHでの再集計を標準化すると意思決定の速度が上がります。BigQueryエクスポートをオンにしている場合、以下のようなクエリでユニークコンバージョンを素早く点検できます(event_idやuser_pseudo_idをキーに重複排除)。

-- GA4 export (events_*)からgenerate_leadのユニーク件数
SELECT
  _TABLE_SUFFIX AS dt,
  COUNT(DISTINCT CONCAT(COALESCE((SELECT value.string_value FROM UNNEST(event_params)
                                  WHERE key='event_id'), user_pseudo_id), '-', event_timestamp)) AS unique_conversions
FROM `project.dataset.events_*`
WHERE event_name = 'generate_lead'
GROUP BY dt
ORDER BY dt DESC;

Data APIでのサニティチェックも有効です。ダッシュボードの自動更新前にスモークテストを走らせ、急なゼロ件や極端なスパイクを検知したらSlackに通知すると運用が安定します。

from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import DateRange, Dimension, Metric, RunReportRequest

# GOOGLE_APPLICATION_CREDENTIALS を設定済みのサービスアカウントを想定

def ga4_count_generate_lead(property_id: str):
    client = BetaAnalyticsDataClient()
    request = RunReportRequest(
        property=f"properties/{property_id}",
        dimensions=[Dimension(name="eventName")],
        metrics=[Metric(name="eventCount")],
        date_ranges=[DateRange(start_date="7daysAgo", end_date="today")],
        dimension_filter={
            "filter": {
                "field_name": "eventName",
                "string_filter": {"value": "generate_lead"}
            }
        }
    )
    resp = client.run_report(request)
    for row in resp.rows:
        print(row.dimension_values[0].value, row.metric_values[0].value)

# ga4_count_generate_lead('123456789')

検証では、イベントの命名、必須パラメータの有無、同意状態での送信挙動を3点セットで確認します。モニタリングでは、転送失敗率、二重送信率、同意率に応じたモデリング比率といった品質KPIを定義し、週次でレビューします。特にB2BではMQL定義の変更が頻発するため、イベント名は安易に差し替えず、パラメータ側でバージョンを持つとダッシュボードや機械学習の特徴量が崩れません。

よくある不一致の読み解き方

広告プラットフォームとGA4のコンバージョン数が噛み合わない時、まずタイムゾーン、アトリビューションの窓とモデル、そして重複排除のキーを確認します。次に同意未取得時のモデル化コンバージョンが混在していないかを見ます(Consent Mode由来の推定値が入るケース)。最後に、サーバー送信とクライアント送信の二重をtransaction_idやevent_idで排除できているかを検証します。これらの視点を順に当てれば、ほとんどの差分は説明可能になります。⁵ ⁹

まとめ:小さく正しく始め、確実に積み上げる

GA4時代のコンバージョンは、イベント設計、同意、送信経路、検証の四点で成否が決まります。まずは推奨イベントに沿ってビジネス価値の高い最小集合を定義し、gtagやGTMで過不足なく送信します。欠測に悩むならMeasurement Protocolを併用して、transaction_idやevent_idで二重を防ぐ堅実な基盤を作ります。⁹ ⁴ 検証はDebugViewと探索を日次で回し、DWHでの再集計を週次の習慣にします。そうすれば、アトリビューションの揺らぎに翻弄されず、意思決定の速度と質を両立できます。あなたのプロダクトで最初に正したいのはどこでしょうか。イベント命名か、同意の初期化か、あるいは検証の仕組みか。今日ひとつだけでも改善し、来週の数値で前進を確かめる。その反復が、移行後の混乱を静かに終わらせてくれます。

参考文献

  1. Google Ads & Commerce Blog. Upgrade to Google Analytics 4 before July 1.
  2. Google アナリティクス ヘルプ. 推奨イベント(ウェブ).
  3. Google アナリティクス ヘルプ. コンバージョン(イベントをコンバージョンとしてマークする).
  4. Google Analytics Help. Transaction ID guidelines.
  5. Google Analytics Help. Attribution in Google Analytics 4 properties.
  6. Google Analytics Help. DebugView でイベントを監視する.
  7. Google Developers. Measure single-page applications (GA4).
  8. Google Developers. Consent mode (Advanced) for Google tags.
  9. Google Developers. Google Analytics 4 Measurement Protocol.