Updated August 8, 2026: Since December 11, 2025, Google Tag Manager has offered built-in Analytics Client ID, Analytics Session ID, and Analytics Session Number variables. For a custom cookie prefix and more precise session selection, you can use the user-defined Analytics Storage variable. The old _ga cookie parser is therefore no longer recommended.
One-sentence recommendation: Use the built-in Analytics Client ID variable for the default Google Analytics cookie, use Analytics Storage for a custom prefix, verify consent status separately, and collect Client ID only for a specific use case. ID;
- private or incognito windows and regular windows may use different identifiers;
- deleting the cookie or allowing it to expire results in a new Client ID;
- storage restrictions, browser protections, and consent status can make the value unavailable;
- on the first page view, availability may depend on whether the Google tag has already created the cookie.
| Value | What it identifies | Typical use |
|---|---|---|
| Client ID | A pseudonymous browser instance | Linking web measurement to a server-side or offline event |
| User-ID | Your own ID for a signed-in account | Deduplicating users across devices according to User-ID rules |
| Session ID | A specific analytics session | Attributing a server-side event to the correct session |
User-ID must remain stable within your own sign-in identity system and must not contain PII, such as an email address or phone number. Google describes it as a custom identifier for a signed-in user that does not contain personally identifiable information in the documentation on implementing User-ID.
Client ID, User-ID, and Session ID are not interchangeable. Do not use any of these values as an authentication, authorization, or security token.
Which GTM variable should you choose?
| Situation | Recommended solution | Note |
|---|---|---|
I need Client ID from the default _ga cookie | Built-in Analytics Client ID variable | The simplest supported approach |
| I use a custom Google Analytics cookie prefix | User-defined Analytics Storage variable | Set the custom cookie prefix for Client ID |
| I need Session ID or Session Number for a specific GA4 destination | Analytics Storage with a Measurement ID | The Measurement ID selects one specific session value |
| I do not have a clearly defined downstream use case | No variable | Do not collect or pass on Client ID unnecessarily |
How to enable the built-in Analytics Client ID variable
- Open the web container in Google Tag Manager.
- Go to
Variables. - Under Built-In Variables, select
Configure. - In the Utilities section, enable
Analytics Client ID. - Open Preview mode and verify the value in Tag Assistant.
According to the documentation on built-in variables for web containers, Analytics Client ID provides the value from the default Google Analytics Client ID cookie. You no longer need a regular expression, manual removal of the GA1.2. prefix, or Custom JavaScript.
The variable does not create its own identifier or send an additional network request. When the cookie does not yet exist, is blocked, or the variable is evaluated before the Google tag creates the value, the downstream tag or code must safely handle the missing value.
Verify consent status separately. Do not infer whether the user has consented from the presence or absence of Client ID. The source of truth is the Consent Mode state or the state your CMP passes to the implementation.
Therefore, test the first visit in a clean browser profile, not only in your regular browser with an old cookie and previously granted consent.
Analytics Storage for a custom cookie prefix and a specific session
For advanced configurations, create a user-defined variable of the Analytics Storage type:
Variables > User-Defined Variables > New.- Select the
Analytics Storagetype. - Choose the
Client ID,Session ID, orSession Numberdata field. - Add a cookie prefix or Measurement ID as needed.
| Data field | Measurement ID | Cookie prefix | Behavior |
|---|---|---|---|
| Client ID | Not used | Optional | Lets you select Client ID from a custom cookie prefix |
| Session ID | Optional | Optional | With a Measurement ID, returns one session; without it, it may return a composite string from multiple relevant cookies |
| Session Number | Optional | Optional | With a Measurement ID, returns one value; without it, it may return multiple relevant values in a composite string |
If the website uses multiple GA4 streams or destinations, specify a Measurement ID for session values. Otherwise, do not take the first number you find without verification, because the result may contain multiple session values.
Beware of the similar name: the user-defined Analytics Storage variable in GTM is a reader for analytics identifiers. The analytics_storage consent type in Consent Mode determines whether the Google tag may use analytics storage. They are not the same thing.
How to safely remove the old _ga cookie parser
If you find this or a similar Custom JavaScript variable in your container, replace its use with the native value and remove it after testing:
function() {
return ('; ' + document.cookie).split('; _ga=')
.pop()
.split(';')
.shift()
.match(/GA1.[0-9]{1}.(.+)/)[1]
}Do not copy this code. It has several specific problems:
- when the
_gacookie does not exist,match()returnsnull, and accessing[1]throws an error; - the dots in the regular expression match any character because they are not escaped;
- the parser assumes a specific internal cookie format that Google does not guarantee as a public API;
- it does not handle a custom prefix, domain, path, or multiple relevant cookies;
- it reads the raw cookie string independently of the Google tag’s logic and may therefore work with a stale cookie even when downstream processing should not occur;
document.cookieis a synchronous API that can block the main thread, and a Custom JavaScript variable may be evaluated repeatedly in GTM.
The original text also mentioned handling the problem with try, but the published example contains no try/catch. Adding try/catch would not solve the dependency on the cookie’s internal format either.
On August 1, 2025, Google added the supported readAnalyticsStorage API for custom templates, and in December of the same year it made the variables available directly in GTM. Google stated the reason explicitly: reverse-engineering cookie formats was unreliable and could break when their structure changed.
Safe migration procedure
- Find all tags, triggers, and variables that use the old parser.
- Enable the built-in variable or create an Analytics Storage variable for a custom prefix.
- Replace references incrementally rather than renaming the old variable and changing the entire container at once.
- Verify a clean first visit, granting consent, denying consent, and revoking consent without a reload.
- Publish a named container version with the option of a quick rollback.
- Delete the old parser only after no references to it remain.
When do you actually need Client ID?
The most common legitimate case is the GA4 Measurement Protocol: you want to send a server-side or offline event and link it to browser activity that has already been captured through the Google tag. I explain the difference between direct server-side measurement, client-side measurement, and server-side GTM in more detail in the article Client-Side and Server-Side Measurement vs. Google Server-Side Tagging.
For a web stream, the Measurement Protocol uses:
measurement_idin the request URL;client_idin the JSON body;api_secretin the request URL, but only on a trusted server;- depending on the use case, also
session_id,engagement_time_msec, and optionallytimestamp_micros.
Client ID should match the value created by the Google Analytics tag on the website. Never put the API secret in a GTM variable, the data layer, or browser JavaScript. Any visitor could read it and send fake data to your GA4 property.
If a server-side event is meant to inherit the attributes of a specific session, you also need session_id. For session attribution, Google requires the event to be sent no later than 24 hours after the session starts. For correct engagement metrics and better visibility in Realtime, the documentation also recommends adding engagement_time_msec.
The Measurement Protocol is intended to supplement measurement through the Google tag, not replace it. Server-to-server events without the corresponding online context may have only partial reporting and poorer attribution.
Other legitimate cases
- targeted debugging of a specific data flow;
- server-side linking of online and offline events for a clearly defined purpose;
- data import supported by GA4;
- a custom analytics backend that respects consent status, access controls, and retention periods.
“Maybe it will be useful someday” is not a sufficient use case for collecting another pseudonymous identifier.
Why you should not send Client ID as a custom dimension with every event
The original article recommended sending Client ID with every hit as a custom dimension. This used to be a common workaround in Universal Analytics. I would not use it as the default approach in GA4.
Client ID has an almost unique value for each browser instance, creating a high-cardinality dimension. Google considers more than 500 unique values per day to be high cardinality. Such a dimension increases the number of rows, raises the risk of values being grouped into the (other) row, and consumes one of the limited custom definitions.
Use a more appropriate approach for your objective:
- I need raw event data: the GA4 BigQuery export contains the pseudonymous
user_pseudo_idfield. However, it still does not represent a stable person across browsers and devices. - I need to link a signed-in user across devices: implement a system-level User-ID, not a custom dimension containing Client ID or User-ID.
- I need to review the activity of an individual pseudonymous user: use User exploration or BigQuery, depending on availability and purpose.
- I need a server-side event: pass Client ID only into the specific server-side flow and follow the Measurement Protocol rules.
Testing matrix for Client ID and consent status
Do not look for one universal expected string. In every scenario, verify the Consent Mode state, the variable value, cookies, and network requests separately.
| Scenario | What to expect | What to verify |
|---|---|---|
| New clean profile before consent in Basic Consent Mode | The Google tag is blocked, _ga is not created, and Client ID is unavailable | Default consent set before tags, absence of the analytics cookie, no GA request, and safe handling of the missing value |
| Consent granted | The Google tag may create the cookie, and the native variable may read Client ID after it has been created | The consent update, tag order, cookie, value in Tag Assistant, and corresponding network request |
Advanced Consent Mode with analytics_storage='denied' | Cookieless pings may be sent, but the Google tag must not read or write analytics cookies | The consent state, absence of a newly created _ga cookie, request parameters, and absence of a custom replacement identifier |
| Consent granted, cookie created, then consent revoked without a reload | The exact GTM variable value is not universally documented; the old cookie may physically remain | The variable value, new consent state, cookie status, blocking of downstream tags, and network requests as separate checks |
Performance, privacy, and checklist
Performance
The built-in variable does not create an additional network request and removes the need for a custom regular expression. A single manual read of document.cookie will not usually slow down a website measurably, but it is a synchronous API, and GTM may evaluate a Custom JavaScript variable repeatedly. The native solution is therefore more reliable, simpler, and less expensive to maintain.
Privacy
Client ID is pseudonymous, not anonymous. Recital 30 of the GDPR explicitly lists cookie identifiers among online identifiers that, when combined with other information, may create a profile or contribute to identifying a person. Pseudonymization reduces risk, but it does not make the data anonymous.
You should therefore have a specific purpose, an appropriate legal basis, a proportionate retention period, and access rules. If you store Client ID in your own backend or CRM, include it in your data inventory, consent-revocation process, and data-deletion process. Google also prohibits sending PII to Analytics and notes that its contractual definition of PII may not be identical to the GDPR definition of personal data. Details are available in the documentation on PII in the Google Analytics terms.
Do not link Client ID to an email address, phone number, or other directly identifying value without a clear, assessed, and documented reason. Never send PII to Google Analytics.
Sometimes the best GTM variable is the one you do not need at all. The native Analytics Client ID variable solves the reliable retrieval of the value. It does not address the purpose of collection, identity quality, tag sequencing, Consent Mode, or data governance in downstream systems.