Skip to main content

GA4 / i-cherry Web dataLayer

Ownership​

Record Web emits the client-approved analytics contract as plain objects in window.dataLayer and loads the client-owned Google Tag Manager container from NEXT_PUBLIC_GTM_ID. Record owns the container configuration that maps those objects to GA4/i-cherry. The application does not configure a GA4 measurement ID, call gtag() or send events directly to a GA4 property.

The contract combines Web v09 with the 2026-08-04 Accedo-layout revision ([R7+iC] Mapa de Tags GA4 - RecordPlus - Web-v1.pdf, SHA-256 30165e59acf11a720e2a7343d644046e572d3548189556665f57be4392042825).

Event shape​

Emitters call trackMarketingEvent / trackMarketingEcommerceEvent, which push the dataLayer objects below and send the same event to Permutive when it is configured (see Permutive).

Non-ecommerce events use a flat dataLayer object:

globalThis.dataLayer.push({ event: 'login', method: 'email' });

Ecommerce events clear stale ecommerce state and then use the documented nested shape:

globalThis.dataLayer.push({ ecommerce: null });
globalThis.dataLayer.push({
event: 'purchase',
ecommerce: {
currency: 'BRL',
value: 30.5,
transaction_id: '...',
items: [],
},
});

Authenticated identity is dataLayer state. userId is the ArcXP account UUID exposed by the authenticated session as user.id; email is never used for GA4 identity. plano is the active plan title and planoid is its ID. All three values are cleared on logout. client_id is generated by GA4 and is not sent as a custom field.

Personal data — sign-off required​

userId is a stable pseudonymous account identifier and remains personal data under the LGPD. Record confirmed the ArcXP UUID contract in ACS-5149. The application exposes it only after an Adult profile enables commercial measurement; pre-profile product measurement remains anonymous and Kids measurement remains blocked.

Before this ships to production, record here:

  • Legal basis / consent — which basis covers pushing userId to Record-owned GTM, and whether it must be gated on a consent signal rather than emitted for every authenticated session.
  • Retention — how long the GA4 property keeps user-scoped data.
  • Deletion path — how an LGPD erasure request reaches GA4, given the application only writes to dataLayer and does not own the property.

The application's runtime policy clears the identity fields whenever commercial measurement is unavailable or the authenticated session lacks an ArcXP UUID.

Status: unresolved — needs Record's DPO/legal confirmation.

Page views​

useGA4ScreenTracking(pathname) emits one explicit page_view for each route change. ga4ScreenPaths.ts maps the Next.js pathname to the canonical i-cherry page_title; page_location remains the real browser URL.

Payment information​

trackAddPaymentInfo implements the approved add_payment_info payload, including payment_type, but is intentionally not connected to the current Cleeng Hosted Widget. That API exposes checkout loaded and payment result events, not payment-method selection. Emitting it at payment success would put the event at the wrong funnel stage. Connect it only when the checkout provides a genuine pre-purchase payment-method callback.

Validation​

  1. Open browser DevTools and inspect window.dataLayer.
  2. Perform the mapped action and verify exactly one object with the expected event and parameters.
  3. For ecommerce, verify { ecommerce: null } immediately precedes the event.
  4. In GTM Preview, confirm the matching Record-owned tag fires once.
  5. In GA4 DebugView/Realtime, filter by the test build, device and timestamp and verify the event name and parameters. Do not use unrelated legacy-app traffic as evidence for this implementation.

The deployment workflow requires the public GitHub environment variable GTM_CONTAINER_ID. The application validates that it matches the GTM-* web container format and renders no GTM markup for invalid values. The client must publish a container version whose triggers and variables consume this documented dataLayer contract; loading the container alone does not validate that mapping.