Analytics, Tag Manager and Consent Banners

3 min read

Analytics and consent tools assume one page load per pageview. Under ajax navigation that assumption breaks, and the symptoms are quiet — nothing errors, the numbers just go wrong.

The navigation event

document.addEventListener('ajaxpress:ready', (e) => {
  // e.detail.url, e.detail.title
});

Fires once per navigation, after the title and head metadata have synced. Everything below hangs off this.

Google Analytics 4

GA4 Enhanced Measurement includes “page changes based on browser history events”, on by default. It usually works, but often records the pageview before the new title is set — giving you the previous page’s title against the new URL.

If you turn it off, send pageviews yourself:

document.addEventListener('ajaxpress:ready', (e) => {
  gtag('event', 'page_view', {
    page_location: e.detail.url,
    page_title: e.detail.title
  });
});

Never both. Enhanced Measurement plus manual pageviews doubles every metric.

Known issue: engagement time reads zero

GA4 “Average engagement time” dropping to zero under AjaxPress is an open issue, reported by a user and not yet fixed. GA4 measures engagement with timers tied to page visibility and focus, and those do not restart cleanly for a virtual pageview.

Pageviews, events and conversions are unaffected.

Google Tag Manager

GTM’s “All Pages” trigger fires on real page loads only. Push your own event:

document.addEventListener('ajaxpress:ready', (e) => {
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    event: 'ajaxpress_pageview',
    pagePath: e.detail.url,
    pageTitle: e.detail.title
  });
});

Then create a Custom Event trigger on ajaxpress_pageview. Be selective about which tags you attach — a conversion tag firing on every navigation will corrupt your data.

Consent and cookie banners

Consent scripts expect to initialise once. Under a SPA they can initialise repeatedly, and the banner reappears.

Known issue: the iubenda consent popup has been reported firing twice with AjaxPress enabled. Open, being worked on, and the fix targets the general double-initialisation case.

For other consent tools, guard initialisation:

if (!window.__consentInitialised) {
  window.__consentInitialised = true;
  // initialise the consent tool
}

Consent state is one of the few things that should not re-initialise per navigation.

Sliders, lightboxes and widgets

The opposite case — these do need re-initialising, because the elements they bound to were replaced.

document.addEventListener('ajaxpress:ready', () => {
  const el = jQuery('.your-slider');
  if (el.hasClass('slick-initialized')) el.slick('unslick');
  el.slick();
});

Symptom reference

SymptomCause
Double pageviewsEnhanced Measurement and manual pageviews
No pageviews after the firstEnhanced Measurement off, nothing sending manually
Right URL, wrong titlePageview firing before the title syncs
Consent banner twiceDouble initialisation, or the known iubenda issue
Slider works on first load onlyNeeds re-initialising on ajaxpress:ready
Engagement time zeroKnown open issue

Verifying

Use GA4 DebugView or GTM Preview, navigate through five or six pages, and confirm exactly one pageview per navigation with matching URL and title. Test the Back button — that is where duplicate-firing bugs surface.