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
userIdto 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
dataLayerand 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
- Open browser DevTools and inspect
window.dataLayer. - Perform the mapped action and verify exactly one object with the expected
eventand parameters. - For ecommerce, verify
{ ecommerce: null }immediately precedes the event. - In GTM Preview, confirm the matching Record-owned tag fires once.
- 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.