· ハルボウヤ · analytics · 10 min read

GA4移行後にCVが計上されなくなるGTMタグの直し方

タグは発火しているのにコンバージョンが記録されない。UA時代に書かれたカスタムHTMLタグが静かに失敗する仕組みと、その直し方を整理する。

purchaseイベントの通過を確認している様子のイラスト。カートのアイコンとチェックマークが並んでいる

外部の計測ツールに送っているコンバージョンが、ある時期からゼロになっていた。GTM のプレビューで見るとタグは「発火」と表示される。エラーも出ていない。それでも件数は増えない。

原因は、UA(ユニバーサルアナリティクス)時代に書かれたカスタム HTML タグが、GA4 移行後に前提を失っていたこと。同じ構造のタグは多くのサイトに残っているため、症状と直し方を整理しておく。

なお、以下のコードは実際の実装をもとに、URL・識別子・ベンダー名を伏せた形に書き換えている。

問題のあるタグの形

<script src="(計測ベンダーが配布するSDKのURL)"></script>
<script>
  var cvParams = {};

  function sendConversion() {
    try {
      cvParams['order_id'] = tmp_actionFields['id'];

      if (customerId != null && customerId.length > 0) {
        cvParams['user_id'] = customerId;
      }
      if (visitorId != null && visitorId.length > 0) {
        cvParams['session_id'] = visitorId;
      }

      var productInfo = '';
      for (var i = 0; i < tmp_products.length; i++) {
        var row = tmp_products[i];
        productInfo += (row['sku'] || row['id'] || '') + ':';
        productInfo += row['price'] + ':';
        productInfo += row['quantity'] + ',';
      }
      cvParams['product_info'] = productInfo.slice(0, -1);

      vendorAnalytics.cv.sendTrackingRequest('(テナントID)', cvParams);
    } catch (error) {
      console.log(error.name);
    }
  }

  if (typeof tmp_products !== 'undefined' && tmp_products != null) {
    if (typeof tmp_actionFields !== 'undefined' && tmp_actionFields != null) {
      sendConversion();
    }
  }
</script>

tmp_productstmp_actionFieldscustomerIdvisitorId は、ページ側が定義したグローバル変数。変数名はサイトによって異なるが、UA の拡張eコマース実装ではこの形がよく使われていた。

なぜ気づけないのか

このタグが厄介なのは、壊れても何も言わない点にある。理由が3つ重なっている。

1. 未定義チェックが「静かに何もしない」

最後の if で、グローバル変数が未定義なら関数を呼ばずに終わる。GA4 移行でページ側の dataLayer 設計が変わり、これらの変数が定義されなくなると、タグはエラーも出さず、送信もせずに終了する。

2. GTM のプレビューでは「発火」と表示される

GTM が判定しているのは、トリガー条件を満たしてタグが実行されたかどうか。タグの中で処理が握りつぶされていても、画面上は正常に見える。発火=成功ではない

3. エラーが console.log に出るだけ

catch の中が console.log(error.name) のみ。ブラウザのコンソールを開いている人がいなければ、誰も気づかない。しかも出るのは例外の名前だけで、原因の特定に使えない。

さらに、このタグは「タグの順序付け」で別の前処理タグに依存している。前処理タグ側の変更でも同じように静かに壊れる。

改善の方針

1. グローバル変数への直接参照をやめる

ページ側のグローバル変数を JavaScript から直に触る構造を、dataLayer と GTM 変数を経由する形に変える。

GTM の「変数」でデータレイヤー変数を定義する。

変数名の例データレイヤーのキー
DLV - transaction_idecommerce.transaction_id
DLV - itemsecommerce.items
DLV - user_iduser_id

カスタム HTML の中では {{DLV - transaction_id}} の形で参照する。こうすると、値が取れているかどうかを GTM のプレビュー画面で確認できるようになる。タグの中を読まなくても分かる状態にすることが目的。

2. GA4 の purchase イベントの構造に合わせる

GA4 の purchase では、商品は ecommerce.items の配列で渡される。キー名も UA 時代とは違う。

