How do I access the individual timestamp of a GA4 event?

Simmer Clips #4

The question we’re going to be looking at today is inspired by our course, Query GA4 Data in Google BigQuery.

How do I access the individual timestamp of a GA4 event?

One of the features of Google Analytics 4’s client-side measurement is that the platform collects events in batches. This means that when an event happens, it isn’t immediately dispatched to Google Analytics 4.

Instead, the client-side library waits up to 5 seconds for other events to happen, at which point all the events that happened during this batch window are dispatched.

This is not that uncommon with telemetry tools. Batching is common especially on mobile devices, where constant network requests can quickly deplete the device battery, for example.

However, there’s a huge downside to this with Google Analytics 4. For some reason, individual events are not timestamped nor do they have a sequence indicator. All events share the timestamp of the batch request itself, which leads to the following, unbelievable conclusion: by default, it’s not possible to know WHEN a certain event happened, or what the sequence of events in any given batch was.

In this article, I’ll walk you through the simple steps of how to diagnose this issue as well as how to fix it by adding a custom timestamp to your events. There are some caveats, however. Hopefully, at some point Google will figure out this mistake and add timestamps to all events of any given batch.

Video walkthrough

If you prefer this walkthrough in video format, you can check out the video below.

Don’t forget to subscribe to the Simmer YouTube channel for more content like this.

Overview of the problem

To identify the problem, run the following query against your Google Analytics 4 data. You can choose any date you wish. This query simply pulls in user_pseudo_id and all events associated with each user, ordered by timestamp.

				
					SELECT
  user_pseudo_id,
  event_timestamp,
  event_name
FROM
  `project.dataset.events_YYYYMMDD`
ORDER BY
  user_pseudo_id,
  event_timestamp
				
			

This is what the results might look like:

If you scroll the results far enough, you should see multiple event_name rows that share the user_pseudo_id and that all have the same event_timestamp.

In these cases, these events were collected in a batch, and all events share the same timestamp.

In the screenshot above, I’ve circled these multi-event batches in red. As you can see, the second batch has FIVE events that all share the same timestamp. How on earth am I supposed to build sequence analyses when there are five events of which I don’t know the relative sequence or the exact time when they occurred?

In my opinion, this is a fairly big mistake from Google and one that should be fixed.

Luckily, there is something you can do to fix this proactively. You can add a custom event parameter to all your GA4 events so that they’ll have a timestamp associated with them.

Add the event parameter to your GA4 tags

Because the timestamp needs to be evaluated for all GA4 event tags separately, you shouldn’t add it to the GA4 Configuration tag / hit

At this point, if you’re still using the automatically collected Page View option in the Configuration tag, I recommend disabling it and sending the page_view as its own GA4 event. This gives you far more control over data collection.

In Google Tag Manager, you can create a Custom JavaScript variable that generates the timestamp with this:

				
					function() {
  return new Date().getTime();
}
				
			

Even better, you can use a custom template to get the timestamp without having to use a Custom JavaScript variable. This template does the job nicely: Timestamp by luratic.

Once you’ve created the variable, you need to add it to all your GA4 event tags.

If you are using gtag.js, the process is very similar, except you will just need to generate the timestamp with JavaScript.

				
					gtag('event', 'custom_click', {
  custom_timestamp: new Date().getTime()
});
				
			

Once the custom parameter has been added to your events, you’re ready to start collecting that data for analysis.

Warning! I don’t recommend creating a custom dimension in GA4 for the timestamp, because this might lead to severe cardinality issues in your data. It’s best to leave the granular analysis to Google BigQuery.

Analyze the data in Google BigQuery

Once you’ve added the custom event parameter, you can modify your query in Google BigQuery to see the impact.

Here’s the query from the beginning of this article, modified to include the custom event parameter.

				
					SELECT
  user_pseudo_id,
  TIMESTAMP_MICROS(event_timestamp) AS event_timestamp,
  TIMESTAMP_MILLIS((SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'custom_timestamp')) AS custom_timestamp,
  event_name
FROM
  `project.dataset.table`
ORDER BY
  user_pseudo_id, 
  event_timestamp
				
			

And here are the results.

Fixed BigQuery result with custom event timestamp included

If you look at the highlighted rows (4–8), you can see how the individual events in the batch are now associated with their own timestamps. You can now more clearly identify the sequence of events.

Note that in the case of the highlighted rows, we got “lucky” in that BigQuery actually displayed the events in the correct order (the custom timestamps are in ascending order even though we didn’t ORDER BY them). 

If you look at rows 11–13, you can see that the three events in that particular batch are not in the correct order. Based on the custom_timestamp parameter, page_view came first, then view_item, and finally fetch_user_data.

This is why it’s so important to collect the custom timestamp.

Caveat & Summary

One important caveat is apparent in the screenshot above. The custom parameter is not collected for events that GA4 generates independent of your event tags. session_start, first_visit, and user_engagement are such events.

While session_start and first_visit are generally easy to attribute to the page_view that’s in the same batch as them, user_engagement is a difficult nut to crack, because there’s no way to add custom parameters to that automatically generated event.

So there will be minor inconsistencies, but at least for all the events that matter, you now have a way of aligning them properly in your data warehouse.

In summary, this is one of those articles that I really hope will become redundant soon, because that would mean that Google has fixed this issue in the data collection. While batching is a good feature in general, it’s kind of inexcusable to ignore the granularity of event collection in 2023. It shouldn’t be too difficult to automatically add a time index to all events – it doesn’t have to be the full timestamp, just the offset from the batch time would do, for example.

Leave a Comment

Hide picture