この記事でわかること
GA4のレポート(Data API)とBigQueryエクスポートで、同じコンバージョンの参照元が食い違うことがあります。エクスポートに3つのトラフィックソース項目があること、公式の定義文がそもそも違うこと、そして自分のプロパティで乖離を測る手順を解説します。
生成AIによる要約
GA4のBigQueryエクスポートを使い始めると、必ず一度はぶつかる現象があります。管理画面では「直接流入」になっているコンバージョンが、BigQueryでは「有料検索」になっている。同じGA4のデータのはずなのに、どこから来たのかが食い違う。
これは不具合ではありません。エクスポートにはトラフィックソースの項目が3つあり、それぞれスコープと値の決め方が違うためです。そして、そのうちどれもレポート側の「セッションの参照元」と同じ規則にはなっていません。
この記事では、3つの項目の違いを整理したうえで、公式の定義文がどう違うのかを示し、最後に自分のプロパティで乖離を測る手順まで扱います。
前提: BigQueryエクスポートは「別システム」ではない
まず押さえておきたいのは、BigQueryエクスポートがGA4とは別の計測システムではないという点です。同じタグが集めた同じデータを、別の形で書き出したものです。
にもかかわらず数字が食い違うのは、収集の問題ではなく処理の問題です。レポートは問い合わせた時点で計算し、エクスポートは書き出す時点で確定した値をイベント1件ずつに焼き付けます。処理する仕組みが別なので、同じ入力から別の出力が出ます。
運用メモ:媒体管理画面とGA4の乖離は「別の計測システムだから」で説明できますが、レポートとBigQueryの乖離はそうではありません。同じデータから出発しているぶん、原因は定義の中にあります。
参照元は3つある
BigQueryエクスポートのイベント行には、トラフィックソースに関する項目が3つ入っています。名前が似ていますが、指しているものが違います。
スコープが違うということは、そのまま入れ替えられないということです。レポート側にもスコープ別のディメンションがあるので、対応関係を押さえておくと迷いません。
| BigQueryの項目 | スコープ | 値の決め方 | レポート側の対応物 |
|---|---|---|---|
collected_traffic_source | イベント | そのイベントが持ってきた情報のみ | 対応するディメンションなし |
session_traffic_source_last_click | セッション | 直近のクリックまでさかのぼる | 完全に対応するものはない |
traffic_source | ユーザー | 最初に獲得した参照元 | ユーザーの最初の参照元 |
注意したいのが真ん中の行です。セッションスコープどうしなのに、レポートの「セッションの参照元」と完全には対応しません。 粒度は同じでも、値の決め方が別だからです。
collected_traffic_source の性質も押さえておくと理解が早まります。この項目は、そのイベントが持ってきた情報だけを入れます。URLのUTMパラメータ、広告のクリックID、遷移元のドメイン。持っていなければ空のままで、前のイベントから引き継ぐこともしません。サイト内を移動して発生したイベントには、原則として何も入りません。
定義文がそもそも違う
なぜセッションスコープどうしで食い違うのか。答えは公式ドキュメントの定義文にあります。並べてみると、規則が別物であることがそのまま書かれています。
BigQuery Export スキーマは session_traffic_source_last_click をこう説明しています。
Google 広告と手動コンテキスト全体のラストクリックが関連付けられているセッションのトラフィック ソース データ
いっぽう Data API のディメンション定義では、セッションの参照元はこうです。
ウェブサイトまたはアプリでセッションを開始した参照元
片方は「直近のクリックを探しにいく」と書いてあり、もう片方は「そのセッションが始まったときの値」だと書いてあります。同じものを指す名前に見えて、別の規則です。
1件のコンバージョンがどう記録されるか
図にすると、どこで分岐しているかがはっきりします。
ここで見落としやすいのが、セッションの区切り方は食い違っていないという点です。後日の訪問を別セッションとして数えるのは、どちらの出力でも同じです。分かれるのは、その新しいセッションに何を貼るかだけです。
逆方向のズレもある
BigQueryのほうが広く拾うのだから、常にBigQueryのコンバージョン数が多くなる、とは限りません。逆方向のズレもあります。
BigQueryエクスポートは端末単位です。 ユーザーIDによる統合はレポート側の機能で、エクスポートには反映されません。つまり、スマートフォンで広告をクリックしてパソコンで購入した場合、パソコン側のデータには広告の痕跡がありません。レポートは統合して拾えますが、BigQueryでは追えません。
もうひとつ、ラストクリックの性質による取りこぼしもあります。「直近の非ダイレクト」なので、広告をクリックしたあとに自然検索から訪れると、自然検索のほうが上書きします。 レポート側が別の規則で広告に紐づけていれば、そこでも差が出ます。
| ズレの向き | 主な原因 | どちらが拾えるか |
|---|---|---|
| BigQueryのほうが広告が多い | 時間をあけた直接再訪を、直近のクリックに紐づける | BigQueryが拾い、レポートは拾わない |
| レポートのほうが広告が多い | 端末をまたぐ導線をユーザーIDで統合する | レポートが拾い、BigQueryは拾えない |
| レポートのほうが広告が多い | 広告クリック後の自然検索がラストクリックを上書き | 規則の違いによる |
どちらの出力にも死角があります。 どちらが大きいかはサイトの性質次第で、検討期間が長い商材では時間方向のズレが、複数端末での比較検討が多い商材では端末方向のズレが大きくなります。
自分のプロパティで測る手順
一般論では判断できないので、実際に測ります。コンバージョン単位で突き合わせるのが最も確実です。トランザクションIDのような一意のキーがあれば、1件ずつ照合できます。
手順1: Data APIでレポート側の値を取る
トランザクションIDとセッションの参照元・メディアを軸にレポートを取得します。
{
"dateRanges": [{ "startDate": "2026-07-01", "endDate": "2026-07-31" }],
"dimensions": [
{ "name": "transactionId" },
{ "name": "sessionSource" },
{ "name": "sessionMedium" },
{ "name": "sessionCampaignName" }
],
"metrics": [{ "name": "transactions" }],
"limit": 100000
}
行数が多い場合は offset を進めて全件取得します。トランザクションIDのようにカーディナリティが高いディメンションは (other) にまとめられることがあるため、返ってきた行数と rowCount を必ず突き合わせてください。
手順2: BigQueryで同じ期間を取る
エクスポート側は、購入イベントに貼られているセッションスコープの値を読みます。
SELECT
ecommerce.transaction_id AS tid,
LOWER(IFNULL(session_traffic_source_last_click.cross_channel_campaign.source, '(direct)')) AS src,
LOWER(IFNULL(session_traffic_source_last_click.cross_channel_campaign.medium, '(none)')) AS med,
session_traffic_source_last_click.cross_channel_campaign.campaign_name AS campaign
FROM `<project>.<dataset>.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260701' AND '20260731'
AND event_name = 'purchase'
AND ecommerce.transaction_id IS NOT NULL
同じトランザクションIDが複数行返る場合は、最初の購入イベントに絞ります。
手順3: 突き合わせて一致率を出す
トランザクションIDをキーに結合し、参照元とメディアが一致した割合を数えます。あわせて、「広告経由と判定した件数」がそれぞれいくつになるかも出しておくと、判断に直結します。
手順4: ズレた行の原因を切り分ける
一致しなかった行について、次の2つを確認すると原因が分かれます。
ひとつめは、同じ端末の過去に広告クリックがあるかです。購入セッションより前のセッションに collected_traffic_source.gclid が入っていれば、時間方向のズレです。そのセッションのキャンペーン名と、購入セッションに貼られているキャンペーン名が一致すれば、引き継ぎが起きていることまで確認できます。
WITH pur AS (
SELECT
ecommerce.transaction_id AS tid,
user_pseudo_id,
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS sid,
event_timestamp AS ts,
session_traffic_source_last_click.cross_channel_campaign.campaign_name AS camp_now
FROM `<project>.<dataset>.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260701' AND '20260731'
AND event_name = 'purchase'
),
clicks AS (
SELECT
user_pseudo_id,
event_timestamp AS ts,
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS sid,
session_traffic_source_last_click.cross_channel_campaign.campaign_name AS camp_click
FROM `<project>.<dataset>.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260601' AND '20260731'
AND collected_traffic_source.gclid IS NOT NULL
)
SELECT
COUNT(*) AS n,
COUNTIF(camp_now = camp_click) AS same_campaign
FROM (
SELECT
p.camp_now,
c.camp_click,
ROW_NUMBER() OVER (PARTITION BY p.tid ORDER BY c.ts DESC) AS rn
FROM pur p
JOIN clicks c
ON c.user_pseudo_id = p.user_pseudo_id
AND c.ts <= p.ts
AND c.sid <> p.sid
)
WHERE rn = 1
ふたつめは、同じユーザーIDの別端末に広告クリックがあるかです。user_id が一致して user_pseudo_id が違う行にクリックがあれば、端末方向のズレです。
運用メモ:
traffic_sourceに替えれば近づくのではないか、と考えたくなりますが逆効果です。これはユーザーを最初に獲得した参照元で、レポート側の対応物はセッションの参照元ではありません。別の概念どうしを比べることになり、乖離はかえって広がります。
どちらを使うか
測ったうえで、目的に応じて選びます。近似を作ろうとしないのが要点です。
| 目的 | 向いている出力 | 理由 |
|---|---|---|
| 実績の共有・定点報告 | Data API | 誰が管理画面を開いても同じ数字が出る。説明の手間がかからない |
| 予算配分・注力度の判断 | BigQueryエクスポート | 直接流入や分類不能に埋もれる分が減り、規則を説明できる |
| 長期の遡及分析 | BigQueryエクスポート | レポートはデータ保持期間の制約を受けるが、エクスポートは残る |
| クロスデバイスの評価 | Data API | ユーザーIDによる統合はエクスポートに反映されない |
ひとつ補足すると、チャネル同士の比較なら、どちらを使っても結論は大きく変わりません。 時間方向の引き継ぎは広告だけでなく自然検索にも同じように効くためです。基準を変えて動くのは、各チャネルの絶対量と、「どこから来たか分からない」に残る量です。
分かっていないこと
最後に、公開情報からは確認できない点を明記しておきます。
「直接来訪のとき、レポート側が前回の参照元を引き継ぐかどうか」を明記した公式資料は見つかりません。 公開されているのは「セッションを開始した参照元」という一文だけです。日本語の解説記事には「ノーリファラー訪問では過去の参照元が引き継がれる」と説明しているものもありますが、それはコンバージョンのアトリビューションや、session_traffic_source_last_click が追加される前の状況を指している場合があります。
また、「session_traffic_source_last_click を使えばレポートと揃う」という記述も見かけますが、揃うかどうかはプロパティの性質に左右されます。 一致率は自分のデータで測ってください。この記事の手順は、そのために書いています。
関連記事
この記事をシェア
ryottaman
広告代理店で17年、現在は事業会社でインハウスマーケティングを担当しています。
SIGNALZの記事はAIを活用して作成し、10年以上の運用型広告の実務経験をもとに内容を確認・監修しています。制作方針の詳細はサイトについてをご覧ください。
Google検索の優先ソースにSIGNALZを追加
追加すると、Google検索のトップニュースでSIGNALZの記事が見つけやすくなります。AIモードとAIによる概要でも「優先」バッジが付きます。設定はいつでも解除できます。