Adds Google Tag Manager to the application and manages communication with GTM JavaScript (data-layer).
HxGoogleTagManager and related components are distributed in a separate NuGet package: Havit.Blazor.GoogleTagManager.
Install GTM support through application startup:
builder.Services.AddHxGoogleTagManager(options =>
{
builder.Configuration.Bind("HxGoogleTagManager", options);
});| 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. |
Initializes Google Tag Manager and tracks page-views to the GTM data-layer.
Install GTM support through application startup (see above) and add HxGoogleTagManagerPageViewTracker to App.razor or MainLayout.razor
<HxGoogleTagManagerPageViewTracker />RendererInfo.
On net8.0 the component keeps its original behavior and tracks page-views in interactive render modes only.
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. |
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.
| 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.
When a Content Security Policy with nonce-* is in use, pass the nonce to the inline snippet:
<HxGoogleTagManagerPageViewTracker Nonce="@Nonce" />| 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. |