I wanted a way to demonstrate my ability to work across the full analytics engineering process using real data. My portfolio website already had user activity, so I decided to use Google Analytics 4 (GA4) as the event collection layer and build a complete data pipeline on top.
This project covers the full workflow, including event collection, export to BigQuery, dimensional modeling, incremental ETL, and Power BI reporting. The result is a production-style analytics pipeline built on real usage data from my website.
When GA4 exports data to BigQuery, it produces a set of daily summary tables. These tables are partitioned by the _DATA_DATE column and contain different types of behavioural information. For the purposes of building a dimensional model, the most important summary tables are described below.
This table contains session-level acquisition metrics such as:
sessionDefaultChannelGroupsessionSourcesessionMediumsessions, eventCount, engagedSessionstotalRevenue_DATA_DATE (partition)This table is the basis for understanding daily traffic by acquisition channel.
This table focuses on first-user acquisition and includes fields such as:
firstUserSourcefirstUserMediumfirstUserCampaignNamenewUsers, totalUsers_DATA_DATEThis is used to understand how new visitors first discovered the website.
This table provides page level behavioural data:
unifiedPagePathScreenunifiedScreenNamescreenPageViewsactiveUserseventCountkeyEventsuserEngagementDuration_DATA_DATEThis table is central for page performance analysis.
This table provides information about the devices and platforms used:
deviceCategoryoperatingSystembrowserscreenResolutionplatformDeviceCategory_DATA_DATEThis forms the basis for device and platform analytics.
The GA4 export schema is intended for Google's built in reporting. It is not structured for BI tools. The main issues include:
To build a model suitable for analysis, I remodelled the dataset into a star schema.
A dimensional model resolves the problems created by the GA4 export structure.
Traffic sources, pages, devices, and dates become reusable lookup tables.
Each fact table represents a specific analytical concept.
Surrogate keys replace long, inconsistent GA4 strings.
Joins become predictable and efficient.
Since GA4 exports data daily by _DATA_DATE, the model can be updated incrementally.
This approach reflects how analytics engineering is typically performed in production.
The model consists of four dimension tables and four fact tables. The diagram below shows how they relate.
These tables were built directly in BigQuery. Since GA4 exports natively into BigQuery, this approach avoids any data movement costs and keeps the overall pipeline inexpensive to operate. The same modelling pattern could be implemented in other warehouses such as Microsoft Fabric, Azure SQL, or Amazon Redshift, but BigQuery remains the most cost efficient option for GA4 data.
The dimension tables standardise descriptive attributes and are referenced by all fact tables.
This table is generated using the minimum and maximum _DATA_DATE across all GA4 tables. It contains fields such as:
The primary key is a dim_date_key formatted as YYYYMMDD.
GA4 includes traffic source information in multiple tables, and the attributes vary depending on scope. I consolidated these fields into one dimension with the following attributes:
SESSION or FIRST_USER)Each unique combination receives a stable surrogate key generated using a fingerprint hash.
This table is built from the pages and screens table and includes page level attributes:
Each URL receives a unique dim_page_key.
This dimension contains device and platform attributes:
Each unique device configuration receives a dim_device_key.
Each fact table represents a different type of daily measurement.
Grain: date by session traffic source
Metrics include:
Keys:
Grain: date by first-user traffic source
Metrics include:
Grain: date by page
Metrics include:
Grain: date by device
Metrics include:
GA4 exports data once per day. This allows the ETL pipeline to run incrementally, processing only new data.
Below is an example of the incremental pattern used for fact tables.
INSERT INTO ga4_data.fact_page_metrics (...)
SELECT ...
FROM ga4_data.ga4_PagesAndScreens
WHERE _DATA_DATE > (SELECT MAX(date) FROM ga4_data.fact_page_metrics);
This approach keeps processing costs low and avoids reprocessing historical data. All transformations run as BigQuery Scheduled Queries.
Power BI includes a native connector for BigQuery. Connecting the dimensional model is straightforward:
The diagram below shows how the tables appear in Power BI after relationships are created.
Once the model is connected, I built visuals to show daily traffic, page performance, device usage, acquisition trends, and user engagement.
This project demonstrates the full analytics engineering lifecycle using real data from my website. By collecting events with GA4, exporting them to BigQuery, restructuring the raw tables into a dimensional model, building incremental ETL pipelines, and visualising the data in Power BI, I created a maintainable and scalable analytics workflow.
This approach mirrors the process used in production analytics environments and highlights my capability in:
The resulting dashboard presents a clear view of how visitors interact with my site and provides a practical example of end to end data capability.