There’s times when it’s useful to send GA4 events to two (or more) GA4 properties. Maybe you’ve got a GA4 “Rollup property” for multiple domains or a property to gather all errors in one place.
Update November 2023: The new Google Variable “Google Tag: Configuration Settings” allows you to setup parameters in one place. You can then apply these parameters to the two GA4 setup tags using the one configuration tag. If you’ve got lots of parameters then this will be useful.
I was hoping for some ID flexibility, but not there yet.
GA4 Setup Tag With Configuration Variable
Update January 2024: I now use a JavaScript variable for the “Tag ID”. This allows me to dynamically change the ID depending on if it’s an internal or test user. I’ve got a special GA4 property to receive internal or test hits. This keeps my normal GA4 property cleaner, with less internal traffic contamination.
Here’s how the variable is configured:
You may read that using JavaScript variables is resource intensive. But in fact this one will only be run when it’s needed. However when you use Tag Assistant you’ll find it gets run VERY often. (you can add a console.log(“being run”); to check). Once you’ve published the GTM container the JS variable is only run when it’s needed – not so often.
Back to GA4 setup using a configuration variable…
Here’s how to do that using GTM. It’s easier than you might think.
The GA4 Setup Tag in GTM (Google Tag Manager – without configuration tag)
The “Measurement ID” is what determines which GA4 property any events are sent to.
Putting two Measurement IDs in the setup (with a comma separating them) doesn’t work (it’s not that simple). GTM picks the first ID and uses that.
We could use two GA4 Setup Tags. One for each property. The second one is exactly the same as the first except for the Measurement ID.
The Second GA4 Property Setup Tag (without configuration tag)
However an undocumented trick that works (for me) is to put multiple GA4 Measurement IDs in a JavaScript Array:
['G-AAAAAAAAA','G-BBBBBBBBB']
You can’t put this in the tag directly, but I do it as a Custom JavaScript Variable.
Now when you load a page there’s 2 page_view events sent. One to each property.
Here is where it gets simple. Lets add another event – in this case “test_event”. The trick is to “Manually Set ID” for the event. Using a GTM Custom JavaScript variable with the two Measurement IDs in a JavaScript Array.
The Array contains the Measurement IDs you want to send events to.
I have a special ID GTM variable with both Measurement IDs setup inside.
This is how we use the combined ID variable
Now when we load a page the “test_event” is sent to both GA4 properties.
The images are from Chrome Dev Tools showing the two almost identical events sent to the two different GA4 properties.
This works for me in simple Google Analytics 4 setups in Tag Manager.
My previous version used comma separated GA4 Measurement IDs, however the GA cookies were compromised. Using the JavaScript Array method is much more reliable.
If you get any issues please contact me, and I’ll check.
If you’ve got some offline or late conversions coming in after a visitor leaves your site then it’s useful to be able to feed them into Google Analytics. In this case GA4.
One of the ways you can do this is called “Measurement Protocol” – MP for short.
To use MP you’ll need to get or create the MP secret from your GA4 Admin area: Admin >> Data Streams
Then click on the stream you want to send the conversions to. And you’ll see:
Click on the “Measurement Protocol API secrets” bar and you can Create a secret or copy one if you’ve previously created a secret.
Once you have the secret store it in a safe place – that you’ll remember.
To send a conversion to GA4 you’ll need a few bits of information (mainly IDs) to tie the conversions to what Google knows about the converting visitor and the session when they were active:
client id – this is the GA4 id for the visitor – for example, like this 232912142.1691119463 – Google is able to match a conversion to a particular visitor who has been on your website.
session id – the actual session that you want to give credit for the conversion “1691126066” – Google uses this to match the conversion to a particular visitor “session”. Visitors might have multiple sessions on your site.
timestamp micros – this is a “microsecond timestamp”, which should be within the session. This is something like “1706828159565000” (which converts to Thu, 01 Feb 2024 22:56:23 GMT).
(and “non_personalized_ads“:false to keep retargeting working)
I’ll show you how to find these and how I store them later on.
Plus you’ll need the actual conversion information, just like you would for a normal on website conversion. I like to send the following (some are optional):
transaction id – unique id for the specific transaction (if you need to send a refund to GA4 this will have to match the purchase transaction id
currency – eg USD can specify currency at the item level (but avoid multi-currency if at all possible) I generally would put this parameter at the top level of parameters.
I use n8n to send this POST to Google. It’s a nifty open source workflow tool I self host. You could use Zapier or make.com as well. Or code it up in a language like JavaScript/PHP/etc.
Getting the Client ID and Session ID
Both these IDs are stored as part of the Google Analytics first party cookies when a visitor is on your site:
The client ID is in “_ga” and the Session ID is in _ga_XXXXXXX (corresponding to the Measurement ID of you Google Analytics 4 property). You have to extract the part of the cookie you need. The last number for the Session ID and the last two large numbers (and the connecting “.”) for the Client ID.
To get the GA4 client_id and session_id using gtag:
gtag('get', 'G-XXXXXXXXXX', 'client_id', function(client_id){
console.log(client_id);/* do something here */
});
gtag('get', 'G-XXXXXXXXXX', 'session_id', function(session_id){
console.log(session_id);/* do something here */
});
Note that the Client ID is stored in BiqQuery by the automatic GA4 to BigQuery export. The Session ID is stored as one of the event parameters, with key “ga_session_id”.
The session ID is just a second timestamp. And it’s not necessarily unique. If you have a reasonable number of visitors then there’s likely to be overlap on session IDs. For a unique id concatenate the client_id and the session_id.
I often do something like this in BigQuery SQL:
CONCAT(client_id, session_id) as unique_id -- this would be after extracting the session_id from the event parameter field
You can store the session ID as a GA4 event parameter then define it as a custom dimension in GA4. Then it will be available as an dimension in GA4 reports.
Getting The “timestamp_micros” Parameter Correct in Measurement Protocol
The timestamp micros is a microsecond UNIX timestamp that is during the session. If you don’t use this parameter in this way Google shows the conversion in GA4, but it doesn’t assign it to the correct source/channel.
I generally save all this information, including the timestamp value, just after GA4 has sent it’s first page_view event. You can get a JavaScript callback when the event has finished.
For gtag:
gtag('event','page_view',
{'event_callback': function(){
var gaId = readCookie('_ga');
var gsId = readCookie('_ga_'+GA4ID);
serverev('track', 'info', {'ga_id':gaId,'gs_id':gsId}, 'se');
}
})
That’s my “serverev info” event with all the required information (the timestamp is automatic). I’m sending this to BigQuery using Jitsu, but you can do something similar in other ways.
The other key is to be able to “reconnect” you conversion to the information you’ve saved.
You can directly save it in a CRM / Sales system as hidden fields so it’s available later.
In my case the conversion is via an affiliate network. I make sure I send a “subid” to the network with each click. If I get a conversion I can obtain the associated subid.
Then I use the subid to join the conversion to the information I’ve saved in BigQuery earlier.
And so when the conversion data becomes available, hours or days after the session I can use SQL on BigQuery and get the information to build the POST to Google Measurement Protocol.
n8n has a BiqQuery connector. This allows me to run the SQL and obtain the client_id, session_id and timestamp_micros values I saved earlier. Then I can just POST to MP using the JSON format I showed above.