Article

Googleアナリティクス4活用術:データ分析でマーケ施策を改善

高田晃太郎
Googleアナリティクス4活用術:データ分析でマーケ施策を改善

2023年7月にUniversal Analyticsの処理が停止し[1]、Googleアナリティクス4(以下、GA4)が実質的な標準となりました。GA4は(標準プロパティで)BigQueryエクスポートを提供し[2]、データの基本単位をセッションではなくイベントに統一しています[6]。ここでいうイベントは「ユーザーが起こした行動の記録(例: ページ閲覧や購入)」で、時系列で分析しやすい形です。計測から分析、意思決定までの距離を短縮できる前提は整った一方で、実務では従来のセッション中心の見方から抜け出せず、広告やCRM連携を活かしきれていないケースが目立ちます。私は、エンジニアリング起点で施策改善のループを閉じることがCTOや技術リーダーの役割だと考えます。まずは事実に立脚し、GA4の構造を理解し、分析とアクションを結びつける仕組みを構築することが肝要です。ここではイベント設計、BigQuery分析、API連携の三点で、実装とビジネス効果に直結する方法を具体的に示します。

GA4で施策改善が加速する理由

GA4の本質は、イベントベースでユーザー行動を時系列に記録し[6]、クロスデバイスやプライバシー制約下でも計測を継続可能にした点にあります[3]。データドリブンアトリビューション(各接点の貢献度を統計的に配分する考え方)やコンバージョンモデリング(欠損データの推定)はブラックボックスに見えますが、インプットの品質を高めれば、安定して実務に耐える信号になります。品質とは、イベントの意味が一貫し、必要なパラメータが欠損せず、タイムスタンプとユーザー識別子が分析可能な精度で残っていることです。BigQuery(Googleのデータウェアハウス)へのエクスポートが標準化されたことで、ダッシュボード可視化にとどまらない分析、すなわちチャネル横断のマージやLTV推定、クリエイティブ単位の効果検証(因果を意識した検証)が現実的になりました[2]。さらにConsent Mode(同意状態に応じて計測挙動を切り替える仕組み)やEnhanced Conversions(同意済みのファーストパーティデータでコンバージョン補完を行う仕組み)の導入により、クッキーレス環境でもコンバージョンの補完が働き、媒体最適化の学習が途切れません[4][5]。技術リーダーに求められるのは、これらを前提にイベント設計の規約化、データ基盤への落とし込み、広告へのフィードバックという工程を、一貫したワークフローとして整えることです。

設計が9割:イベントとパラメータの規約化

命名規約は分析の再現性を左右します。主要イベントはpurchase、add_to_cart、view_item、generate_leadなどの推奨名に合わせ[6][7]、value、currency、items、campaign、source、medium、creative、contentといった属性を必須パラメータとして定義します。複数プロダクトを横断する場合でも、item_idやitem_categoryの含意がブレないようにデータレイヤー契約を文書化し、フロントとバックで同じ辞書を参照するのが安全です。eコマースで税や送料を含む金額の扱いを誤るとROIの推定が崩れます。税を含むか否か、クーポン適用後かどうか、タイムゾーンの統一など、数式で解釈可能な定義に落としておくと、後段のSQLや機械学習が安定します。

<!-- Code 1: gtag.js で add_to_cart を送信 -->
<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');

  function onAddToCart(item){
    gtag('event', 'add_to_cart', {
      currency: 'JPY',
      value: item.price,
      items: [{
        item_id: item.id,
        item_name: item.name,
        item_category: item.category,
        quantity: item.qty
      }],
      campaign: window.__utm_campaign || '(not set)',
      source: window.__utm_source || '(direct)',
      medium: window.__utm_medium || '(none)'
    });
  }
</script>

この実装では通貨やvalueの定義を明示しています。値引き後の支払額をvalueに、クーポン割引額を別パラメータdiscountに保持すると、のちの売上貢献と値引きコストの分離が容易になります。UTMの運用はクライアント側の文字列継承に頼らず、可能ならサーバサイドで正規化した上で計測に渡すと安定します。

計測品質の担保:DebugView・sGTM・Measurement Protocol

リリース前のDebugView(GA4のリアルタイム検証画面)でイベントの順序や欠損を確認し、Consent Modeの同意フラグとイベントの到達関係を検証します。高単価なCVイベントはサーバサイドGTM(sGTM:タグ配信をサーバ側で行う構成)経由で送ると、アドブロックやネットワーク遮断の影響を軽減できます。オフライン成約はMeasurement Protocol v2(バックエンドからGA4へイベント送信するAPI)でサーバから送信し、広告側のコンバージョン補完と突合させると学習が安定します[8]。タイムゾーンと重複排除の鍵は実務で落とし穴になりがちです。

