Blog

Server-side hit overrides for GA4: client_id, session_id, user_id

Three identifiers that GA4 uses to stitch sessions together. Overriding them server-side fixes problems that the browser cannot.

GA4 uses three identifiers to attribute events to users: client_id (cookie-based, browser-scoped), session_id (per-session, derived from client_id), and user_id (your own cross-device identifier). All three can be overridden server-side, and each override solves a specific class of problem.

client_id

Default: GA4 cookie value, generated client-side. Server-side override: read from a first-party HttpOnly cookie set by your tagging server. The override means client_id survives ITP-driven cookie deletion (the GA4 cookie is JavaScript-set and gets deleted; the HttpOnly one does not).

// In your GA4 tag, override client_id
const persistent = getCookieValues('_user_id')[0];
return persistent || getEventData('client_id');

session_id

Default: GA4 generates this from the cookie, with a 30-minute inactivity timeout. Server-side override: useful if you need to enforce different session boundaries (for example, a session-per-checkout-attempt for ecommerce reporting).

Less commonly overridden than client_id. The defaults work for most use cases, and changing them affects how GA4 reports sessions in unexpected ways.

user_id

Default: not set (you have to provide it explicitly). Server-side override: pull from your authentication system once the user is logged in. Without user_id, GA4 cannot stitch a single user across devices, even if other signals (email hash) are present.

// In your GA4 tag, set user_id
const sessionUserId = getCookieValues('_auth_user_id')[0];
if (sessionUserId) return sessionUserId;
return undefined; // unset for unauthenticated users

When to override which

ProblemOverride
Users appear as new on every visitclient_id from HttpOnly cookie
Cross-device journeys brokenuser_id from auth system
Sessions splitting too aggressivelysession_id (rare, careful)
First-time visit needs to be remembered after consentclient_id propagation from before consent

A note on userless tracking

If your privacy posture is "no cross-device identity," do not set user_id. The two cookie-derived IDs are session/device-scoped and do not survive across devices. user_id is what crosses the boundary; leaving it unset keeps your tracking strictly per-device.