PAYATHON 2026

Google Analytics Enhanced Ecommerce checkout payload 过大

支付小周

结论

analytics.js 不会自动拆分超过 8192 bytes 的 hit。每次调用 ga('send', ...) 时,hit 都必须在这一限制以内。

如果 purchase 包含大量商品,需要将商品分批,通过多个 Enhanced Ecommerce hit 发送:

  • 每一批都使用相同的 transaction ID。
  • 交易金额、税费、运费等 transaction-level 字段只在第一批发送。
  • 后续批次只发送 transaction ID 和本批商品,以免重复累计交易金额。
  • 不要根据固定的商品数量估算大小,应检查编码后的请求字节数或实际发出的采集请求。
  • 改用 POST、transport: 'beacon' 或 Measurement Protocol,也无法让单个 hit 超过 8192 bytes。

为什么会失败

调用 ga('ec:addProduct', ...) 时,商品不会立即发出,而是暂存在 tracker 的 Enhanced Ecommerce 数据模型中。执行下面的代码后:

ga('send', 'pageview');

商品、purchase action 和 pageview 参数才会合并为一个 hit。

也就是说,100 个商品不会产生 100 个请求,而会组成一个带有 pr1...pr100 等参数的大请求。如果编码后的 payload 超过 8192 bytes,analytics.js 就会拒绝发送。商品名称、SKU、分类、优惠券和 product-scoped custom dimensions 都会占用请求空间。

推荐发送方式

先发送普通 pageview,再通过非互动事件分批发送 purchase 数据。每次 send 完成后,再添加下一批商品和 action:

ga('require', 'ec');

ga('send', 'pageview');

function sendPurchaseInBatches(products, transaction, batchSize = 20) {
  const batches = [];

  for (let i = 0; i < products.length; i += batchSize) {
    batches.push(products.slice(i, i + batchSize));
  }

  function sendBatch(index) {
    if (index >= batches.length) {
      return;
    }

    batches[index].forEach(product => {
      ga('ec:addProduct', {
        id: product.id,
        name: product.name,
        category: product.category,
        brand: product.brand,
        variant: product.variant,
        price: product.price,
        quantity: product.quantity,
        coupon: product.coupon
      });
    });

    if (index === 0) {
      // 交易级字段只发送一次。
      ga('ec:setAction', 'purchase', {
        id: transaction.id,
        affiliation: transaction.affiliation,
        revenue: transaction.revenue,
        tax: transaction.tax,
        shipping: transaction.shipping,
        coupon: transaction.coupon
      });
    } else {
      // 后续批次仍需标明这些商品属于同一 purchase。
      ga('ec:setAction', 'purchase', {
        id: transaction.id
      });
    }

    ga('send', 'event', {
      eventCategory: 'Ecommerce',
      eventAction: index === 0
        ? 'Purchase'
        : 'Purchase Product Batch',
      eventLabel: transaction.id,
      nonInteraction: true,
      transport: 'beacon',
      hitCallback: function () {
        sendBatch(index + 1);
      }
    });
  }

  sendBatch(0);
}

这里的 batchSize = 20 只是示例,并不是对所有情况都安全的数值。商品字段较长时,20 个商品仍可能超出限制;字段较短时,每批可以容纳更多商品。

大小控制

是否需要拆分,应以最终编码后的 hit 大小为准,不能只看商品数量。可以在浏览器的 Network 面板中检查发往以下端点的请求:

https://www.google-analytics.com/collect

需要计算 URL 编码后的查询字符串或 POST body 所占的 UTF-8 字节数。中文、特殊字符和 product-scoped custom dimensions 编码后可能占用多个字节,因此 JavaScript 字符串的 length 无法准确表示请求大小。

生产环境中应留出余量,让每个 hit 明显低于 8192 bytes。tracker 配置、campaign 参数和自定义维度也会写入 payload,占用一部分空间。

还可以删除不影响报表的字段,尤其是内容过长的字段,例如:

  • name
  • category
  • variant
  • coupon
  • product-scoped custom dimensions

但不要为了缩短请求而截断商品 ID、transaction ID,以及其他用于关联或去重的字段。

注意事项

把同一个 purchase 拆成多个 hit 后,需要在实际使用的 Universal Analytics property 中检查 Transactions、Revenue、Quantity 和 Product Revenue 等指标。如果每个批次都重复发送 revenue、tax、shipping 等字段,交易级金额很容易被重复累计。

所有批次还需要在页面卸载前发出。通过 hitCallback 串行发送,可以减少一次性排队带来的风险,但回调无法保证请求一定送达。如果结账完成后页面会立即跳转,可以推迟跳转,也可以让服务端通过 Measurement Protocol 分批发送。服务端发送仍须保证每个 hit 不超过 8192 bytes,并为各批次保留相同的 transaction ID 和 client ID。

如果系统已经迁移到 GA4,不要直接套用这套 analytics.js 写法。GA4 使用不同的事件模型、参数名称和限制,需要改用 GA4 的 purchase 事件方案。

备注:内容仅供参考。