{"id":453,"date":"2026-09-09T08:45:00","date_gmt":"2026-09-09T06:45:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/?p=453"},"modified":"2026-08-19T10:27:50","modified_gmt":"2026-08-19T08:27:50","slug":"ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/","title":{"rendered":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions"},"content":{"rendered":"\r\n<p class=\"wp-block-paragraph\">Tracking e-commerce events in Single-Page Applications (SPAs) built with React, Vue, or Next.js presents unique architectural challenges. Because standard browser page loads do not occur during route transitions, traditional DOM-ready or window-loaded tracking triggers fail. Furthermore, asynchronous component rendering frequently introduces DataLayer race conditions: Google Tag Manager (GTM) tags may execute before e-commerce payload objects are fully populated, or stale transaction data from previous routes may persist and pollute subsequent events. Implementing a deterministic, race-condition-free GA4 e-commerce tracking architecture ensures data precision across the entire checkout funnel.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">1. Architectural Root Causes of SPA Tracking Failures<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Race conditions in SPAs typically originate from three structural antipatterns:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>Missing Ecommerce Payload Resets:<\/strong> GA4 e-commerce tags merge new dataLayer pushes with existing objects. If an old <code>ecommerce<\/code> object is not explicitly cleared, items from previous views duplicate across subsequent events.<\/li>\r\n<li><strong>History Change Trigger Dependency:<\/strong> Relying on GTM History Change triggers for virtual pageviews often fires tags before asynchronous API endpoints have returned product pricing or cart state.<\/li>\r\n<li><strong>Unordered Event Dispatching:<\/strong> Pushing state changes and tracking events in separate, uncoordinated JavaScript execution blocks creates non-deterministic tag firing orders.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<figure class=\"lw-diagram\">\n<img loading=\"lazy\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/ga4-spa-datalayer-sequence-en.png\" width=\"1120\" height=\"650\" decoding=\"async\"\n     alt=\"Sequence diagram of the dataLayer pushes in a single-page app, from route change through reset and atomic push to the GA4 event\">\n<figcaption>Time runs downwards: reset, then one single push carrying event and payload together. Splitting the two is what lets the tag fire against the previous object.<\/figcaption>\n<\/figure>\n\n<h2 class=\"wp-block-heading\">2. Step-by-Step Implementation of Deterministic DataLayer Pushes<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">To guarantee thread-safe dataLayer communication in frontend frameworks, e-commerce pushes must follow a strict three-step execution pattern:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li><strong>Explicit Object Clearing:<\/strong> Every e-commerce push must be immediately preceded by a reset command setting <code>ecommerce: null<\/code>. This flushes GTM internal data models.<\/li>\r\n<li><strong>Atomic Event and Payload Bundling:<\/strong> Never push the data payload and the trigger event separately. Always bundle the custom event name and the full <code>ecommerce<\/code> object within a single atomic push.<\/li>\r\n<li><strong>Framework State Synchronization:<\/strong> In React or Next.js, encapsulate tracking calls inside side-effect hooks (such as <code>useEffect<\/code>) with explicit dependency arrays, ensuring tags fire only after DOM hydration and state resolution are complete.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Production-Ready TypeScript \/ Vanilla JS Pattern<\/h3>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code class=\"language-javascript\">\/**\r\n * Safely dispatches a GA4 e-commerce event without race conditions.\r\n * @param {string} eventName - GA4 event name (e.g., 'add_to_cart', 'purchase').\r\n * @param {Object} ecommercePayload - The standardized GA4 ecommerce object.\r\n *\/\r\nfunction dispatchGa4EcommerceEvent(eventName, ecommercePayload) {\r\n  window.dataLayer = window.dataLayer || [];\r\n\r\n  \/\/ Step 1: Flush stale e-commerce data to prevent merge collisions\r\n  window.dataLayer.push({ ecommerce: null });\r\n\r\n  \/\/ Step 2: Atomic push of event and payload\r\n  window.dataLayer.push({\r\n    event: eventName,\r\n    ecommerce: ecommercePayload\r\n  });\r\n}\r\n\r\n\/\/ Example usage within a React checkout component:\r\n\/\/ dispatchGa4EcommerceEvent('add_to_cart', {\r\n\/\/   currency: 'EUR',\r\n\/\/   value: 129.99,\r\n\/\/   items: [{ item_id: 'SKU_441', item_name: 'Enterprise Router', price: 129.99, quantity: 1 }]\r\n\/\/ });<\/code><\/pre>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">3. Step-by-Step Google Tag Manager (GTM) Configuration<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Frontend code reliability must be mirrored by a defensive GTM container configuration:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li><strong>Custom Event Triggers Only:<\/strong> Avoid <code>All Pages<\/code> or <code>History Change<\/code> triggers for e-commerce. Create custom event triggers explicitly matching GA4 event names (e.g., <code>add_to_cart<\/code>, <code>begin_checkout<\/code>, <code>purchase<\/code>).<\/li>\r\n<li><strong>Data Layer Variable Setup:<\/strong> Define a Data Layer Variable named <code>dlv - ecommerce<\/code> pointing to the key <code>ecommerce<\/code>. Ensure the default value is undefined.<\/li>\r\n<li><strong>GA4 Event Tag Mapping:<\/strong> Configure the GA4 Event Tag to use the Custom Event trigger. Under <em>More Settings &gt; E-commerce<\/em>, check <code>Send Ecommerce data<\/code> and select <code>Data Layer<\/code> as the data source.<\/li>\r\n<li><strong>Tag Sequencing Enforcement:<\/strong> For critical conversion events like <code>purchase<\/code>, utilize GTM Tag Sequencing to ensure consent management platform (CMP) updates or user-id attribution tags complete firing before the transaction tag executes.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">4. Summary &amp; Architectural Value<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\"><strong>What this tutorial achieves:<\/strong> The deployment of a deterministic, race-condition-free Google Analytics 4 e-commerce tracking architecture tailored for Single-Page Applications (React, Vue, Next.js), utilizing atomic payload resetting and Custom Event bundling.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\"><strong>Resulting value:<\/strong> E-commerce analytics datasets become strictly accurate and reproducible. Revenue inflation caused by stale dataLayer merges is permanently eliminated, and missing cart or checkout funnel steps due to asynchronous component rendering are prevented. Consequently, performance marketing attribution and algorithmic bidding strategies receive clean, verified conversion signals.<\/p>\r\n\n\n<div class=\"lw-quellen\">\n<h2>Sources<\/h2>\n<ul>\n<li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/ga4\/reference\/events\" target=\"_blank\" rel=\"noopener noreferrer\">Google Analytics 4 event reference<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\" target=\"_blank\" rel=\"noopener noreferrer\">MDN Web Docs<\/a><\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>A technical tutorial on implementing deterministic, race-condition-free GA4 e-commerce tracking in Single-Page Applications (React, Vue, Next.js).<\/p>\n","protected":false},"author":1,"featured_media":14013,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[113],"tags":[91339,91258,91267,91312,91342,91516,91219],"class_list":["post-453","post","type-post","status-publish","format-standard","hentry","category-tutorials","tag-e-commerce","tag-google-analytics-4","tag-google-tag-manager","tag-javascript","tag-single-page-application","tag-tracking","tag-tutorial"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"A technical tutorial on implementing deterministic, race-condition-free GA4 e-commerce tracking in Single-Page Applications (React, Vue, Next.js).\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-09T06:45:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"luky\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"luky\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/\"},\"author\":{\"name\":\"luky\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions\",\"datePublished\":\"2026-09-09T06:45:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/\"},\"wordCount\":534,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png\",\"keywords\":[\"E-Commerce\",\"Google Analytics 4\",\"Google Tag Manager\",\"JavaScript\",\"Single-Page Application\",\"Tracking\",\"Tutorial\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/\",\"name\":\"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png\",\"datePublished\":\"2026-09-09T06:45:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png\",\"width\":1200,\"height\":630,\"caption\":\"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"],\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/author\\\/luky\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/","og_locale":"en_US","og_type":"article","og_title":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions - Lukas Wojcik - Blog","og_description":"A technical tutorial on implementing deterministic, race-condition-free GA4 e-commerce tracking in Single-Page Applications (React, Vue, Next.js).","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-09-09T06:45:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png","type":"image\/png"}],"author":"luky","twitter_card":"summary_large_image","twitter_misc":{"Written by":"luky","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/"},"author":{"name":"luky","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions","datePublished":"2026-09-09T06:45:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/"},"wordCount":534,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png","keywords":["E-Commerce","Google Analytics 4","Google Tag Manager","JavaScript","Single-Page Application","Tracking","Tutorial"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/","name":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png","datePublished":"2026-09-09T06:45:00+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-453-ga4-e-commerce-enhanced-tracking-spa-g.png","width":1200,"height":630,"caption":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/ga4-e-commerce-enhanced-tracking-spas-without-datalayer-race-conditions-en\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"GA4 E-Commerce Enhanced Tracking in SPAs without DataLayer Race Conditions"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"],"url":"https:\/\/www.lukaswojcik.com\/blog\/author\/luky\/"}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/453","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=453"}],"version-history":[{"count":2,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/453\/revisions"}],"predecessor-version":[{"id":11865,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/453\/revisions\/11865"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/14013"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=453"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=453"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=453"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}