Magento 2: GTM dataLayer undefined on KnockoutJS (checkout) page — sessionStorage data empty, how to track checkout/purchase/payment events reliably?

I’m implementing Google Tag Manager (GTM) enhanced ecommerce tracking on a Magento 2 store and facing critical issues specifically on KnockoutJS-rendered pages (like checkout). Despite all setup being done correctly, the GTM events are not firing, and window.dataLayer shows as undefined on the checkout page.

✅ Requirements
I want to track the following 3 GTM events reliably using sessionStorage for data transport between pages:

  1. Checkout Event — Trigger on clicking “Checkout” in the Mini Cart

Parameters and Datatypes:

EMAIL – text

Product ID – int

Product Name – text

produrl – text

Product Category – text

Product Price MRP – int

Product Price Selling price – int

SKU – text

Payment Method – text

Cart Total – int

Discount coupon used – text

  1. Purchase Event — On reaching Thank You page

(Same data fields as above)

  1. Payment Event — When clicking “Pay Now” or “Proceed to Pay” button

(Same data fields as above)

🚨 The Problem
GTM base code is loaded (confirmed in view source of checkout page).

window.dataLayer is undefined on the checkout page, so GTM can’t receive data.

sessionStorage item gtm_event_data is being set, but all fields (like email, items, cart_total) are empty or zero.

Other pages like Home, PLP successfully populate gtmCartProducts and product-level data.

GTM Preview/Debug shows no event firing for checkout.

🧪 What I’ve Tried So Far
✅ Added ViewModels to render GTM payloads on checkout page via layout XML

✅ Verified GTM base code is present in source

✅ Stored data in sessionStorage on Mini Cart “Checkout” button click

✅ Used inline scripts to push from sessionStorage into window.dataLayer

✅ Delayed dataLayer.push() using window.addEventListener(‘load’)

❌ Still get window.checkoutGTMData = undefined

❌ Still get window.dataLayer = undefined

❌ Still see sessionStorage.getItem(‘gtm_event_data’) = null or empty object

🔍 Suspected Root Issues
Magento 2’s KnockoutJS checkout rendering may delay or sandbox GTM script execution.

Inline scripts with dataLayer.push fail due to Knockout rendering timing.

Custom ViewModel isn’t injected early enough (or gets null dependencies).

GTM is possibly not initialized properly on dynamic checkout layout.

🛠️ What I’m Looking For
A fully working and KnockoutJS-compatible solution to:

Reliably store all GTM parameters for the checkout, payment, and purchase events using sessionStorage (before checkout page load).

Trigger the dataLayer.push() after the checkout page is fully rendered, even if GTM is slow or Knockout interferes.

Ensure window.dataLayer is initialized and GTM is listening on checkout and thank you pages.

📌 Extra Info
Magento version: 2.x

GTM base code: Added via Magento backend config

Module used: Custom module Whiteteak_GtmEvents

Knockout element selector used for Checkout:

💬 Any ideas or proven implementations for this GTM Knockout timing issue?
Would appreciate working code snippets or alternative approaches that don’t rely on brittle timing hacks. I’m open to ViewModels, RequireJS, or even raw JS solutions — as long as it works 100% for Magento’s Knockout-based checkout.