# Code 2: Measurement Protocol v2 でサーバ送信(重複排除とエラーハンドリング)
import os
import json
import time
import uuid
import logging
import requests

MEASUREMENT_ID = os.environ["GA4_MEASUREMENT_ID"]  # 例: G-XXXXXXXXXX
API_SECRET = os.environ["GA4_API_SECRET"]
CLIENT_ID = "555.{}".format(int(time.time()))  # 本番は実ユーザーの _ga 値等に置換
DEDUP_KEY = str(uuid.uuid4())

payload = {
    "client_id": CLIENT_ID,
    "non_personalized_ads": False,
    "events": [
        {
            "name": "generate_lead",
            "params": {
                "value": 0,
                "currency": "JPY",
                "engagement_time_msec": 1,
                "transaction_id": DEDUP_KEY
            }
        }
    ]
}

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

try:
    res = requests.post(endpoint, data=json.dumps(payload), timeout=3)
    res.raise_for_status()
except requests.HTTPError as e:
    logging.exception("GA4 MP send failed: %s", e)

transaction_idの一貫性を保てば、ブラウザとサーバの二重送信を避けられます。MPの検証エンドポイントでスキーマエラーを事前に検出すると、データの欠落を防げます[8]。

BigQueryエクスポートで意思決定を定量化

GA4の生データはevents_YYYYMMDDテーブルに日別パーティションで蓄積され、event_paramsやuser_propertiesは配列で保持されます。UNNESTを適切に使い、必要なキーだけを抽出し、読み取りバイトを削減するとコストが抑えられます[9]。アトリビューションの検証では、セッション由来のsourceやmediumをsession_startイベントから取得し、コンバージョンはpurchaseやgenerate_leadの発火から集計すると、媒体別のCVRがクリアになります。費用は媒体レポートを別テーブルにロードし、日付とキャンペーンキーで結合して効率的に算出します。

