はじめに:メルマガが売上に効いたのか分からない
中小ECを運営していると、メルマガ(メールマガジン)はほぼ必ず手元にある集客手段です。新商品の案内、セールの告知、再入荷のお知らせと、配信のネタは尽きません。配信ツールの管理画面を開けば、開封率やクリック率もそれなりに見えます。
ところが、肝心の「で、メルマガから売上はいくら立ったのか」になると、急に分からなくなります。
- 配信ツールの数字は「開封した」「クリックした」までしか追えない
- クリックした人がその後に買ったのかどうかは、別のデータ(受注データ)を見ないと分からない
- 「いつも買ってくれる常連さん」と「久しぶりに反応してくれた人」を分けて見たいのに、混ざってしまう
開封率やクリック率は「メールの中での反応」です。けれど本当に知りたいのは「メールをきっかけに、最終的にどれだけ買われたか」のはずです。この二つは別の指標で、つなげるには配信ツールの外に出る必要があります。
この記事では、GA4とBigQueryを使って、メルマガのクリックから購入までを一本の線でつなぎ、さらに会員セグメント別に効果を測る方法を整理します。配信ツール単体では見えなかった「メルマガの本当の貢献」を、自分の手元の数字として持てるようになることがゴールです。
なお、計測の前提として、GA4のデータをBigQueryへエクスポートしている状態を想定しています。GA4の管理画面から無料でBigQueryへの連携を設定できますので、まだの方は先にそちらを済ませておいてください。
utm設計とGA4計測
メルマガの効果測定は、「メール内のリンクにどんな目印を付けるか」で半分以上が決まります。この目印が utm パラメータです。
utm パラメータは、リンクの末尾に付ける「どこから来たか」を示すタグです。GA4はこれを読み取って、流入を分類してくれます。メルマガで使う主な項目は次の三つです。
utm_source:流入元。メルマガならnewsletterなど固定の名前にするutm_medium:媒体の種類。メールならemailで統一するutm_campaign:配信の識別名。配信ごとに変える(例:20260730_summer_sale)
たとえばセール告知メールの商品リンクは、次のような形になります。
https://example.com/products/12345?utm_source=newsletter&utm_medium=email&utm_campaign=20260730_summer_sale
ここで一番大事なのは、表記を「毎回ブレさせないこと」です。あるときは email、あるときは mail、あるときは大文字の Email と混ざると、GA4の中で別物として集計され、後から合算するのが面倒になります。utm_source と utm_medium は固定値と決め、変えるのは utm_campaign だけにするのがおすすめです。
utm_campaign の名前付けにもルールを決めておくと、後で集計が楽になります。たとえば「日付+内容」のように 20260730_summer_sale という形にしておけば、SQLで日付や種類を切り出すこともできます。
GA4側では、これらの utm 付きリンクから流入したセッションが「参照元 / メディア」に newsletter / email として記録されます。GA4の管理画面(探索レポートなど)でも、ここまでは確認できます。ただし、GA4の標準レポートはセッション単位・集計済みの数字が中心で、「クリックした人がその後どの注文につながったか」を一件ずつ追うのは苦手です。そこでBigQueryの出番になります。
クリック→購入の追跡SQL
ここからは、BigQueryにエクスポートされたGA4のイベントデータを使って、メルマガ経由のクリックと購入を結びつけます。
GA4のBigQueryエクスポートでは、テーブル名が events_YYYYMMDD の形(日付ごとのテーブル)になります。* を使うと複数日をまとめて読めますが、その際は必ず _table_suffix で日付を絞り、スキャン量(=コスト)を抑えてください。
まずは、メルマガ経由のセッションを抽出してみます。ここで一つ注意が必要です。utm(source / medium / campaign)は、event_params の中に source や medium という key で入っていると思われがちですが、GA4のBigQueryエクスポートでは違います。これらはイベント単位の collected_traffic_source.manual_source / manual_medium / manual_campaign_name(流入時のトラフィックソース)に格納されます。event_params の key として取り出そうとしても値は取れません。
なお、GA4のBigQueryエクスポートのスキーマ(カラム構成)はGA4のバージョンによって異なる場合があります。実際に書く前に、最新の公式ドキュメントで
collected_traffic_source配下のフィールド名を確認してください。
そこで、collected_traffic_source.manual_* を使って抽出します。
SELECT
user_pseudo_id,
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS session_id,
collected_traffic_source.manual_campaign_name AS utm_campaign,
collected_traffic_source.manual_source AS utm_source,
collected_traffic_source.manual_medium AS utm_medium
FROM `your_project.analytics_123456789.events_*`
WHERE _table_suffix BETWEEN '20260730' AND '20260805'
このうち utm_source = 'newsletter' かつ utm_medium = 'email' のものが、メルマガ経由の流入です。
次に、そのセッションの中で発生した購入(purchase イベント)を結びつけます。GA4の購入イベントには、注文を識別する transaction_id と売上金額が入っているので、それを取り出して集計します。
注意:トラフィックソース(流入元)は本来「セッション単位」の概念です。
purchaseイベント自体を source で直接絞り込む(購入イベントに付いた流入元だけを見る)のは、設計として不正確になりがちです。購入イベントの流入元が、そのユーザーがメルマガから入ってきた事実を必ずしも反映しないためです。正しくは「まずセッション単位で流入元を判定し、そのセッションの中で起きた購入を数える」という順序で組み立てます。以下のSQLも、メルマガ経由と判定したセッションに購入を結合する形にしています。
WITH newsletter_sessions AS (
SELECT
user_pseudo_id,
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS session_id,
collected_traffic_source.manual_campaign_name AS utm_campaign
FROM `your_project.analytics_123456789.events_*`
WHERE _table_suffix BETWEEN '20260730' AND '20260805'
AND collected_traffic_source.manual_source = 'newsletter'
AND collected_traffic_source.manual_medium = 'email'
GROUP BY user_pseudo_id, session_id, utm_campaign
),
purchases AS (
SELECT
user_pseudo_id,
(SELECT value.int_value
FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS session_id,
ecommerce.transaction_id,
ecommerce.purchase_revenue AS revenue
FROM `your_project.analytics_123456789.events_*`
WHERE _table_suffix BETWEEN '20260730' AND '20260805'
AND event_name = 'purchase'
)
SELECT
s.utm_campaign,
COUNT(DISTINCT p.transaction_id) AS orders,
SUM(p.revenue) AS revenue
FROM newsletter_sessions AS s
JOIN purchases AS p
ON s.user_pseudo_id = p.user_pseudo_id
AND s.session_id = p.session_id
GROUP BY s.utm_campaign
ORDER BY revenue DESC
ポイントは、user_pseudo_id(ブラウザ単位の識別子)と session_id の二つを結合キーにしている点です。これで「メルマガをクリックして入ってきた、そのセッションの中で買われた注文」だけを集計できます。配信ツールでは見えなかった、配信(utm_campaign)ごとの注文件数と売上が、ここで初めて一つの表になります。
なお、メルマガをクリックした当日には買わず、数日後に別ルートで戻ってきて買う人もいます。それを含めて評価したい場合は、同一セッション内ではなく「クリックから○日以内の同一ユーザーの購入」という形に条件をゆるめる作り方もあります。ただし、どこまでをメルマガの貢献と見なすか(アトリビューションの考え方)は事前に決めておかないと、数字が膨らみやすい点に注意してください。GA4の受注データとの突合をさらに詳しくやりたい場合は、BigQueryでEC受注データ×GA4データを結合して正確な売上帰属分析をするもあわせてご覧ください。
会員セグメント別の効果測定
メルマガの効果は、「誰に届いたか」で大きく変わります。常連さんへの再入荷案内と、しばらく買っていない人へのカムバック案内では、反応も売上もまったく別物です。全体の合計だけ見ていると、この違いが平均にならされて見えなくなります。
セグメント別に測るには、GA4のデータに「会員の属性」を結びつける必要があります。会員ごとの属性は、自社の受注データやCRM(顧客管理)側にあるはずなので、それをBigQueryのテーブルとして用意し、結合します。
結合の鍵になるのが、GA4側に渡しておく会員ID(ユーザーID)です。GA4では user_id という形でログイン会員の識別子を送れます。これを送っておくと、user_pseudo_id(ブラウザ単位)よりも正確に、人単位でデータをつなげられます。
ここでは、会員ごとに「直近の購入回数の段階」を持ったセグメント表(your_project.crm.member_segment)があると仮定して、配信×セグメント別に売上を出してみます。
こちらも、購入イベントを source で直接絞るのではなく、メルマガ経由と判定したセッションに購入を結合する形にします。
WITH newsletter_sessions AS (
SELECT
user_id,
(SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
collected_traffic_source.manual_campaign_name AS utm_campaign
FROM `your_project.analytics_123456789.events_*`
WHERE _table_suffix BETWEEN '20260730' AND '20260805'
AND collected_traffic_source.manual_source = 'newsletter'
AND collected_traffic_source.manual_medium = 'email'
AND user_id IS NOT NULL
GROUP BY user_id, session_id, utm_campaign
),
purchases AS (
SELECT
user_id,
(SELECT value.int_value
FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
ecommerce.transaction_id,
ecommerce.purchase_revenue AS revenue
FROM `your_project.analytics_123456789.events_*`
WHERE _table_suffix BETWEEN '20260730' AND '20260805'
AND event_name = 'purchase'
),
newsletter_purchases AS (
SELECT
s.user_id,
s.utm_campaign,
p.transaction_id,
p.revenue
FROM newsletter_sessions AS s
JOIN purchases AS p
ON s.user_id = p.user_id
AND s.session_id = p.session_id
)
SELECT
m.segment,
np.utm_campaign,
COUNT(DISTINCT np.transaction_id) AS orders,
SUM(np.revenue) AS revenue,
SAFE_DIVIDE(SUM(np.revenue),
COUNT(DISTINCT np.transaction_id)) AS avg_order_value
FROM newsletter_purchases AS np
JOIN `your_project.crm.member_segment` AS m
ON np.user_id = m.user_id
GROUP BY m.segment, np.utm_campaign
ORDER BY revenue DESC
この表があると、たとえば「常連セグメントは件数は少ないが客単価が高い」「休眠セグメントは反応が薄いが、たまに大きく動く配信がある」といった違いが見えてきます。同じメールでも、誰に効いて誰に効かなかったのかが分かれば、次の配信の宛先や内容を変える判断ができます。
SAFE_DIVIDE を使っているのは、件数がゼロのときにエラーで止まらないようにするためです。セグメント別に切ると母数が小さくなる組み合わせも出てくるので、こうした安全策を入れておくと運用が楽になります。
セグメントの切り方は、最初は無理に細かくしなくて構いません。「常連・たまに買う・久しぶり」くらいの三分割から始めて、メルマガの反応に差が出るかをまず確かめるのが現実的です。
計測の注意:リダイレクトとアプリ内ブラウザ
最後に、メルマガ計測でつまずきやすい点を二つ挙げておきます。数字が思ったより少ないとき、たいていこのあたりが原因です。
一つ目はリダイレクトです。配信ツールによっては、クリック計測のためにメール内のリンクを一度ツール側のURLにくぐらせ、そこから本来のページへ転送します。この転送の過程で utm パラメータが落ちてしまうと、GA4には「メルマガ経由」として記録されません。リンクを設定したら、実際に自分でクリックして、最終的に着地したページのURLに utm が付いたまま残っているかを必ず確認してください。
二つ目はアプリ内ブラウザです。メールアプリやSNSアプリの中でリンクを開くと、通常のブラウザとは別の簡易ブラウザが立ち上がることがあります。この簡易ブラウザは、いったん閉じると同じ人と認識されにくく、後日あらためて買いに来たときに別ユーザーとして数えられがちです。結果として、メルマガで興味を持った人の購入が、メルマガの貢献から漏れて少なく見えることがあります。
これらは完全には避けられませんが、「メルマガ経由の数字はやや少なめに出る傾向がある」と理解しておくだけでも、判断を誤りにくくなります。数字を絶対値で鵜呑みにせず、配信どうしの比較(どの配信が相対的に効いたか)として読むのが安全です。同じく流入の質をチャネルごとに比べる考え方は、GA4×BigQueryでSNS流入の質を測定してInstagramとTikTokを比較したでも触れていますので、参考にしてみてください。
まとめ
メルマガの効果測定は、配信ツールの中だけでは「開封・クリック」までしか見えません。本当に知りたい「クリックから購入まで」をつなぐには、GA4とBigQueryで外に出る必要があります。
この記事の流れを振り返ると、次の四つが要点です。
- utm パラメータを「source と medium は固定、campaign は配信ごと」に決めて、ブレなく付ける
- BigQueryでメルマガ経由のセッションと購入を、ユーザーとセッションを鍵に結びつける
- 会員IDを使ってCRM側のセグメントと結合し、「誰に効いたか」を分けて見る
- リダイレクトとアプリ内ブラウザで数字が少なめに出る前提で、配信どうしの比較として読む
最初から完璧な計測を目指す必要はありません。まずは utm を統一して付け直すこと、そして一度BigQueryでクリックからpurchaseまでをつなぐSQLを動かしてみることから始めれば、メルマガの貢献が「感覚」から「自分の手元の数字」に変わっていきます。