GA4’s User ID feature lets you associate behavior across devices and sessions with a single authenticated user. When implemented correctly, User ID dramatically improves the accuracy of cross-device attribution, enables true user-level analysis in BigQuery, and makes your cohort and lifetime value reports meaningful. When implemented incorrectly, it creates duplicate users, inflates session counts, and corrupts your data. This guide covers the complete implementation, the common mistakes that cause data problems, and the BigQuery queries that let you verify your User ID data is working.
How GA4 User ID Works
When you set a User ID in GA4, the platform associates all subsequent events with that ID until the ID is cleared. If the same user logs in on a phone and a laptop, and you set the same User ID on both devices, GA4 links those sessions together in reporting. The User ID takes precedence over GA4’s device-based identifiers (client ID) for cross-device reconciliation in GA4’s reporting identity model.
GA4 supports three identity spaces: User ID (your authenticated identifier), Google signals (Google account-based cross-device), and device ID (client ID or app instance ID). When you enable User ID, GA4 uses it as the primary identifier for users who are logged in. For anonymous users, GA4 falls back to Google signals and then device ID.
The GTM Implementation
The most reliable way to implement User ID through GTM is to push it to the dataLayer immediately after authentication and then read it via a GTM variable into your GA4 Configuration tag. First, have your application push the user ID to the dataLayer when a user logs in:
// Push User ID to dataLayer after login
dataLayer.push({
event: 'user_logged_in',
user_id: 'hashed_or_internal_user_id_here',
user_properties: {
membership_tier: 'premium',
account_age_days: 365
}
});
In GTM, create a Data Layer Variable with the variable name user_id. Then in your GA4 Configuration tag, add a field named user_id with the value set to your new {{user_id}} variable. The GA4 Configuration tag must fire AFTER the user_logged_in event pushes to the dataLayer. Use a Custom Event trigger on user_logged_in to re-fire the GA4 Configuration tag with the user_id field populated.
What User ID Must Not Be
GA4’s terms of service prohibit sending personally identifiable information (PII) as a User ID or any other parameter. This means you cannot use email addresses, names, phone numbers, or any value that could directly identify a person. Use hashed or pseudonymous identifiers only: your internal database user ID, a UUID assigned at registration, or a hashed version of the email address (SHA-256 without salt is common, though adding a salt is better for privacy).
Hashing in the browser before sending to GTM:
async function hashUserId(email) {
const msgBuffer = new TextEncoder().encode(email.toLowerCase().trim());
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// On login success:
const hashedId = await hashUserId(user.email);
dataLayer.push({ event: 'user_logged_in', user_id: hashedId });

Persisting User ID Across Sessions
The most common User ID implementation mistake is only setting the User ID on the login page. A user who logged in during a previous visit and returns in a new session will have their session attributed to an anonymous user because the user_id was never pushed to the dataLayer on the new session’s page load. The correct implementation pushes the User ID to the dataLayer on every page load for authenticated users, not just on the login event.
If your application uses server-side rendering or stores session state, include the user ID in the initial dataLayer push in the page template. For SPAs, push the user ID on application initialization if the user is already authenticated. A simple pattern is to store the hashed user ID in a first-party cookie after login and read that cookie value into the dataLayer on every page load for authenticated users.
Verifying User ID in BigQuery
-- Check User ID coverage rate
SELECT
DATE(TIMESTAMP_MICROS(event_timestamp)) AS date,
COUNTIF(user_id IS NOT NULL AND user_id != '') AS sessions_with_user_id,
COUNTIF(user_id IS NULL OR user_id = '') AS sessions_without_user_id,
ROUND(COUNTIF(user_id IS NOT NULL AND user_id != '') / COUNT(*) * 100, 1) AS user_id_coverage_pct
FROM `your_project.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'
AND event_name = 'session_start'
GROUP BY date
ORDER BY date
This query shows what percentage of sessions have a User ID set. For a site where most users are anonymous, 10-20% User ID coverage might be expected. For a logged-in-only application, you should see coverage approaching 100%. Significant drops in coverage indicate a deployment broke the User ID implementation on certain pages or authentication flows.
Cross-Device Analysis in BigQuery
-- Find users who used multiple devices
SELECT
user_id,
COUNT(DISTINCT device.category) AS device_types_used,
COUNT(DISTINCT user_pseudo_id) AS client_ids,
ARRAY_AGG(DISTINCT device.category) AS devices
FROM `your_project.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'
AND user_id IS NOT NULL AND user_id != ''
GROUP BY user_id
HAVING COUNT(DISTINCT device.category) > 1
ORDER BY device_types_used DESC
LIMIT 100
This query identifies users who accessed your site from multiple device types. The ratio of users with multiple device types to total authenticated users gives you a measure of how much cross-device attribution User ID is enabling. If this number is very low relative to your expectations, investigate whether the User ID is being set consistently across your mobile and desktop experiences.
