Even though every professional working in Digital Analytics and Web Development wants to reduce Client-Side JavaScript, the “new and advanced” Google Analytics 4 has added JavaScript-based Client-Side session handling. Which basically means, that Google outsourced compute resources to your user’s devices in order to save costs. Obviously, it’s a free and has some astonishing functionalities for a free tool. But let’s assume you don’t want to use GA4 anymore – you want to build your own tracker (possibly after you’ve read my posts about inserting data to BigQuery directly).
Server-Side Googletagmanager offers more than one way to handle a session data-model in a Digital Analytics context. I’d argue there are at least tree, so let’s take a closer look at them:
1. Build a SQL-based session data-model after BigQuery insert
This is the classic way of creating a session data-model. Let’s say you have a denormalized BigQuery table with all your event-data as well as a column “session_id” containing the associated session id for all these. The session_id itself is persisted by any kind of web storage mechanism (e.g. Cookies, localStorage, sessionStorage). While transforming this raw event-data to a more sophisticated production data, you can use SQL to create a model for all relevant session data. For example, you want to create a session table, that contains the session id, the session landingpage as well as the timestamp of the first hit. A query to model this data could look like this:
CREATE TABLE `my-session-table` AS
WITH window_prep AS (
SELECT
session_id,
FIRST_VALUE(timestamp) OVER (PARTITION BY session_id ORDER BY timestamp ASC) first_hit_timestamp,
FIRST_VALUE(page_location) OVER (PARTITION BY session_id ORDER BY timestamp ASC) AS landing_page_url
FROM
`my-event-table`
)
SELECT
*
FROM
window_prep
GROUP BY ALL
The above query creates a session table, that contains the first page visited in a session as landingpage, the timestamp of the session’s first hit as the first_hit_timestamp and the corresponding session id.
This table can be extended by any useful column imaginable. This solution’s biggest advantage is probably it’s ability to be rebuilt/updated at any time. The biggest disadvantage is, that the query usually only runs once a day or so. This means, that you do not have a session data-model in realtime. Additionally, you have to perform SQL-JOINs whenever you need session information working with your event data.
2. Persist session data based on a (HTTP-) Cookie
In this version, we use sGTMs capabilities to create an HTTP-only cookie, which contains all relevant session data. It can be static throughout the session or be updated whenever necessary.
Imagine having an object within a cookie, that contains not only the session id but also data like landingpage and first hit timestamp:
{
id: '123456789', //session id
lp: '/home', //landingpage
fhts: 787687677875 //first hit timestamp
lhts: 787687679875 //latest hit timestamp
}
The above cookie needs to be created by sGTM when a new session is started. When a session starts or an existing session ends can be engineered by checking for an existing cookie and calculating the difference between the current timestamp and the latest hit timestamp in the above object.
With every hit after the session’s initialization the cookie is read and both the event data as well as the session data is written to BigQuery. This way your event table contains up-to-date session data in every column – which is probably this option’s biggest advantage. But be aware, that this option is more difficult to engineer, easier to manipulate and your collected data cannot be changed afterwards.

A little service advise: In case you want to store all your session data in a cookie, remember to stringify the object and also consider encoding it in some way.
3. Persist session data based on a backend document-storage (Firebase)
The third option is actually kind of a mix of the other two. Instead of setting a cookie, which contains all relevant session data in an object, you create and update a Google Firebase document (visually similar to a JavaScript object) using sGTM’s native API.
Like the cookie in option two, the document has to be created whenever a new session starts. For every incoming event afterwards, you query Firestore to retrieve the session data and write to BigQuery together with the event data.
The resulting table contents should be identical to option two. But all this happens in your Cloud backend instead of cookie visible to your users – similar to option one.

This option has all the advantages that number two has, while also being more difficult to identify and manipulate. But mind the costs that can be create in GCP by using Firestore for every single incoming tracking request.
I hope you were to get an idea of different possibilities to persist a session and create a data-model. At the end of the day, what solution you chose should depend on your need for real-time session data and the option to change the logic in which you stitch together a session.
Best!
Ramon