HxGoogleTagManager #

Adds Google Tag Manager to the application and manages communication with GTM JavaScript (data-layer).

Basic usage #

Install GTM support through application startup:

builder.Services.AddHxGoogleTagManager(options =>
{
	builder.Configuration.Bind("HxGoogleTagManager", options);
});

API #

Methods #

Method Returns Description
InitializeAsync() Task Initializes the GTM support. Called automatically within first Push call (incl. HxGoogleTagManagerPageViewTracker calls). To be used explicitly only in those rare cases when you want to initialize GTM without pushing any data.
PushAsync(object data) Task Push generic data to GTM data-layer (using regular JSON-serialization).
PushEventAsync(string eventName, object eventData) Task Push event to GTM data-layer.
PushPageViewAsync(object additionalData) Task Push page-view to GTM data-layer. Always pushes, even for the page-view tracked last. Consider using HxGoogleTagManagerPageViewTracker instead of manual handling.

HxGoogleTagManagerPageViewTracker #

Initializes Google Tag Manager and tracks page-views to the GTM data-layer.

Basic usage #

Install GTM support through application startup (see above) and add HxGoogleTagManagerPageViewTracker to App.razor or MainLayout.razor

<HxGoogleTagManagerPageViewTracker />

Render modes #

All render modes are supported. What the component does depends on where it is rendered:

Render mode How GTM is started and page-views tracked
Static SSR, prerendering The GTM snippet is rendered inline, so GTM starts loading while the page is still being parsed.
Static SSR with enhanced navigation A JS initializer shipped with the package listens for enhancedload. Blazor loads it automatically, nothing needs to be referenced.
Interactive Server, WebAssembly, Auto Page-views are pushed in reaction to NavigationManager.LocationChanged, which covers navigations resolved by the interactive router.

Where to place the component #

App.razor is the natural place — it is rendered on every response, so GTM starts loading as early as possible. App itself is always rendered statically though, and a statically rendered component cannot observe NavigationManager.LocationChanged, so navigations resolved by an interactive router would go untracked. Give the component its own render mode to cover those as well:

@* App.razor *@
<head>
    ...
    <HxGoogleTagManagerPageViewTracker @rendermode="@PageViewTrackerRenderMode" />
</head>

@code {
    [CascadingParameter] private HttpContext HttpContext { get; set; }

    private IComponentRenderMode PageViewTrackerRenderMode
        => HttpContext.AcceptsInteractiveRouting() ? new InteractiveWebAssemblyRenderMode(prerender: true) : null;
}

The component then becomes an interactive root component of its own, sharing the runtime and the NavigationManager with the rest of the app. Prerendering keeps the GTM snippet in the initial HTML even when the pages themselves are not prerendered, and pages excluded from interactive routing stay static, so they do not have to download the runtime just for tracking.

A layout or page inside an interactive island works too, and rendering the component more than once is safe — initialization and automatic page-views are deduplicated in JavaScript, so a navigation seen by more than one instance still produces a single event.

Events pushed to the data-layer #

Event When
gtm.js Once per document load, from the GTM snippet.
pageview Once per document load. Not part of Google's snippet — pushed for backwards compatibility.
PageViewEventName
(virtualPageView by default)
Once per navigation, enhanced navigation and interactive routing included. Configure a trigger for it in your GTM container — pageview alone fires only on real page loads.

By default the page the document was loaded with is announced by both pageview and PageViewEventName. Which convention your container follows decides whether that is what you want:

  • PageViewEventName is the single source of truth and pageview is ignored — keep EnableInitialPageViewTracking at its default true.
  • pageview (or the container's built-in Page View trigger) covers real document loads and PageViewEventName only the navigations that follow — set EnableInitialPageViewTracking to false, otherwise the landing page of every session is counted twice.

Content Security Policy #

When a Content Security Policy with nonce-* is in use, pass the nonce to the inline snippet:

<HxGoogleTagManagerPageViewTracker Nonce="@Nonce" />

API #

Parameters #

Name Type Description
Nonce string CSP nonce for the inline <script> tag rendered during static SSR and prerendering. Required when a Content Security Policy with nonce-* is in use.
An unhandled error has occurred. Reload 🗙