-- Code 3: 媒体別セッションとコンバージョン率
WITH sessions AS (
  SELECT
    event_date,
    (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source') AS source,
    (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'medium') AS medium,
    COUNTIF(event_name = 'session_start') AS sessions
  FROM `project.dataset.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
  GROUP BY event_date, source, medium
),
conversions AS (
  SELECT
    event_date,
    (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source') AS source,
    (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'medium') AS medium,
    COUNTIF(event_name = 'purchase' OR event_name = 'generate_lead') AS convs
  FROM `project.dataset.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
  GROUP BY event_date, source, medium
)
SELECT
  s.event_date,
  s.source,
  s.medium,
  s.sessions,
  IFNULL(c.convs, 0) AS convs,
  SAFE_DIVIDE(IFNULL(c.convs, 0), s.sessions) AS cvr
FROM sessions s
LEFT JOIN conversions c
USING(event_date, source, medium)
ORDER BY cvr DESC;

この集計はデイリーで媒体別のCVRを比較できます。費用テーブルを結合すればCPAやROASに拡張できます。スキャン量は必要な列に限定し、日付でパーティションを絞り、可能ならクエリ一時テーブルを活用します。BigQueryのオンデマンド料金はスキャンしたデータ量に応じて課金されるため、読み取りバイトを最小化する設計が有効です。

-- Code 4: コホート保持率(初回来訪週基準)
WITH first_week AS (
  SELECT
    user_pseudo_id,
    FORMAT_DATE('%G-%V', PARSE_DATE('%Y%m%d', MIN(event_date))) AS cohort_week
  FROM `project.dataset.events_*`
  GROUP BY user_pseudo_id
),
visits AS (
  SELECT
    e.user_pseudo_id,
    f.cohort_week,
    FORMAT_DATE('%G-%V', PARSE_DATE('%Y%m%d', e.event_date)) AS visit_week
  FROM `project.dataset.events_*` e
  JOIN first_week f USING(user_pseudo_id)
  WHERE e.event_name = 'session_start'
)
SELECT
  cohort_week,
  visit_week,
  COUNT(DISTINCT user_pseudo_id) AS users
FROM visits
GROUP BY cohort_week, visit_week
ORDER BY cohort_week, visit_week;

この出力をピボットすれば週次のリテンションマトリクスになります。施策適用週と保持の相関を計測し、テストとコントロールの差分を見れば、キャンペーンの効果を因果的に評価できます。媒体費を結合してマージンベースのLTVにすると、グローバル最適に近づきます。

スキーマ最適化とコスト管理の実務

頻出の抽出キーは事前に展開したマテビューや派生テーブルにしておくと、毎回のUNNESTを避けられます。events_*のクラスターキーにevent_dateとuser_pseudo_id(匿名化されたユーザー識別子)を選ぶとスキャン効率が上がります。運用の型としては、毎日走るダッシュボードは軽量な集計に留め、深掘りの臨時分析はサンドボックスに分けるとクラウドコストが安定します。行レベルのプライバシー制御はBigQueryの行アクセス制御や列マスキングで対応できるため、個人情報の混入を避ける設計と合わせて統制します。より詳しいBigQueryのコスト最適化は、公式ドキュメントや公開ガイドと合わせて学ぶと実装の精度が上がります。

GA4 Data APIと広告連携でループを閉じる

分析はアクションに繋がって初めて価値になります。GA4 Data APIでKPIを抽出し、自動でSlackやLooker Studioへ配信し、閾値割れでアラートを飛ばすと、劣化の早期検知が可能です。さらにGoogle Adsや他媒体のAPIとつなぎ、オーディエンスやコンバージョンのフィードバックを自動化すると、学習サイクルが短縮されます。クリエイティブIDやクエリ文言をイベントに同梱しておくと、後段の最適化が精密になります[10]。

# Code 5: GA4 Data API で日次レポート取得(Python)
from google.analytics.data_v1 import AnalyticsDataClient
from google.analytics.data_v1.types import DateRange, Dimension, Metric, RunReportRequest
from google.api_core.exceptions import GoogleAPIError
import os

PROPERTY_ID = os.environ["GA4_PROPERTY_ID"]
client = AnalyticsDataClient()

request = RunReportRequest(
    property=f"properties/{PROPERTY_ID}",
    dimensions=[Dimension(name="date"), Dimension(name="sessionSource"), Dimension(name="sessionMedium")],
    metrics=[Metric(name="sessions"), Metric(name="conversions"), Metric(name="totalRevenue")],
    date_ranges=[DateRange(start_date="2025-01-01", end_date="2025-01-31")]
)

try:
    response = client.run_report(request)
    for row in response.rows:
        print([d.value for d in row.dimension_values], [m.value for m in row.metric_values])
except GoogleAPIError as e:
    print("API error", e)

この出力を媒体費テーブルと結合し、閾値に応じて入札と予算を再配分します。Google Ads APIではオフラインコンバージョンのアップロードや調整も可能で、媒体学習に質の高い信号を返せます[10]。

# Code 6: Google Ads API でオフラインコンバージョンをアップロード
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
import os

client = GoogleAdsClient.load_from_storage()
conversion_upload_service = client.get_service("ConversionUploadService")

click_conversion = client.get_type("ClickConversion")
click_conversion.conversion_action = "customers/1234567890/conversionActions/1111111111"
click_conversion.gclid = "EAIaIQobChMI..."  # 同意取得済みのクリックID
click_conversion.conversion_date_time = "2025-01-20 12:34:56+09:00"
click_conversion.conversion_value = 12000.0
click_conversion.currency_code = "JPY"

try:
    response = conversion_upload_service.upload_click_conversions(
        customer_id="1234567890",
        conversions=[click_conversion],
        partial_failure=True,
        validate_only=False,
    )
    for result in response.results:
        print("uploaded:", result)
except GoogleAdsException as ex:
    for e in ex.failure.errors:
        print("error:", e.message)

GDPRや電気通信事業法ガイドラインの文脈では、同意管理と識別子の保持期間に配慮が欠かせません。Consent Mode v2を導入し、同意がない場合のイベント送信を抑制しつつ、モデル化による補完を有効化すると、プライバシー遵守と最適化の両立が進みます[4]。さらに、UTMの運用ガイドを策定し、campaignやcontentの変数設計をチームで共有すると、クリエイティブテストの学習が速くなります。

品質をテストする小さなCI

計測はコードであり、テスト可能です。リリース前にMeasurement Protocolのスキーマ検証を自動化し、必須パラメータの欠損や型崩れを検知します。GTMのバージョン差分をコードレビューにかけ、データレイヤー契約との乖離を検出する仕組みを用意すると、障害の早期発見に繋がります。

# Code 7: pytest でMPペイロードを検証
import json
import re

def validate_payload(payload: dict) -> bool:
    assert "client_id" in payload and re.match(r"^\d+\.\d+$", payload["client_id"]) 
    assert "events" in payload and len(payload["events"]) > 0
    e = payload["events"][0]
    assert "name" in e and isinstance(e["name"], str)
    assert "params" in e and isinstance(e["params"], dict)
    assert "currency" in e["params"] and e["params"]["currency"] in ["JPY", "USD", "EUR"]
    return True

sample = {"client_id": "12345.67890", "events": [{"name":"purchase", "params":{"currency":"JPY","value":9800}}]}
assert validate_payload(sample)

このような小さなCIがあるだけで、本番での計測抜けや媒体側の学習崩壊を防げます。可観測性の観点では、イベント到達率や遅延分布をメトリクス化し、PrometheusやCloud Monitoringに送り、SLOを定義しておくと運用品質が安定します。

ROIを設計する:ビジネス指標への写像

データの価値は、施策変更と利益の関係を数字で語れることにあります。例えば月間トラフィックが50万セッション、現行CVRが2.0%、平均受注額が1.2万円だとします。CVRを0.3ポイント改善できれば、追加受注は1500件、粗売上は約1800万円の上振れです。媒体費が月2000万円なら、ROASは0.9から1.0へ近づき、マージン次第で黒字転換の閾値を超える可能性があります。GA4のデータから発見されたボトルネック、たとえば特定のLPの滞在が短く離脱が多い、あるいは特定のキャンペーンの新規率が高いがLTVが低い、といった洞察を施策に反映し、翌週の指標で差分を評価するサイクルを定着させます。重要なのは、KPIを指標単体ではなく因果でつなぐことです。セッション増加はコンバージョンを押し上げてもCPAを悪化させる懸念があり、逆にLTVの高いチャネルに予算を寄せれば短期のCVが減っても中期の利益は改善します。GA4とBigQuery、広告APIがそろえば、これらのトレードオフを管理するための意思決定ダッシュボードを短期間で構築できます。

最後に、分析はチームの作法によって速度が決まります。命名規約とデータ辞書をGitで管理し、PRレビューで仕様変更を明示する。週次の仮説レビューで、改善したい係数を先に合意し、必要なイベントの追加やタグの改修をすぐに反映する。数字と変更履歴が常に一体で残ることが、改善の継続性を支えます。技術リーダーが先頭でモデルと実装の両輪を回し続けることが、ビジネスの推進力になります。

まとめ:小さく測り、すぐ直し、確実に積み上げる

GA4はレポートツールではなく、施策改善のオペレーティングシステムです。イベント設計の規約化でデータの意味をそろえ、BigQueryで仮説に即した集計を素早く回し、API連携で広告やプロダクトに反映する。この一連の流れを一つのワークフローに束ねれば、改善の速度は確実に上がります。今日できる第一歩として、主要CVイベントの定義とパラメータの棚卸しを行い、欠損や二重送信がないかをDebugViewで確認してみてください。続けて、BigQueryの簡単なCVR集計をセットし、前週比での差分をチームでレビューすると、次の打ち手が見えてきます。成果は、計測の質と改善の回転数に比例します。今のデータでどこまで意思決定を前に進められるか、一度立ち止まって問い直し、明日からの一手に落としていきましょう。

参考文献

  1. Universal Analytics is no longer processing data. https://support.google.com/analytics/answer/11583528?hl=en
  2. Export Google Analytics 4 data to BigQuery (JA). https://support.google.com/analytics/answer/9358801?hl=ja
  3. Using first-party data with Google Analytics 4 to power durable and accurate measurement. https://support.google.com/analytics/answer/14299607?hl=en
  4. About Consent Mode and behavior modeling. https://support.google.com/analytics/answer/11161109?hl=en
  5. Enhanced Conversions overview. https://support.google.com/analytics/answer/14252663?hl=en
  6. GA4 recommended events: add_to_cart. https://support.google.com/analytics/answer/9267735#:~:text=add_to_cart%20%20,begins%20checkout
  7. GA4 recommended events: generate_lead. https://support.google.com/analytics/answer/9267735#:~:text=generate_lead%20%20,completes%20a%20purchase
  8. Google Analytics 4 Measurement Protocol (v2). https://developers.google.com/analytics/devguides/collection/protocol/ga4
  9. Export Google Analytics 4 data to BigQuery (EN). https://support.google.com/analytics/answer/9358801?hl=en
  10. Upload offline conversions using the Google Ads API. https://developers.google.com/google-ads/api/docs/conversions/upload-offline