Aahhh… the joy of setting up GA4. A clean, fresh implementation. No legacy.. just pure new good intentions. And also a lot of quirks to work around.
Your Universal Analytics routine won’t help you here, so.. you might wonder: What should I put in a GA4 implementation to make it truly shine, and to get the most of it?
Here’s a list of things to add in your GA4 implementation that will really make your GA4 life easier.
Data modeling in Big Query can be made easier..
Problem: Relying on the GA4 built-in event_timestamp
will give you the microsecond-granular timestamp of when the event was batch-sent from the browser.
So that can be up to 5 seconds later than the actual event itseld, and all events in the batch will have the same timestamp.
Solution:
- Date.now()
I always create aclient_timestamp
parameter and fill it with the client date. This way, you will have millisecond-granular data on when the event happened in the browser.
When modeling event timings, and event-order you can now use this parameter as a timestamp.
Problem: When modeling events in Big Query.. how do you know it’s an event you have already processed, or if it’s a new one?
Solution:
- {{random number}}
Adding an event parameterrandom_number
will allow you to use a concatenation of random_number + user_pseudo_id + event_timestamp + event_name as event ID.
This is especially convenient, because Google can update the events_YYYYMMDD tables up to days after these tables are created. So rather than waiting, or using stale information: process them again, append them to your temporaty model table, and in the end, only use the last row.
Problem: What events happened on a particular page?
That is easy enough. But can be really tricky to model, using made-up IDs and window functions. What would make it super convenient is having a page_view_id of some sort.
Solution:
- {{gtm.start}}
When you add the gtm.start variable to a parameter calledpage_view_id
(in the config tag for example), all the tags that are loaded in that page load, will have the same ID. Super convenient!
I use a concatenation of user_pseudo_id and page_view_id to generate a page view ID, so all events with the same ID share the same page load.
Debug parameters
Although not useful directly for the business, there are some parameters that you can add to your events that will help you find out why things go wrong:
- gtm.uniqueEventId
adding this parameter (hat tip to Yehoshua Coren) will give you an ID that might not be unique, but in combination with the gtm.start variable, you will know if a dataLayer push made one or more tags fire. - {{Container ID}} {{Container version}}
Having a container id and version in tags will help you not only keep track of which versions were published at what date, but also will help you pinpoint data breakage to a certain GTM version. - {{Container ID}} {{Container version}}
Wait, what? Duplicate? Nope. The server container also has an ID and version. You can use that too in your server side variables!
Giovani Ortolani Barbosa says
Hi there. Thank you for the tips.
Just pointing out that the solution to “Problem: What events happened on a particular page?” does not work with SPAs.
jules says
Thanks!
And you’re right, that is why I use the team ‘on the same page load’, and not ‘page view’.
For SPAs, you need to resort to window functions.
MA40 says
Hello.
I have a custom event created directly on the web page, as follows:
gtag(‘event’, , {‘value’: , ‘client_timestamp’: Date.now()});
My problem is that the timestamp of the events has a precision of 5 second and sometimes, when two events occur in a row within the same second, GA4 records them with the same timestamp, and sometimes interleaves them in the timeline, putting the first one after the second one and breaking the sequence order.
Keeping the chronological order of events in the GA4 user interface would be very important to me.
Am I doing something wrong?
How could I solve this problem?
Best regards and thank you very much.
MA40 says
*** gtag(‘event’, , {‘value’: , ‘event_timestamp’: Date.now()});
MA40 says
*** gtag(‘event’, -action-, {‘value’: -value-, ‘client_timestamp’: Date.now()});
jules says
If you send
gtag('event', 'some_event', { 'client_timestamp': Date.now() } )
it will come out just fine as an event named “some_event” and a millisecond timestamp.
{
0: "event",
1: "some_event",
2: {
client_timestamp: 1677245040916
}
}