{"id":10134,"date":"2026-09-13T07:52:00","date_gmt":"2026-09-13T05:52:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=10134"},"modified":"2026-10-26T11:42:01","modified_gmt":"2026-10-26T10:42:01","slug":"tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/","title":{"rendered":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM"},"content":{"rendered":"<p>Server-side GTM provides control over the processing and destinations of measurement requests. Routing browser events through a tagging server and sending confirmed purchases from the shop backend are separate changes. Neither guarantees complete analytics: consent, missing identifiers, duplicate events, failed delivery and reporting definitions still matter.<\/p>\n<p id=\"gtm-update-20261019\"><strong>Update \u2014 19.10.2026:<\/strong> The endpoint examples now distinguish standalone gtag.js, GTM and optimized destination tags. Container optimization does not itself migrate measurement to a tagging server; the actual request URL remains the decisive check. <a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/google-tag-manager-and-gtag-js-merge-what-changes-in-2026\/\">The October changes to Google tag and GTM<\/a>.<\/p>\n<p>The migration starts with a separate test destination, preserves a rollback path and uses order-level reconciliation before production cutover.<\/p>\n<figure class=\"lw-diagram\"><img decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/dia-10134-migration-20261024.png\" width=\"1120\" height=\"580\" loading=\"lazy\" alt=\"A controlled migration separates routing, backend delivery and order reconciliation. No route guarantees complete analytics.\"><figcaption>A controlled migration separates routing, backend delivery and order reconciliation. No route guarantees complete analytics.<\/figcaption><\/figure>\n<h2>1. Comparison criteria<\/h2>\n<p>The existing production route remains active while the new route sends to a separate test property. Sending both copies into the same production property can inflate events and revenue; a matching transaction ID is not a general deduplication mechanism for every event or destination.<\/p>\n<p>The test property needs comparable timezone, currency, event definitions, filters and relevant links. Two to four weeks can be a useful initial observation period, but the required duration depends on purchase cycles, traffic and delayed payments. Acceptance criteria should cover missing and duplicated orders, amounts, consent behavior and failed requests, not merely a higher purchase total.<\/p>\n<h2>2. The complete server environment<\/h2>\n<p>GTM offers automatic Cloud Run provisioning. A manual deployment needs both a preview server and a production tagging service. Both use the same container configuration; the preview service uses <code>RUN_AS_PREVIEW_SERVER=true<\/code>, and the tagging service receives its HTTPS address through <code>PREVIEW_SERVER_URL<\/code>. Google&#8217;s manual setup guide contains the complete deployment sequence. A single tagging-service command would omit the preview infrastructure.<\/p>\n<p>Other compatible Docker environments are possible, but networking, credentials, scaling, health checks and image updates remain operational responsibilities. Capacity must be tested against actual traffic. Publishing a GTM workspace updates container configuration; it does not replace the runtime image.<\/p>\n<p>A same-site subdomain or same-origin route can provide first-party context. A generated cloud hostname can still receive events but is not first-party to the shop. DNS, TLS, CSP and the actual request route need verification. A custom hostname does not make browser blocking or cookie limits disappear.<\/p>\n<h2>3. Receiving client and outgoing tag<\/h2>\n<p>A client must claim the incoming request and turn the supported payload into event data. The preinstalled Google Analytics client handles the supported Google tag format. Other protocols require an appropriate client. A receiving client alone does not deliver data to GA4: a server-side destination tag and its trigger must also be configured.<\/p>\n<p>Client activation settings, Google-script serving and the browser&#8217;s destination are different controls. The browser must explicitly route measurement requests to the server. Consent settings and transformations must survive the entire path; browser-only variables do not automatically exist in the server container.<\/p>\n<h2>4. Routing the existing web installation<\/h2>\n<p>In GTM, <code>server_container_url<\/code> belongs to the Google tag or Google Analytics destination tag according to the installed configuration. In an existing standalone gtag.js setup, the equivalent setting is part of the existing configuration command:<\/p>\n<figure style=\"--cbb-digits:1\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"javascript\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">JavaScript<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-javascript\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-function\">gtag<\/span>(<span class=\"cbb-string\">'config'<\/span>, <span class=\"cbb-string\">'G-XXXXXXXXXX'<\/span>, {\n<\/span><span class=\"cbb-line\">  server_container_url: <span class=\"cbb-string\">'https:\/\/sgtm.shop.example.com'<\/span>\n<\/span><span class=\"cbb-line\">});<\/span><\/code><\/pre><\/figure>\n<p>The measurement ID and endpoint are placeholders. This fragment neither installs gtag.js nor configures GTM. Adding a second configuration call can alter page-view behavior; the existing setup and its page-view policy should be updated deliberately.<\/p>\n<p>A browser network check confirms the actual endpoint. Server preview then checks the claiming client, event data, consent state, transformations and outgoing tag. Finally, the test destination confirms receipt. A successful response at the tagging server alone does not prove that GA4 processed the event.<\/p>\n<h2>5. Backend purchases as a separate integration<\/h2>\n<p>A backend event can be triggered by a confirmed order without waiting for the confirmation page to render. The analytics integration still needs permitted collection, valid data and reliable delivery. A longer-lived identifier does not itself extend a GA4 session.<\/p>\n<p>The backend sender should use a documented interface. Direct GA4 Measurement Protocol uses HTTPS POST to <code>\/mp\/collect<\/code>, a web-stream measurement ID and private API secret in the URL, and a JSON body with <code>client_id<\/code> and events. This direct route bypasses the tagging container. Routing a backend payload through sGTM instead requires a deliberately configured receiving client, supported payload format, authentication strategy and destination mapping. Replacing the hostname of a JSON Measurement Protocol request is not enough to prove compatibility with the built-in client.<\/p>\n<p>For matching an online visit, permitted client and session identifiers should come from the actual measurement context, not from an assumed cookie string layout. Missing identifiers require an explicit policy; fabricating a matching session would produce misleading attribution. For direct Measurement Protocol session attribution, Google&#8217;s documented time and session constraints also apply, including a request within 24 hours of session start and an event timestamp within that session.<\/p>\n<ol><li>The purchase trigger is explicitly defined: for example a confirmed paid order, not every order-status update.<\/li><li>A durable delivery record stores a unique order\/event key, occurrence time, currency, item data and the applicable consent context.<\/li><li>Purchase data is validated; value and item amounts must use the agreed tax, shipping and discount definition.<\/li><li>Current permission is checked before sending, including later withdrawal where applicable. Backend sending is not a substitute for consent handling.<\/li><li>Delivery outcomes are recorded; failures are handled through a bounded queue and explicit retry policy. A timeout means no response arrived in time. The recipient may still have received the event, so a retry needs protection against counting it twice.<\/li><\/ol>\n<p>Each order needs a stable, nonempty <code>transaction_id<\/code>. GA4 documents purchase deduplication for web streams; this is not a universal exactly-once guarantee across app streams, advertising destinations or custom exports. After cutover, one component should own the production purchase event. A browser and backend overlap belongs in the isolated test design.<\/p>\n<p>For direct Measurement Protocol, validation at <code>\/debug\/mp\/collect<\/code> checks payload structure without adding events to reports. A production <code>2xx<\/code> response confirms HTTP receipt, not successful analytics processing. Secrets belong on the server and should be excluded from logs and browser code.<\/p>\n<h2>6. Reconciliation and cutover<\/h2>\n<p>Comparison starts with the same eligible order population, date boundaries, currencies and revenue definition. Excluded consent states, delayed payments and refunds require separate explanations. Higher counts alone are not evidence of better data. The tools below support order-level checks.<\/p>\n<p>Cutover changes one production route at a time, disables the redundant production purchase sender and monitors delivery errors, duplicates, attribution and costs. The previous configuration remains available for rollback, with a plan to avoid replaying already delivered purchases.<\/p>\n<div class=\"lw-gtm-related\" id=\"gtm-related-links-20261020\" style=\"margin:20px 0;color:var(--text-secondary);line-height:1.6;\"><p><strong>Related guides and tools:<\/strong><\/p><ul><li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/google-tag-gateway-what-it-changes-in-a-measurement-request-and-how-it-differs-from-server-side-tagging\/\">Google tag gateway and server-side tagging<\/a> \u2013 first-party routing, payloads and their different roles.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/csp-header-generator-tracking-linter\/\">CSP Header Generator<\/a> \u2013 preparing provider and endpoint permissions.<\/li><\/ul><\/div><div class=\"lw-faq\"><h2>Questions and answers<\/h2><h3>Is the shop&#8217;s own subdomain enough to stop Safari from shortening the cookie set by the server container?<\/h3><p>No. An own subdomain alone guarantees neither full cookie lifetime nor exemption from tracking prevention. WebKit caps response-cookie expiry for detected third-party CNAME or IP-address cloaking. A route through the site&#8217;s infrastructure can change the applicable conditions, but it does not establish an unconditional lifetime guarantee. Verification needs the actual DNS and request path, Set-Cookie attributes and the browser&#8217;s policy; GTM container optimization changes none of those automatically.<\/p><\/div><div class=\"lw-quellen\">\n<h2>Sources<\/h2>\n<ul>\n<li><a href=\"https:\/\/developers.google.com\/tag-platform\/tag-manager\/server-side\" rel=\"noopener noreferrer\" target=\"_blank\">Google Tag Manager: Server-side tagging<\/a><\/li>\n<li><a href=\"https:\/\/developers.google.com\/tag-platform\/tag-manager\" rel=\"noopener noreferrer\" target=\"_blank\">Google Tag Manager documentation<\/a><\/li>\n<li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/ga4\/ecommerce\" rel=\"noopener noreferrer\" target=\"_blank\">Google Analytics: Ecommerce events<\/a><\/li>\n<li><a href=\"https:\/\/support.google.com\/tagmanager\/answer\/4620708?hl=en\">Google Tag Manager: release notes, 8 and 12 October 2026<\/a><\/li><li><a href=\"https:\/\/support.google.com\/tagmanager\/answer\/17079602?hl=en\">Google tag and Tag Manager: unified configuration<\/a><\/li><li><a href=\"https:\/\/support.google.com\/tagmanager\/answer\/17231523?hl=en\">Google tag: supported installation methods<\/a><\/li><li><a href=\"https:\/\/support.google.com\/tagmanager\/answer\/15756616?hl=en\">Google tag in Tag Manager: setup and initialization<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/tag-platform\/tag-manager\/server-side\/send-data\">Server-side Tag Manager: send data<\/a><\/li><li><a href=\"https:\/\/webkit.org\/tracking-prevention\/\">WebKit: Tracking Prevention<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/tag-platform\/tag-manager\/server-side\/manual-setup-guide\">Google Tag Manager: Manual server-side setup<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/protocol\/ga4\/sending-events\">Google Analytics: Send Measurement Protocol events<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/protocol\/ga4\/reference\">Google Analytics: Measurement Protocol reference<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/protocol\/ga4\/use-cases\">Google Analytics: Measurement Protocol use cases<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/protocol\/ga4\/validating-events\">Google Analytics: Validate Measurement Protocol events<\/a><\/li><li><a href=\"https:\/\/support.google.com\/analytics\/answer\/12313109?hl=en\">Google Analytics: Minimize duplicate key events with transaction IDs<\/a><\/li><li><a href=\"https:\/\/developers.google.com\/tag-platform\/tag-manager\/server-side\/consent-mode\">Google Tag Manager: Implement consent mode with server-side tagging<\/a><\/li><\/ul>\n<\/div><p><!-- lw-analytics-reconcile-guide:start --><\/p>\n<h2>Practical check: reconcile orders with the shop export<\/h2>\n<p>The <a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/shop-ga4-revenue-reconciliation\/\">Shop vs. GA4 Revenue Reconciliation tool<\/a> compares two CSV files locally. The order ID is the join key. Customer names, email addresses and contact details are unnecessary for this comparison: an order ID, amount and currency are enough.<\/p>\n<ol>\n<li>Both exports use the same period and timezone, with the same treatment of tax, shipping and refunds. Line items and refunds are combined into one agreed amount per order before comparison.<\/li>\n<li>Each file is loaded with its separator and decimal mark. The order ID, amount and currency columns are mapped to the comparison fields. Identifiers with leading zeros remain text.<\/li>\n<li>Decimal precision and an explicit per-order tolerance are selected. Currency conversion is not performed.<\/li>\n<li>The review covers the separate groups: missing on either side, duplicate ID, different currency and amount outside tolerance.<\/li>\n<li>The result can be exported for investigation of individual orders in the source systems.<\/li>\n<\/ol>\n<p>Duplicate IDs are flagged rather than added together: a repeated purchase event, an item-level export and a refund row require different interpretations. Negative amounts are accepted only as numbers; the business definition still has to agree between files. A missing Analytics order can reflect consent, timing, filtering or collection failures and is not by itself proof of a faulty tag. A zero difference also does not establish that all orders were exported. The tool never combines totals across currencies.<\/p>\n<p>Definitions should follow the chosen export and the <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/collection\/ga4\/ecommerce\" target=\"_blank\" rel=\"noopener noreferrer\">GA4 ecommerce documentation<\/a>. The <a href=\"https:\/\/developers.google.com\/analytics\/devguides\/reporting\/data\/v1\/api-schema\" target=\"_blank\" rel=\"noopener noreferrer\">Data API schema<\/a> distinguishes transaction IDs and revenue metrics; a generic total-revenue column is not automatically equivalent to a shop&#8217;s order amount.<\/p>\n<p><!-- lw-analytics-reconcile-guide:end --><\/p>\n<p><!-- lw-revenue-export-guide:start --><\/p>\n<h2>Preparing the Analytics CSV from BigQuery<\/h2>\n<p>The <a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/shop-ga4-revenue-reconciliation\/#aw-export-helper\">export helper in the revenue reconciliation tool<\/a> generates a purchase query for an existing daily GA4 export. Project, dataset, dates and rounding precision are entered locally. The page does not run the SQL or request BigQuery access.<\/p>\n<p>The resulting columns <code>transaction_id<\/code>, <code>amount<\/code> and <code>currency<\/code> match the comparison fields. Each recorded purchase remains a row. An additional purchase-event count helps identify repeated transaction IDs; these are not silently summed or discarded. A missing amount is not replaced with zero.<\/p>\n<ol>\n<li>The purchase-amount definition and reporting-day boundaries are agreed before the shop file is created. This query excludes refunds and does not add tax or shipping separately.<\/li>\n<li>The generated SQL is validated in BigQuery and its cost estimate checked. A maximum bytes billed limit is set before execution.<\/li>\n<li>The complete results are saved as a local CSV and loaded with comma-separated fields and decimal dot, using the same precision as the query.<\/li>\n<li>Repeated IDs and missing fields are checked before amount differences are interpreted. The comparison accepts up to 20,000 data rows per file. Identifiers remain text in spreadsheet software.<\/li>\n<\/ol>\n<p>Two downloadable invented CSV files provide a reproducible first test, with one case in each of the six result groups. They are independent of the SQL and use two decimals with zero tolerance.<\/p>\n<p>References: <a href=\"https:\/\/support.google.com\/analytics\/answer\/7029846?hl=en\">GA4 export schema<\/a>, <a href=\"https:\/\/docs.cloud.google.com\/bigquery\/docs\/running-queries\">query validation and cost controls<\/a>, and <a href=\"https:\/\/docs.cloud.google.com\/bigquery\/docs\/export-file\">saving query results as CSV<\/a>.<\/p>\n<p><!-- lw-revenue-export-guide:end --><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A staged e-commerce migration to server-side GTM with an isolated test destination, explicit backend purchase delivery and order-by-order reconciliation. Browser routing and backend delivery are separate changes.<\/p>\n","protected":false},"author":1,"featured_media":13836,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[113],"tags":[91339,91258,91267,91061,91219],"class_list":["post-10134","post","type-post","status-publish","format-standard","hentry","category-tutorials","tag-e-commerce","tag-google-analytics-4","tag-google-tag-manager","tag-server-side-gtm","tag-tutorial"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.\" \/>\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\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-13T05:52:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-26T10:42:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-10134-tutorial-migrating-e-commerce-analyt-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=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:description\" content=\"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 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\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM\",\"datePublished\":\"2026-09-13T05:52:00+00:00\",\"dateModified\":\"2026-10-26T10:42:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/\"},\"wordCount\":1782,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png\",\"keywords\":[\"E-Commerce\",\"Google Analytics 4\",\"Google Tag Manager\",\"Server-Side GTM\",\"Tutorial\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/\",\"name\":\"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png\",\"datePublished\":\"2026-09-13T05:52:00+00:00\",\"dateModified\":\"2026-10-26T10:42:01+00:00\",\"description\":\"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png\",\"width\":1200,\"height\":630,\"caption\":\"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/digital-analytics\\\/tutorials\\\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM\"}]},{\"@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\":\"Lukas Wojcik\",\"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\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM | Lukas Wojcik","description":"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.","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\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/","og_locale":"en_US","og_type":"article","og_title":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM | Lukas Wojcik","og_description":"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-09-13T05:52:00+00:00","article_modified_time":"2026-10-26T10:42:01+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_description":"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM","datePublished":"2026-09-13T05:52:00+00:00","dateModified":"2026-10-26T10:42:01+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/"},"wordCount":1782,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png","keywords":["E-Commerce","Google Analytics 4","Google Tag Manager","Server-Side GTM","Tutorial"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/","name":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png","datePublished":"2026-09-13T05:52:00+00:00","dateModified":"2026-10-26T10:42:01+00:00","description":"Migrating e-commerce measurement to server-side GTM: GA4 client, explicit server_container_url, preview and parallel verification.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-10134-tutorial-migrating-e-commerce-analyt-g.png","width":1200,"height":630,"caption":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/digital-analytics\/tutorials\/tutorial-migrating-e-commerce-analytics-from-client-side-to-server-side-gtm\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Tutorial: Migrating E-Commerce Analytics from Client-Side to Server-Side GTM"}]},{"@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":"Lukas Wojcik","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":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/10134","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=10134"}],"version-history":[{"count":10,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/10134\/revisions"}],"predecessor-version":[{"id":27574,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/10134\/revisions\/27574"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/13836"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=10134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=10134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=10134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}