[object Object]

← back to Dw Domain Fleet

gtm: pre-stage GTM container snippet for commercialwallcovering + hollywoodwallcovering

94d2a07caae562dee986f2cb744c3b5b42a066af · 2026-08-17 12:48:38 -0700 · Steve Abrams

- shared/render.js: add gtmHeadSnippet() + gtmNoscript() functions; wire
  both into head() so every page emits the GTM <script> in <head> and the
  <noscript> iframe immediately after <body> — keyed off cfg.gtm per site
- sites/commercialwallcovering.json: add "gtm": "GTM-XXXXXXX" placeholder
- sites/hollywoodwallcovering.json: add "gtm": "GTM-XXXXXXX" placeholder
- server.js: expand CSP to allow www.googletagmanager.com in scriptSrc +
  frameSrc; add google-analytics.com / analytics.google.com to connectSrc

Swap GTM-XXXXXXX -> real container id per site once Steve supplies them.
No deploy — drafted to yolo-queue/pending-approval/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files touched

Diff

commit 94d2a07caae562dee986f2cb744c3b5b42a066af
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Aug 17 12:48:38 2026 -0700

    gtm: pre-stage GTM container snippet for commercialwallcovering + hollywoodwallcovering
    
    - shared/render.js: add gtmHeadSnippet() + gtmNoscript() functions; wire
      both into head() so every page emits the GTM <script> in <head> and the
      <noscript> iframe immediately after <body> — keyed off cfg.gtm per site
    - sites/commercialwallcovering.json: add "gtm": "GTM-XXXXXXX" placeholder
    - sites/hollywoodwallcovering.json: add "gtm": "GTM-XXXXXXX" placeholder
    - server.js: expand CSP to allow www.googletagmanager.com in scriptSrc +
      frameSrc; add google-analytics.com / analytics.google.com to connectSrc
    
    Swap GTM-XXXXXXX -> real container id per site once Steve supplies them.
    No deploy — drafted to yolo-queue/pending-approval/.
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---
 server.js                         |  8 ++++++--
 shared/render.js                  | 30 ++++++++++++++++++++++++++++--
 sites/commercialwallcovering.json |  3 ++-
 sites/hollywoodwallcovering.json  |  3 ++-
 4 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/server.js b/server.js
index 6916029..01ef06e 100644
--- a/server.js
+++ b/server.js
@@ -83,11 +83,15 @@ app.use(helmet({
   contentSecurityPolicy: {
     directives: {
       defaultSrc: ["'self'"],
-      scriptSrc: ["'self'", "'unsafe-inline'"],
+      // 'unsafe-inline' required by GTM and inline theme/promo scripts.
+      // www.googletagmanager.com serves gtm.js + gtag/js (GA4 + GTM).
+      scriptSrc: ["'self'", "'unsafe-inline'", 'https://www.googletagmanager.com'],
       styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
       imgSrc: ["'self'", 'data:', 'https:'],
       fontSrc: ["'self'", 'https://fonts.gstatic.com', 'data:'],
-      connectSrc: ["'self'"],
+      connectSrc: ["'self'", 'https://www.google-analytics.com', 'https://analytics.google.com'],
+      // GTM noscript <iframe src="https://www.googletagmanager.com/ns.html?id=...">
+      frameSrc: ['https://www.googletagmanager.com'],
       frameAncestors: ["'none'"], objectSrc: ["'none'"], baseUri: ["'self'"],
       formAction: ["'self'"], upgradeInsecureRequests: []
     }
diff --git a/shared/render.js b/shared/render.js
index 8380cdc..644f695 100644
--- a/shared/render.js
+++ b/shared/render.js
@@ -460,6 +460,32 @@ function gtagSnippet(mid) {
 <!-- /Google Analytics 4 -->`;
 }
 
+/* gtmHeadSnippet / gtmNoscript — Google Tag Manager injection.
+ * id is sourced from cfg.gtm (per-site JSON field).  When cfg.gtm is absent
+ * or empty these return '' so non-GTM sites are unaffected.
+ * Swap GTM-XXXXXXX for the real container id once Steve supplies it.
+ *
+ * gtmHeadSnippet goes inside <head> (as high as possible — placed just before
+ * the closing </head> tag, after GA4 and the anti-flash script).
+ * gtmNoscript goes as the FIRST child after <body> (Google requirement). */
+function gtmHeadSnippet(id) {
+  if (!id) return '';
+  return `<!-- Google Tag Manager -->
+<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
+new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
+j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
+'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
+})(window,document,'script','dataLayer','${id}');</script>
+<!-- End Google Tag Manager -->`;
+}
+function gtmNoscript(id) {
+  if (!id) return '';
+  return `<!-- Google Tag Manager (noscript) -->
+<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${id}"
+height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
+<!-- End Google Tag Manager (noscript) -->`;
+}
+
 function head(cfg, title, desc, path, canonicalOverride, bodyClass) {
   const url = 'https://' + cfg.domain + (path || '');
   const canonical = canonicalOverride || url;
@@ -474,10 +500,10 @@ function head(cfg, title, desc, path, canonicalOverride, bodyClass) {
 <meta property="og:url" content="${esc(url)}">
 <meta name="twitter:card" content="summary_large_image">
 <meta name="twitter:title" content="${esc(title)}"><meta name="twitter:description" content="${esc(desc)}">
-${gtagSnippet(cfg.ga4)}<style>:root{--top-fg:#fff}</style>
+${gtagSnippet(cfg.ga4)}${gtmHeadSnippet(cfg.gtm)}<style>:root{--top-fg:#fff}</style>
 <script>(function(){var s=localStorage.getItem('${cfg.slug}_theme');if(s)document.documentElement.dataset.theme=s;})();</script>
 <style>${css(cfg)}</style>
-</head><body${bodyClass ? ` class="${esc(bodyClass)}"` : ''}>`;
+</head><body${bodyClass ? ` class="${esc(bodyClass)}"` : ''}>${gtmNoscript(cfg.gtm)}`;
 }
 
 function jsonld(cfg) {
diff --git a/sites/commercialwallcovering.json b/sites/commercialwallcovering.json
index d634598..4925356 100644
--- a/sites/commercialwallcovering.json
+++ b/sites/commercialwallcovering.json
@@ -31,5 +31,6 @@
     "palette": "slate",
     "font": "cormorant"
   },
-  "ga4": "G-22TD8SY6L4"
+  "ga4": "G-22TD8SY6L4",
+  "gtm": "GTM-XXXXXXX"
 }
\ No newline at end of file
diff --git a/sites/hollywoodwallcovering.json b/sites/hollywoodwallcovering.json
index 96ef499..199f728 100644
--- a/sites/hollywoodwallcovering.json
+++ b/sites/hollywoodwallcovering.json
@@ -32,5 +32,6 @@
     "palette": "gilt",
     "font": "bodoni"
   },
-  "ga4": "G-ZSCWGG7FZW"
+  "ga4": "G-ZSCWGG7FZW",
+  "gtm": "GTM-XXXXXXX"
 }
\ No newline at end of file

← aebcb81 GA4: inject gtag via render.js head() + ga4 IDs for commerci  ·  back to Dw Domain Fleet  ·  Fleet: keep showroom-only vendors (Phillip Jeffries) out of 3161f75 →