UA の拡張eコマースGA4
actionFields.idtransaction_id
products[].sku / iditems[].item_id
products[].priceitems[].price
products[].quantityitems[].quantity

移行後のコードはこうなる。

<script>
  (function () {
    var orderId = {{DLV - transaction_id}};
    var items = {{DLV - items}};

    if (!orderId || !items || !items.length) {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: 'measurement_error',
        error_tag: 'cv_tag',
        error_reason: !orderId ? 'missing_transaction_id' : 'missing_items',
      });
      return;
    }

    var productInfo = items
      .map(function (item) {
        return [item.item_id, item.price, item.quantity].join(':');
      })
      .join(',');

    vendorAnalytics.cv.sendTrackingRequest('(テナントID)', {
      order_id: orderId,
      user_id: {{DLV - user_id}},
      product_info: productInfo,
    });
  })();
</script>

3. 失敗を握りつぶさず、検知できる形にする

変更点は、値が揃わなかったときに measurement_error イベントを dataLayer に流すこと。

これだけで次のことができるようになる。

  • GTM のプレビューで、失敗したことがイベントとして見える
  • GA4 側でこのイベントをカスタムイベントとして受け、発生件数を監視できる
  • 「CVが0件」ではなく「CVタグが値を取れていない」という形で検知できる

console.log で終わらせない。気づける場所に出すことが要点。

4. 発火条件はトリガー側に寄せる

「変数が存在するか」の判定をタグ内の if に書くと、発火したのに何も起きない状態が生まれる。これをトリガーの条件に移す。

  • トリガー:カスタムイベント purchase
  • 条件:{{DLV - transaction_id}} が空でない

こうすると、値がないときはタグ自体が発火しない。GTM のプレビューで「発火しなかったタグ」として一覧に出るため、状態が正しく見える。

5. タグの順序付けへの依存を減らす

前処理タグでグローバル変数を組み立て、後続タグがそれを読む構成は、片方の変更で静かに壊れる。

サイト側で 1回の dataLayer.push に必要な値をすべて入れる形にできれば、順序付けは不要になる。実装側の改修が必要になるが、長期的にはこれが一番効く。

直したあとの検証手順

  1. GTM のプレビューモードで購入完了まで進む
  2. Variables タブで、定義した各変数に値が入っているか確認する
  3. Data Layer タブecommerce の中身を確認する
  4. ブラウザの開発者ツールの Network タブで、計測リクエストが実際に送信され、正常なステータスが返っているか確認する
  5. 計測ツール側の管理画面で件数を確認する
  6. GA4 の purchase 件数と突き合わせ、乖離がないか見る

5と6を飛ばすと、「タグは直ったが値が間違っている」状態を見逃す。

移行時のチェックリスト

UA 時代のカスタム HTML タグが残っている場合、次を確認する。

確認項目危ないサイン
ページ側のグローバル変数を直接参照していないかtmp_ などで始まる変数名が出てくる
未定義チェックで黙って終了していないかtypeof ... !== 'undefined' で囲んだだけの if
エラー処理が console.log で終わっていないかcatch の中が1行だけ
タグの順序付けに依存していないか「設定タグ」が指定されている
UA のキー名が残っていないかactionFieldsproductssku
送信件数を監視しているか誰も件数を見ていない

まとめ

  • 発火している=送信できている、ではない。GTM の表示だけで判断しない
  • UA 時代のグローバル変数依存は、GA4 移行で静かに壊れる
  • dataLayer と GTM 変数を経由させ、プレビュー画面で値が見える状態にする
  • 失敗したら measurement_error を流し、検知できる形にする
  • 条件はタグ内の if ではなくトリガーに寄せる
  • 直したあとは件数の突き合わせまでやる

計測は、壊れても誰も困らない時間が長く続いてから発覚する。壊れたことが分かる仕組みを一緒に入れておく。

Share:
Back to Blog

Related Posts

View All Posts »
AIを会社に導入していく手順

AIを会社に導入していく手順

ツールを配るだけでは定着しない。中小企業と大企業で何が違うのかを分けて、導入から定着までの手順を整理する。