
GA4のセッション数と、BigQueryにエクスポートされたデータによるセッション数がズレる——これは多くの分析担当者が直面する悩みのひとつです。
また、GA4画面でのデータと比べて、BigQueryにエクスポートしたデータではダイレクト流入が異常に多くなってしまう、という事例もよく聞きますが、これらの差異は両者の仕様の違いによるものです。
本記事では、そうしたズレが発生する背景や構造を踏まえ、BigQuery上でのGA4デフォルトチェネルグループの再現方法や、流入元別セッションをGA4の数値の定義に近づけるよう補正するためのテクニックを紹介します。
また、2024年7月17日に追加された新しいフィールド「session_traffic_source_last_click
」についてもご紹介します。
※GA4とBigQueryの構造的な違いにフォーカスした前編記事もあわせてご参照ください:
👉 GA4とBigQueryで流入元セッションがズレる理由|構造の違いを理解する – 前編
⚠️ 本記事に引用しているSQLクエリは未検証のため、正常な動作は保証できません。検証・デバッグ済みのSQLクエリ全文は、次回の検証記事に掲載しますので、そちらをご参照ください。
1. チャネル分類の補正と整合性の確保
前編でも触れた通り、GA4ではデフォルトでチャネルが分類(デフォルトチャネルグループ)されていますが、BigQueryのエクスポートデータにはこの分類情報が含まれていません。そのため、チャネル分類ロジックをBigQuery上で再現する必要があります。
以下は、チャネル再分類を含む簡易的なSQL例です(詳細は前回記事を参照→ GA4チャネルグループ分類の正規表現まとめ|BigQuery用サンプルSQLつき):
CASE
WHEN REGEXP_CONTAINS(medium, r"^organic$") AND REGEXP_CONTAINS(source, r'(google|bing|yahoo|baidu|duckduckgo|search\.brave\.com)') THEN 'Organic Search'
WHEN REGEXP_CONTAINS(source, r'(facebook|instagram|twitter|t.co|linkedin|pinterest)')
AND REGEXP_CONTAINS(medium, r'^(social|social-organic)$') THEN 'Organic Social'
WHEN REGEXP_CONTAINS(source, r'(facebook|instagram|twitter|t.co|linkedin|pinterest)')
AND REGEXP_CONTAINS(medium, r'^(.*cp.*|ppc|retargeting|paid.*)$') THEN 'Paid Social'
WHEN REGEXP_CONTAINS(medium, r'^(cpc|ppc|paidsearch)$')
AND REGEXP_CONTAINS(source, r'(google|bing|yahoo|baidu|duckduckgo|search\.brave\.com)') THEN 'Paid Search'
WHEN REGEXP_CONTAINS(medium, r'^(email|e-mail)$') THEN 'Email'
WHEN REGEXP_CONTAINS(medium, r'^(affiliate)$') THEN 'Affiliates'
WHEN REGEXP_CONTAINS(medium, r'^(display|banner|cpm)$') THEN 'Display'
WHEN REGEXP_CONTAINS(medium, r'^(video|paidvideo)$') THEN 'Paid Video'
WHEN REGEXP_CONTAINS(medium, r'^(organic-video)$') THEN 'Organic Video'
WHEN REGEXP_CONTAINS(medium, r'^(audio)$') THEN 'Audio'
WHEN REGEXP_CONTAINS(medium, r'^(sms|text)$') THEN 'SMS'
WHEN REGEXP_CONTAINS(medium, r'^(push|notification)$') THEN 'Mobile Push Notifications'
WHEN source = '(direct)' AND (medium = '(not set)' OR medium = '(none)') THEN 'Direct'
ELSE 'Referral'
END AS default_channel_group
2. セッションの補正と再現テクニック
GA4とBigQueryで流入元別セッションがズレる大きな要因の1つに「セッションの属性処理」があります。ダイレクト訪問した再訪ユーザーに対して、GA4画面には前回の流入元からの訪問としてカウントするロジックがありますが、BigQueryのエクスポートデータには2024年7月17日まで反映されていなかったため、手動でロジックを再現しなければなりません。
以下は、代表的な再現方法です:
1)2024年7月17日以降のデータ
2024年7月17日以降のデータは、GA4のロジックを反映したフィールド「session_traffic_source_last_click
」を使えばいいので、比較的簡単に実装できます。
SELECT
user_pseudo_id,
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
session_traffic_source_last_click.source AS session_source,
session_traffic_source_last_click.medium AS session_medium,
session_traffic_source_last_click.campaign AS session_campaign
FROM
`your_project.your_dataset.ga4_events_*`
WHERE
_TABLE_SUFFIX BETWEEN '20240717' AND '20241231'
AND event_name = 'session_start'
2)ラストノンダイレクトクリック属性の再現(2024年7月16日以前のデータ)
ただし、2024年7月16日以前のデータには「session_traffic_source_last_click」フィールドが存在しないため、イベントレベルのトラフィックソース情報をもとに、ロジック(ラストノンダイレクトクリック属性)を手動で再現する必要があります。
以下は、Napkyn社によって公開されている再現クエリの一例です:
出典:
Session-Level Attribution in GA4 with BigQuery: A Practical Guide
WITH SessionData AS (
SELECT
user_pseudo_id,
FORMAT_TIMESTAMP('%Y%m%d', TIMESTAMP_MICROS(event_timestamp)) AS event_date,
event_timestamp,
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
collected_traffic_source.source AS source,
collected_traffic_source.medium AS medium,
collected_traffic_source.campaign AS campaign,
CASE
WHEN (collected_traffic_source.source IS NULL OR collected_traffic_source.source = 'direct')
AND (collected_traffic_source.medium IS NULL OR collected_traffic_source.medium = '(none)')
THEN TRUE ELSE FALSE
END AS is_direct
FROM
`your_project.your_dataset.ga4_events_*`
WHERE
_TABLE_SUFFIX BETWEEN '20230101' AND '20231231'
GROUP BY
user_pseudo_id, event_date, event_timestamp, session_id, source, medium, campaign, is_direct
),
UserJourneys AS (
SELECT
user_pseudo_id,
session_id,
event_date,
MIN(event_timestamp) AS session_start_time,
MAX(is_direct) AS is_direct_session,
CASE
WHEN MAX(is_direct) = FALSE THEN MAX(IF(is_direct = FALSE, source, NULL))
ELSE NULL
END AS non_direct_source,
CASE
WHEN MAX(is_direct) = FALSE THEN MAX(IF(is_direct = FALSE, medium, NULL))
ELSE NULL
END AS non_direct_medium,
CASE
WHEN MAX(is_direct) = FALSE THEN MAX(IF(is_direct = FALSE, campaign, NULL))
ELSE NULL
END AS non_direct_campaign
FROM
SessionData
GROUP BY
user_pseudo_id, session_id, event_date
),
LastNonDirectAttribution AS (
SELECT
a.user_pseudo_id,
a.session_id,
a.event_date,
a.session_start_time,
a.is_direct_session,
CASE
WHEN a.is_direct_session THEN
LAST_VALUE(b.non_direct_source IGNORE NULLS) OVER (
PARTITION BY a.user_pseudo_id
ORDER BY a.session_start_time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
ELSE a.non_direct_source
END AS attributed_source,
CASE
WHEN a.is_direct_session THEN
LAST_VALUE(b.non_direct_medium IGNORE NULLS) OVER (
PARTITION BY a.user_pseudo_id
ORDER BY a.session_start_time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
ELSE a.non_direct_medium
END AS attributed_medium,
CASE
WHEN a.is_direct_session THEN
LAST_VALUE(b.non_direct_campaign IGNORE NULLS) OVER (
PARTITION BY a.user_pseudo_id
ORDER BY a.session_start_time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
ELSE a.non_direct_campaign
END AS attributed_campaign
FROM
UserJourneys a
LEFT JOIN
UserJourneys b
ON
a.user_pseudo_id = b.user_pseudo_id
AND b.session_start_time <= a.session_start_time
)
SELECT
user_pseudo_id,
session_id,
event_date,
is_direct_session,
COALESCE(attributed_source, 'direct') AS final_source,
COALESCE(attributed_medium, '(none)') AS final_medium,
attributed_campaign AS final_campaign
FROM
LastNonDirectAttribution
ORDER BY
user_pseudo_id, session_start_time
上記の再現SQLは複雑かつ手間がかかりますが、正確な流入元評価には欠かせません。再現プロセスや参考スクリプトについては、Napkyn社やOptimize Smartのブログに詳しい事例があります。
⚠️ 本記事に引用しているSQLクエリは未検証のため、正常な動作は保証できません。検証・デバッグ済みのSQLクエリ全文は、次回の検証記事に掲載しますので、そちらをご参照ください。
セッションのズレを補正するには、構造への理解が欠かせません。
“なぜズレるのか”という構造面の視点については、前編で詳しく解説しています。あわせてご覧ください。
👉 構造理解を扱った前編はこちら:
GA4とBigQueryで流入元セッションがズレる理由|構造の違いを理解する – 前編
📌 この記事は、GA4 × BigQuery の実務分析を支援する「サイトウオンライン」の実験室よりお届けしました。