
Contents
導入(このSQLで解決できる課題)
Webサイトの改善において「ユーザーがどのページから訪問を開始し、その後どれくらいページを見ているか」を把握することは非常に重要です。
特にLP(ランディングページ)は、最初の印象でユーザーの滞在時間や深掘り行動を左右するため、広告効果測定やSEO施策の改善にも直結します。
しかし、GA4の標準レポートでは「ランディングページごとの平均閲覧ページ数」を柔軟に抽出することは難しく、カスタム探索を作り込んでも制限が多いのが現実です。
そこで今回紹介するSQLでは、GA4の生データを用いて「ランディングページごとのセッション数」と「その後に平均何ページ閲覧されたか」を算出できます。
これにより次のような課題を解決できます。
どのLPが深いセッションを生み出しているか比較できる
離脱しやすいランディングを特定できる
広告LPの改善優先度を明確化できる
特に広告投資を行う場面では「流入の量」だけでなく「質(深掘り行動)」を可視化できる点が強みです。
2. 実行結果イメージ
読み方:
sessions_count…そのランディングから始まったセッション数
avg_pages_viewed_before_exit…ランディングから同一セッション内で閲覧されたページ数の平均(高いほど深く回遊)
3. 背景・利用シーン
このSQLは以下のような実務シーンで役立ちます。
広告LPの改善効果測定
「広告で流入したユーザーが、どのくらいサイトを深く見たか」を定量化し、媒体別やクリエイティブ別の比較に活用できる。SEO記事の質の評価
流入の多い記事が「他ページ閲覧につながっているか」を把握でき、ナビゲーションや内部リンクの改善余地を見つけやすい。直帰率の補完指標
直帰率だけでなく「何ページ見たか」を把握することで、単ページ完結型コンテンツか、回遊導線が不足しているのかを切り分け可能。コンテンツ戦略の優先順位づけ
回遊性の高いランディングを強化し、弱いランディングは改善施策の対象にできる。
抽出結果からできる議論(会話例)
マーケ担当A: 「この記事から入った人は3ページ以上見てますね。」
分析担当B: 「内部リンクが機能している証拠です。関連記事をもっと増やしましょう。」
分析担当B: 「TOPページはセッション数は多いけど、平均1.4ページで浅いですね。」
マーケ担当A: 「初回体験が弱い証拠です。ファーストビューを改善すべきかも。」
マーケ担当A: 「広告LPは平均2.8ページでした。」
分析担当B: 「最低限の効果は出てますが、フォーム導線をもっと強調したほうが良さそうです。」
分析担当B: 「商品ページ直着だと平均1.9ページ止まりですね。」
マーケ担当A: 「スペック比較ページへの導線を増やせば、回遊が伸びるかもしれません。」
マーケ担当A: 「記事からの流入は数は少ないけど、滞在が深い。」
分析担当B: 「ナーチャリングに効いてます。SEO記事をもっと投資対象にすべきですね。」
4. SQLコード(コメント付き分解)
-- ▼ テーブルはあなたの環境に置換してください:`PROJECT.DATASET.events_*`
WITH session_data AS (
SELECT
user_pseudo_id,
-- セッションID(user_pseudo_id + ga_session_id)
CONCAT(
CAST(user_pseudo_id AS STRING), "_",
CAST((SELECT ep.value.int_value
FROM UNNEST(event_params) ep
WHERE ep.key = 'ga_session_id') AS STRING)
) AS session_id,
-- 完全URL(必要に応じてパス化・正規化は「注意点」を参照)
(SELECT ep.value.string_value
FROM UNNEST(event_params) ep
WHERE ep.key = 'page_location') AS page_location,
event_timestamp,
-- セッション内の page_view 順(最初=1)
ROW_NUMBER() OVER (
PARTITION BY user_pseudo_id,
CONCAT(
CAST(user_pseudo_id AS STRING), "_",
CAST((SELECT ep.value.int_value
FROM UNNEST(event_params) ep
WHERE ep.key = 'ga_session_id') AS STRING)
)
ORDER BY event_timestamp
) AS page_view_rank
FROM
`PROJECT.DATASET.events_*`
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_ADD(CURRENT_DATE(), INTERVAL -300 DAY))
AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())
AND event_name = 'page_view'
),
-- ★ セッションの「最初の」page_view をランディングとして1行に固定
landing_pages AS (
SELECT
user_pseudo_id,
session_id,
page_location AS landing_page,
event_timestamp AS landing_timestamp
FROM session_data
QUALIFY page_view_rank = 1
),
-- ランディング時刻以降のそのセッション内 page_view をカウント
page_views AS (
SELECT
sd.user_pseudo_id,
sd.session_id,
lp.landing_page,
COUNT(*) AS pages_viewed_before_exit
FROM session_data sd
JOIN landing_pages lp
ON sd.user_pseudo_id = lp.user_pseudo_id
AND sd.session_id = lp.session_id
AND sd.event_timestamp >= lp.landing_timestamp
GROUP BY
sd.user_pseudo_id, sd.session_id, lp.landing_page
)
-- ランディング単位に集計
SELECT
pv.landing_page,
COUNT(*) AS sessions_count,
AVG(pv.pages_viewed_before_exit) AS avg_pages_viewed_before_exit
FROM page_views pv
GROUP BY pv.landing_page
ORDER BY sessions_count DESC;
各パートの役割
session_data
:セッション内のpage_viewに連番を付与landing_pages
:QUALIFY page_view_rank=1
でランディングを一意に取得page_views
:ランディング時刻以降の閲覧数をセッション単位でカウント最終SELECT:ランディングURLごとにセッション数と平均閲覧ページ数を算出
確認すべきポイント
URLの正規化
現状はフルURLをそのまま使用。REGEXP_REPLACE
でドメイン除去し、パス単位で集計するのがおすすめ。期間の調整
_TABLE_SUFFIX
で「直近300日」を指定しているが、分析目的に応じて変更可能。単ページ完結コンテンツの解釈
平均ページ数が低い=悪いとは限らない。単ページで完結するLPやブログ記事も存在する。広告流入との組み合わせ
traffic_source.medium
やcampaign
をJOINすると、媒体別に深さ比較が可能。
6. まとめ(SQLの効果と使いどころ)
このSQLは、ランディングページ別に「セッション数」と「平均ページ閲覧数」を明確に示すことができます。
LP改善の優先度づけ
SEO記事の評価
離脱要因の特定
といった実務に直結する分析が可能になり、単なる「直帰率」よりも実態に即した改善施策を導き出せます。