Analytics, Tag Manager and Consent Banners
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
| Symptom | Cause |
|---|---|
| Double pageviews | Enhanced Measurement and manual pageviews |
| No pageviews after the first | Enhanced Measurement off, nothing sending manually |
| Right URL, wrong title | Pageview firing before the title syncs |
| Consent banner twice | Double initialisation, or the known iubenda issue |
| Slider works on first load only | Needs re-initialising on ajaxpress:ready |
| Engagement time zero | Known 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.