This guide covers how to install and configure Google Analytics 4 (GA4) on Kentico Xperience websites using both MVC and Portal Engine development models.
Prerequisites
- Google Analytics 4 property created
- GA4 Measurement ID (format:
G-XXXXXXXXXX) - Admin access to Kentico
- Access to edit layout files or master pages
Method 1: Direct Implementation (Recommended for Simple Sites)
For MVC Development Model (Kentico 12+)
Locate Your Layout File
- Navigate to
~/Views/Shared/_Layout.cshtmlin your project - Or your custom layout file if using a different structure
- Navigate to
Add GA4 Tracking Code to Layout
Add this code in the <head> section:
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX', {
'send_page_view': true,
'cookie_flags': 'SameSite=None;Secure'
});
</script>
- Make It Dynamic with Kentico Settings
First, create a setting in Kentico:
- Go to Settings → Integration → Google
- Create a new setting key:
GoogleAnalyticsMeasurementID - Enter your GA4 Measurement ID
Then update your layout file:
@using CMS.Helpers
@{
var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID);
}
@if (!string.IsNullOrEmpty(gaId))
{
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=@gaId"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '@gaId', {
'send_page_view': true,
'cookie_flags': 'SameSite=None;Secure'
});
</script>
}
For Portal Engine (Legacy)
Access Master Page
- Go to Design → Master pages
- Edit your root master page (typically the one used site-wide)
Add Code to Master Page
In the Master page code section, add to <head>:
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
- Using Kentico Macros for Dynamic Values
{% raw %}{%
var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID");
if (!String.IsNullOrEmpty(gaId)) {
%}
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id={% gaId %}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{% gaId %}');
</script>
{% } %}{% endraw %}
Method 2: Using a Custom Web Part (Portal Engine)
Create a reusable Web Part for GA4 tracking:
Create Custom Web Part
- Go to Development → Web parts → New web part
- Name:
GoogleAnalytics4 - Parent category: Choose or create "Analytics"
Web Part Properties
Add these properties:
MeasurementID(Text) - GA4 Measurement IDEnablePageView(Boolean) - Enable automatic page view trackingDebugMode(Boolean) - Enable debug mode
- Web Part Code
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="GoogleAnalytics4.ascx.cs" Inherits="CustomWebParts.GoogleAnalytics4" %>
<% if (!String.IsNullOrEmpty(MeasurementID)) { %>
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=<%= MeasurementID %>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '<%= MeasurementID %>', {
'send_page_view': <%= EnablePageView.ToString().ToLower() %>,
'debug_mode': <%= DebugMode.ToString().ToLower() %>
});
</script>
<% } %>
- Add to Master Page
- Drag the Web Part into your master page
- Configure the properties
- Save and publish
Method 3: Using Custom Module (Advanced)
For enterprise implementations requiring centralized control:
Create Custom Module
- Go to Development → Modules → New module
- Name:
GoogleAnalyticsIntegration
Add Module Class
using CMS;
using CMS.Base;
using CMS.DataEngine;
using CMS.Helpers;
using CMS.SiteProvider;
[assembly: RegisterModule(typeof(GoogleAnalyticsModule))]
public class GoogleAnalyticsModule : Module
{
public GoogleAnalyticsModule() : base("GoogleAnalyticsIntegration") { }
protected override void OnInit()
{
base.OnInit();
// Register event handler for page rendering
RequestEvents.PostMapRequestHandler.Execute += PostMapRequestHandler_Execute;
}
private void PostMapRequestHandler_Execute(object sender, EventArgs e)
{
// Add GA4 script to page head
var measurementId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID);
if (!string.IsNullOrEmpty(measurementId))
{
string gaScript = $@"
<script async src='https://www.googletagmanager.com/gtag/js?id={measurementId}'></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){{dataLayer.push(arguments);}}
gtag('js', new Date());
gtag('config', '{measurementId}');
</script>";
CMS.Base.Web.UI.ScriptHelper.RegisterClientScriptBlock(
typeof(string),
"GA4Tracking",
gaScript,
false
);
}
}
}
Multi-Site Configuration
For Kentico installations managing multiple sites:
Create Site-Specific Settings
- Go to Settings → [Your Site] → Integration
- Add
GoogleAnalyticsMeasurementIDsetting at site level - Enter different GA4 IDs for each site
Layout Code for Multi-Site
@using CMS.Helpers
@using CMS.SiteProvider
@{
var currentSite = SiteContext.CurrentSite;
var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", currentSite.SiteID);
}
@if (!string.IsNullOrEmpty(gaId))
{
<!-- Google Analytics 4 for @currentSite.SiteName -->
<script async src="https://www.googletagmanager.com/gtag/js?id=@gaId"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '@gaId', {
'custom_map': {
'dimension1': 'site_name'
},
'site_name': '@currentSite.SiteName'
});
</script>
}
Excluding Staging/Development Environments
Prevent tracking on non-production environments:
@{
var isProduction = SiteContext.CurrentSite.SiteName == "ProductionSite";
var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID);
}
@if (isProduction && !string.IsNullOrEmpty(gaId))
{
<!-- GA4 code here -->
}
Or use macro expressions:
{% raw %}{% if(CurrentSite.SiteName == "ProductionSite") { %}
<!-- GA4 code here -->
{% } %}{% endraw %}
Enhanced Measurement Configuration
Configure GA4 enhanced measurement features:
gtag('config', 'G-XXXXXXXXXX', {
// Enhanced measurement
'send_page_view': true,
'enhanced_measurement': {
'scrolls': true,
'outbound_clicks': true,
'site_search': true,
'video_engagement': true,
'file_downloads': true
},
// Custom parameters
'custom_map': {
'dimension1': 'kentico_page_type',
'dimension2': 'kentico_document_type',
'dimension3': 'user_authenticated'
},
// Page-specific data
'kentico_page_type': '@ViewBag.PageType',
'kentico_document_type': '@ViewBag.DocumentType',
'user_authenticated': '@(User.Identity.IsAuthenticated ? "yes" : "no")'
});
User ID Tracking
Track authenticated users across devices:
@using CMS.Membership
@{
var currentUser = MembershipContext.AuthenticatedUser;
var userId = currentUser != null && !currentUser.IsPublic()
? currentUser.UserID.ToString()
: null;
}
<script>
gtag('config', 'G-XXXXXXXXXX', {
@if (userId != null) {
<text>'user_id': '@userId',</text>
}
'send_page_view': true
});
</script>
Testing Your Implementation
Use GA4 DebugView
- Add
debug_mode: trueto your config - Open GA4 → Configure → DebugView
- Navigate your site and verify events
- Add
Browser Developer Tools
- Open Network tab
- Filter by "collect" or "google-analytics"
- Verify requests are being sent
GA4 Realtime Reports
- Open GA4 → Reports → Realtime
- Navigate your site
- Check for active users and page views
Tag Assistant (Chrome Extension)
- Install Google Tag Assistant
- Click the extension while on your site
- Verify GA4 tag is firing
Common Issues
GA4 Not Tracking
- Verify Measurement ID is correct (format:
G-XXXXXXXXXX) - Check browser console for errors
- Ensure scripts are in
<head>or before</body> - Verify no ad blockers are interfering
Duplicate Page Views
- Check if tracking code appears multiple times
- Verify not implementing both direct and GTM GA4
- Check for multiple layout files loading the same code
Staging Environment Tracking Production
- Implement environment-based conditional loading
- Use different GA4 properties for staging/production
- Add staging domain to referral exclusion list
Next Steps
- Implement Custom Event Tracking
- Set Up E-commerce Tracking
- Configure GTM Instead (recommended for complex implementations)