GA4 and GTM in jekcms: Snippet Injection, and What You Build Yourself

jekcms's built-in GA4/GTM integration is snippet injection — put your Measurement ID or Container ID in settings, jekcms adds the tag. Scroll depth, custom conversions, and dataLayer event tracking are not built in; here's what's real and what you'd add yourself.

GA4 and GTM in jekcms: Snippet Injection, and What You Build Yourself

jekcms's built-in GA4/GTM integration is snippet injection — put your Measurement ID or Container ID in settings, jekcms adds the tag. Scroll depth, custom conversions, and dataLayer event tracking are not built in; here's what's real and what you'd add yourself.

After entering your GA4 Measurement ID in Settings › Analytics, JekCMS injects the gtag.js snippet automatically through the jek-google plugin, along with a basic page-view event. Custom events — anything beyond page views — require adding JavaScript to your theme yourself, either directly or through a Google Tag Manager container you configure by hand.

Scroll Depth: A Better Bounce Signal

Scroll depth isn't tracked out of the box, but it's one of the more useful custom events to add for a content site. A reader who scrolls to 75% and then leaves has engaged substantively, while one who scrolls 10% and leaves has not — that distinction is more meaningful than bounce rate on its own.

Two-Dimensional Engagement: Time × Scroll

Combine scroll depth with active-time-on-page events and you get a two-dimensional engagement signal you can use to build GA4 audiences. A reader who is deep into a scroll and has spent several minutes on the page has read the article; a reader who bailed at 25% scroll after a few seconds has not.

Adding Custom dataLayer Events

Once the base gtag.js snippet is live, push additional custom events by adding JavaScript to your theme's footer template:

// Track scroll depth milestones
const milestones = [25, 50, 75, 100];
let fired = new Set();

window.addEventListener('scroll', function() {
  const scrollPercent = Math.round(
    (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100
  );
  milestones.forEach(function(m) {
    if (scrollPercent >= m && !fired.has(m)) {
      fired.add(m);
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: 'scroll_depth',
        depth: m,
        page_type: document.body.dataset.pageType
      });
    }
  });
});

In GA4, create a custom dimension for depth so it shows up in reports. The page_type parameter (set via a data-page-type attribute on <body> in your theme) lets you segment scroll depth by content type.

Search Query Tracking

Track internal search queries the same way — push a custom event when your search form submits, with the query and result count as parameters. In GA4, create custom dimensions for those parameters. This reveals what visitors are looking for and how often search comes up empty, which is a direct content gap signal.

Track file downloads and outbound link clicks with a single delegated click listener on document: check whether the clicked element is a link, then inspect its href to decide whether it points to a downloadable file or an external domain, and push a corresponding event.

Building GA4 Audiences from Custom Events

Once scroll depth, time-on-page, and search events are flowing into GA4, build audiences that reflect real engagement rather than raw page view counts — readers who cross both a high scroll-depth and a long active-time threshold, visitors who search and get zero results, or people who've downloaded a resource in the last month. These are standard GA4 audience-building features, not anything specific to JekCMS.

Debugging with GA4 DebugView

Enable GA4 DebugView with the Google Analytics Debugger browser extension. It sends events to the debug stream in real time, so you can verify event names, parameters, and timing without waiting for the 24-48 hour processing delay in standard GA4 reports. Test every custom event in DebugView before deploying to production — misspelled event names, missing parameters, and duplicate events from cached JavaScript are the usual culprits.

Naming Consistency and dataLayer Hygiene

Consistency in GA4 event naming matters for long-term reporting. Pick a convention — lowercase and underscores (scroll_depth, file_download, outbound_click) is the GA4 default recommendation — and stick to it everywhere in your theme, so the same event doesn't fragment into multiple spellings in your reports.

Validate parameters before pushing them: empty or undefined values create ghost rows in GA4 reports and quietly skew your analysis.

Turning GA4 Data Into an Editorial Feedback Loop

The real payoff of collecting this data is feeding it back into your content plan. Review which articles reach the deepest scroll depth, which pages hold attention longest, and which searches return nothing, on a regular basis. That tells you what to write next and what existing content is worth updating.

Order Today

One-time payment, lifetime access. Setup in 30 minutes.

View Pricing
  • Setup and live in 30 minutes
  • 14+ professional themes
  • n8n automation integration
  • Automatic SEO — Sitemap, Schema.org
  • iyzico payment support

Be the first to know

New features, release notes & CMS guides — a couple of emails a month, no spam.