はじめに:従来のサンキューページ計測の限界(チェックアウト改ざん不可問題)
「ShopifyでGA4の購入計測を入れたいのに、サンキューページにタグを貼れない」。こんな壁にぶつかった方は多いのではないでしょうか。
その背景には、Shopifyのチェックアウト(決済〜サンキューページ)の仕様変更があります。かつては checkout.liquid や注文ステータスページの「Additional scripts」に計測コードを直接書き込めましたが、Checkout Extensibilityへの移行に伴い、これらの方法は順次廃止されました。Shopify PlusでないストアではそもそもチェックアウトのHTMLを編集できず、決済ページに任意のスクリプトを差し込むこと自体ができません。
これは決済の安全性とパフォーマンスを守るための仕様であり、いわば「チェックアウト改ざん不可」の世界です。とはいえ計測担当者にとっては、もっとも重要な purchase イベントを取りこぼしかねない大問題です。
そこでShopifyが用意した正規の計測経路が「カスタムピクセル(Customer Events)」です。本記事では、カスタムピクセルからGTMを経由してGA4へeコマースイベントを高精度に送る実装の流れを、コード例つきで解説します。
本記事で扱うShopify管理画面のメニュー名やAPI仕様は変更されることがあります。実装時は必ず最新の公式ドキュメント(Shopify Help Center / GA4ヘルプ)で名称と仕様を確認してください。
Shopifyのカスタムピクセル(Customer Events)とは
カスタムピクセルは、Shopifyの「設定 → カスタマーイベント(Customer events)」から追加できる、独自のJavaScriptスニペットを安全に動かす仕組みです。
最大の特徴は、ストア本体のページとは隔離されたサンドボックス環境で動作する点です。具体的には、各ピクセルが独自のiframeやWeb Worker内で実行され、ストアのDOMやグローバル変数には直接アクセスできません。代わりに、Shopifyが提供する analytics オブジェクトを通じてイベントを購読します。
この仕組みのおかげで、チェックアウトのHTMLを触らなくても、購入完了(checkout_completed)を含む一連のイベントをコードで受け取れます。主なイベントは次のとおりです。
page_viewed… ページ表示product_viewed… 商品詳細の表示product_added_to_cart… カート追加checkout_started… チェックアウト開始checkout_completed… 購入完了(purchaseに対応)
サンドボックスである以上、ストア側で動いているGTMコンテナとはメモリ空間が別です。そのため「ピクセル内でイベントを受け取り、自前でGTM/GA4に送信する」という設計になります。ここが通常のサイト計測といちばん違うところです。
なお、カスタムピクセルには「アプリピクセル」と「カスタムピクセル」の2種類がありますが、自分のストアで手動でコードを書いて計測する場合は、管理画面から追加する後者を使います。また、ピクセルを公開する前に「お客様のプライバシー(Customer Privacy)」の同意設定を確認しておくと、地域の同意要件に沿った計測になります。同意管理(Consent)と組み合わせる場合は、analytics.subscribe の前段で同意状態を判定する設計にしておくと安全です。
GTM/GA4へeコマースイベントを高精度に送る実装の流れ
実装の全体像はシンプルです。
- カスタムピクセル内でShopifyのイベントを購読する
- 受け取ったデータをGA4のeコマース仕様に整形する
- ピクセル内に読み込んだGTMコンテナの
dataLayerへ push する - GTMのトリガー・タグでGA4へ送信する
手順1:カスタムピクセル内でGTMを読み込む
カスタムピクセルはサンドボックスなので、ストア本体に入れたGTMとは別に、ピクセル内でGTMスニペットを読み込みます。Shopifyの「カスタマーイベント」で新規ピクセルを作成し、次のように記述します。
// Customer events(カスタムピクセル)内
// GTMをピクセルのサンドボックスに読み込む
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
var f = d.getElementsByTagName(s)[0];
var j = d.createElement(s);
j.async = true;
j.src = "https://www.googletagmanager.com/gtm.js?id=" + i;
f.parentNode.insertBefore(j, f);
})(window, document, "script", "dataLayer", "GTM-XXXXXXX");
GTM-XXXXXXX は計測用に使うコンテナIDに置き換えてください。
手順2:購入完了イベントを購読してdataLayerへpush
続けて、checkout_completed を購読し、GA4の purchase 仕様に合わせて整形します。GA4では金額・通貨・items 配列がそろっていることが高精度計測の肝です。
analytics.subscribe("checkout_completed", (event) => {
const checkout = event.data.checkout;
const items = (checkout.lineItems || []).map((line) => ({
item_id: line.variant?.sku || line.variant?.id,
item_name: line.title,
quantity: line.quantity,
price: line.variant?.price?.amount,
}));
window.dataLayer.push({ ecommerce: null }); // 前回データのクリア
window.dataLayer.push({
event: "purchase",
ecommerce: {
transaction_id: checkout.order?.id || checkout.token,
value: checkout.totalPrice?.amount,
currency: checkout.currencyCode,
tax: checkout.totalTax?.amount,
shipping: checkout.shippingLine?.price?.amount,
items: items,
},
});
});
ポイントは2つです。1つ目は、transaction_id に注文IDまたは token を必ず入れること。これが重複排除の鍵になり、二重計上を防ぎます。2つ目は、push直前に ecommerce: null を入れて前回値を消すこと。GA4のeコマースは ecommerce オブジェクトを使い回すと前の商品が混ざるため、毎回リセットします。
商品閲覧やカート追加も計測したい場合は、同じ要領で product_viewed(→view_item)や product_added_to_cart(→add_to_cart)を購読します。たとえばカート追加は次のように書けます。
analytics.subscribe("product_added_to_cart", (event) => {
const item = event.data.cartLine?.merchandise;
if (!item) return;
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: "add_to_cart",
ecommerce: {
currency: event.data.cartLine?.cost?.totalAmount?.currencyCode,
value: event.data.cartLine?.cost?.totalAmount?.amount,
items: [
{
item_id: item.sku || item.id,
item_name: item.product?.title,
price: item.price?.amount,
quantity: event.data.cartLine?.quantity,
},
],
},
});
});
イベントごとに event.data の構造が少しずつ違うため、console.log(event) で実際のペイロードを確認してからマッピングすると、項目名のずれによる空値を防げます。
手順3:GTM側のトリガーとタグ
GTM管理画面では、次のように設定します。
- データレイヤー変数:
ecommerce.value、ecommerce.currency、ecommerce.transaction_id、ecommerce.itemsなどを変数化 - カスタムイベントトリガー:イベント名
purchaseで発火 - GA4イベントタグ:イベント名
purchase、「eコマースデータを送信」をオンにして「データレイヤー」を指定
「eコマースデータを送信」をオンにしておけば、GTMが dataLayer の ecommerce オブジェクトを自動でGA4の形式にマッピングしてくれるため、items を一つずつ手動マッピングする必要はありません。
手順4:金額を数値として扱う
地味に効くのが、金額の型をそろえることです。Shopifyのイベントから取れる金額は文字列のことがあり、そのままだとGA4側で合計されなかったり、文字列結合のように扱われたりします。push前に数値へ変換しておくと安全です。
const toNumber = (v) => (v == null ? undefined : Number(v));
// 例:value と各itemのpriceを数値化してからpushする
value: toNumber(checkout.totalPrice?.amount),
transaction_id は文字列のままで問題ありませんが、value・price・tax・shipping・quantity は数値で送るのが基本です。
検証(DebugView/プレビュー)
実装したら必ず検証します。実店舗の購入を伴うため、テスト注文の扱いには注意してください。
- GTMプレビュー(Tag Assistant):カスタムピクセルはサンドボックスのため、通常のプレビュー接続がそのままでは効きにくい場合があります。テスト購入を行い、GTMのプレビューモードでタグの発火と変数値(
valueやtransaction_id)を確認します。値が空でないか、通貨コードが正しいかを必ずチェックします。 - GA4 DebugView:GA4の「管理 → DebugView」で
purchaseイベントがリアルタイムに届くか確認します。value・currency・itemsがイベントパラメータとして入っているかを見ます。デバッグ対象として認識させるには、GTMのGA4タグにdebug_modeパラメータを一時的に付けるのが確実です。 - テスト注文の活用:Shopifyの「Bogus Gateway」やテスト用決済を使えば、実課金なしで
checkout_completedを発火できます。検証後はテスト注文を削除し、GA4側の数値からも除外しておきましょう。
items 配列が空、value が文字列で送られて集計されない、といったトラブルが起きやすいので、DebugViewで実データを目視するのがいちばん確実です。
注意:標準連携との二重計測を避ける
Shopifyには、GA4と公式連携する「Google & YouTube」アプリや、Shopify側のネイティブなGA4連携機能があります。これらを有効にしたまま、本記事のカスタムピクセル経由の purchase も送ると、1件の注文が2回カウントされるおそれがあります。
カスタムピクセルでpurchaseを自前送信するなら、Shopifyの標準GA4連携(Google & YouTubeアプリ等)側の購入計測は無効化し、計測経路を一本化してください。両方を生かす場合は、必ず
transaction_idを一致させて重複排除を効かせるか、別のGA4プロパティに分けて切り分けます。経路が二重のまま運用すると、売上が実態の2倍に膨らみ、ROASの判断を大きく誤ります。
どちらの経路を採用するかは、コントロールしたい範囲で決めます。商品ID・送料・税の整形を細かく制御したいならカスタムピクセル一本化、手間を抑えたいなら標準連携一本化が基本方針になります。
まとめ
Shopifyのチェックアウトに直接タグを貼れない、という制約は、裏を返せば「カスタムピクセルという正規ルートを使えばいい」というシンプルな話でもあります。
- サンキューページ計測の壁は、チェックアウトのHTMLを編集できない仕様によるもの
- カスタムピクセル(Customer Events)はサンドボックスで動き、
checkout_completedなどを購読できる - ピクセル内でGTMを読み込み、
purchase仕様に整形してdataLayerへpushする transaction_idとecommerce: nullリセットが高精度計測の要- DebugViewとGTMプレビューで実データを目視検証する
- 標準連携との二重計測だけは必ず避ける
仕様は今後も変わり得るので、実装の前後で最新の公式ドキュメントを確認する習慣をつけておくと安心です。
GA4のeコマース計測そのものの基礎から固めたい方は、GTMでGA4のeコマース計測を完全設定する手順【Shopify対応】もあわせてどうぞ。計測したのに数値がShopify管理画面と合わない、というときはShopifyとGA4のeコマースデータが合わない原因と対処法で原因を切り分けられます。