From 0dd1de2e4609a1692fa46ceb05d3c035b56fd45a Mon Sep 17 00:00:00 2001 From: Kevin Cantrell Date: Sat, 20 Jun 2026 21:19:19 +0900 Subject: [PATCH] fix(analytics): push the gtag `arguments` object, not a rest array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gtag.js only processes data-layer entries that are the live `arguments` object; a real array (rest params) is silently ignored, so page_view (and user_id) events queued but never sent — app.cropwatch.io showed no Realtime traffic. Push `arguments` like the canonical snippet. Verified in a headless browser: array-push = 0 collect hits, arguments-push = sends. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/analytics/gtag.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lib/analytics/gtag.ts b/src/lib/analytics/gtag.ts index 564d06ef..9a0cab1f 100644 --- a/src/lib/analytics/gtag.ts +++ b/src/lib/analytics/gtag.ts @@ -9,7 +9,7 @@ type GtagArgs = unknown[]; declare global { interface Window { - dataLayer?: GtagArgs[]; + dataLayer?: unknown[]; gtag?: (...args: GtagArgs) => void; } } @@ -35,10 +35,13 @@ export function initAnalytics(measurementId: string, options: { userId?: string document.head.appendChild(script); window.dataLayer = window.dataLayer ?? []; - // gtag forwards its raw argument list onto the data layer; gtag.js reads each - // entry by index/length, so pushing the rest array behaves like `arguments`. - window.gtag = function gtag(...args: GtagArgs) { - window.dataLayer!.push(args); + // gtag.js ONLY processes data-layer entries that are the live `arguments` + // object — a real array (e.g. from rest params) is silently ignored, so the + // events queue but never send. Push `arguments`, exactly like the canonical + // snippet. + window.gtag = function gtag() { + // eslint-disable-next-line prefer-rest-params + window.dataLayer!.push(arguments); }; window.gtag('js', new Date()); window.gtag('config', measurementId, {