GTM(Googleタグマネージャー)で設置する — イベントIDによる重複排除

← コンバージョンAPI設定にもどる

広告タグ(ピクセル)とコンバージョンAPI(CAPI)で同じCVを送ると、そのままでは二重計上されます。Meta・TikTok・Yahoo!ディスプレイ/LINE は、両方に同じイベントIDを渡せば媒体側で1件に統合されます(重複排除の詳細)。

GTM を使うと、これを確実にできます。1つのタグの中でイベントIDを1回だけ発行し、その同じIDを広告タグとアプリの cvTrack() の両方に渡すという形です。IDの受け渡しをタグ間で手作業で合わせる必要がなくなります。

ヒント

考え方はシンプルです。「IDを作る」→「そのIDでピクセルを撃つ」→「同じIDでCAPIを撃つ」を1か所にまとめる。これだけで重複排除が成立します。

前提

  • アプリ側で受信キーの発行CVマッピングの登録が済んでいること。
  • 各媒体の広告タグ(Metaピクセル、TikTokピクセル等)がすでに GTM で動いていること。

手順1【GTM】配布タグを全ページで読み込む

プロジェクト概要の「コンバージョンAPI(CAPI)」→「タグをコピー」で取得した配布タグを、GTM の カスタムHTMLタグとして登録します。

  • トリガー: Initialization - All Pages(または All Pages)
  • これで全ページに cvTrack() / cvLineLink() が読み込まれ、クリックID(gclid など)もクッキーに保存されます。

注意

CVタグより先に読み込まれている必要があります。CVタグ側の「詳細設定 →タグの順序付け」で、「cvTrack が呼び出される前に配布タグを配信」に設定しておくと確実です。

手順2【GTM】イベントIDを発行する変数を作る(最重要)

イベントIDは、同じCVなら何度呼ばれても同じ値でなければいけません。ページをリロードするたびに違うIDになると、媒体側では別のCVとして数えられてしまいます。

そこで、注文番号などの業務IDから決定的に作るのが基本です。GTM の カスタムJavaScript変数(例: CV Event ID)として次を登録します。

function () {
  var eventName = {{DLV - cv_event_name}} || 'Purchase';
  var orderId = {{DLV - transaction_id}};   // dataLayer に積んだ注文番号

  // 業務ID(注文番号)があれば、それを使って決定的に作る(リロードしても同じ値)
  if (orderId) return eventName + '-' + orderId;

  // 業務IDが無いCV(問い合わせ・資料請求など): セッション内で同じ値を使い回す
  var key = '_cv_eid_' + eventName;
  try {
    var cached = sessionStorage.getItem(key);
    if (cached) return cached;
    var id = eventName + '-' + (
      (window.crypto && crypto.randomUUID)
        ? crypto.randomUUID()
        : Date.now() + '-' + Math.random().toString(36).slice(2)
    );
    sessionStorage.setItem(key, id);
    return id;
  } catch (e) {
    return eventName + '-' + Date.now();
  }
}

重要

Date.now() や乱数をそのままイベントIDにしてはいけません。完了ページをリロードするだけで別のCVとして計上されます。上のコードは、注文番号がある場合はそれを使い、無い場合でも sessionStorage にキャッシュして同じ値を返すようにしています。

CV名を接頭辞に付けているのは、同じ注文に対して種類の違うCV(InitiateCheckoutPurchase など)を送るときにIDが衝突しないようにするためです。

手順3【GTM】1つのタグでピクセルとCAPIを同じIDで発火する

カスタムHTMLタグを作り、手順2の変数を使って、広告タグとアプリの cvTrack()同じイベントIDで呼びます。

<script>
(function () {
  var eventId   = {{CV Event ID}};   // 手順2の変数(この1回だけ評価する)
  var eventName = 'Purchase';        // アプリ内CV名(CVマッピングと完全一致させる)
  var value     = {{DLV - value}};   // 金額(数値)
  var currency  = 'JPY';

  // ① Meta ピクセル(第4引数の eventID が重複排除キー)
  if (window.fbq) {
    fbq('track', eventName, { value: value, currency: currency }, { eventID: eventId });
  }

  // ② TikTok ピクセル(第3引数の event_id が重複排除キー)
  if (window.ttq) {
    ttq.track(eventName, { value: value, currency: currency }, { event_id: eventId });
  }

  // ③ アプリのコンバージョンAPI(①②と“同じ” eventId を渡すのが要点)
  if (window.cvTrack) {
    cvTrack(eventName, { value: value, currency: currency, eventId: eventId });
  }
})();
</script>
  • トリガー: 購入完了ページの表示(または dataLayer の purchase イベント)など、CVが確定した瞬間に1回だけ発火するもの。
  • eventName は、アプリのCVマッピングに登録したアプリ内CV名と大文字小文字まで完全一致させてください。
  • 媒体側のピクセルをGTMの公式テンプレート(Metaの「Facebookピクセル」テンプレート等)で運用している場合は、テンプレートの Event ID(イベントID)欄に {{CV Event ID}} を指定し、CAPI用のカスタムHTMLタグでは cvTrack() だけを呼ぶ形でも構いません。同じ変数を参照していれば同じ値になります。

媒体ごとの注意

媒体この方法で重複排除できるか
Metaできる。ピクセルの eventIDcvTrackeventId が一致すれば統合される
TikTokできる。ピクセルの event_id と一致させる
Yahoo!ディスプレイ/LINEできる。CAPIは eventIdtransaction_id として送るため、サイトタグ側で渡している注文IDと同じ値にする
Google Ads不要。CAPIは「インポート(クリック)」型の別のコンバージョンアクションに入るため、サイトタグのCVとは統合されず別カウントになる。入札最適化に使うのはどちらか一方にする
SmartNewsできない。APIにイベントID相当のフィールドが無い。ピクセルかCAPIのどちらか一方だけを発火させる(このタグから cvTrack は呼ぶがピクセルは呼ばない、など)

注意

SmartNews だけは、同じCVでピクセルとCAPIの両方を発火させると必ず二重計上されます。GTMのタグ内で、SmartNews のピクセル発火とCAPI送信のどちらを使うかを決めてください。

確認のしかた

  1. GTMのプレビュー(Tag Assistant) で、CVタグが1回だけ発火し、{{CV Event ID}} が期待どおりの値(例: Purchase-20260713-0001)になっていることを確認します。
  2. 完了ページをリロードして、イベントIDが変わらないことを確認します(変わる場合は手順2の設定を見直してください)。
  3. Meta イベントマネージャの「イベントの重複排除」で、ブラウザとサーバーのイベントが統合されている(重複警告が出ない)ことを確認します。
  4. アプリの「コンバージョン設定」→ 転送結果ログで、送信が成功していることを確認します。同じIDで再送された場合の DUPLICATE_ORDER_ID / CLICK_CONVERSION_ALREADY_EXISTS(Google)は「計上済み」を意味する正常な応答です。