[object Object]

← back to Prestige Car Wash

Analytics: GA4 gtag injection on customer pages, gated on GA_MEASUREMENT_ID (inert until set, format-validated, admin untracked)

10e7bf17ce3fed0181ee80d481e857625ebe4bec · 2026-07-26 16:38:48 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit 10e7bf17ce3fed0181ee80d481e857625ebe4bec
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Sun Jul 26 16:38:48 2026 -0700

    Analytics: GA4 gtag injection on customer pages, gated on GA_MEASUREMENT_ID (inert until set, format-validated, admin untracked)
---
 server.js | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/server.js b/server.js
index 4963f5a..fc44e82 100644
--- a/server.js
+++ b/server.js
@@ -473,11 +473,21 @@ function buildSocialTags(html, pagePath) {
 // Built fresh per request (sync file read + one string replace = microseconds) so the
 // injected JSON-LD/OG NEVER drift from live places.json — a stale NAP is the exact thing
 // Google penalizes, which would defeat the point of injecting it. (contrarian gate, 2026-07-26)
+// GA4 gtag snippet — injected on the customer pages ONLY when GA_MEASUREMENT_ID is set
+// (a valid G-XXXX id). No-op until then, so this is safe to ship before the id exists.
+// Admin (internal) is intentionally NOT tracked as customer traffic.
+function gaSnippet() {
+  const id = process.env.GA_MEASUREMENT_ID;
+  if (!id || !/^G-[A-Z0-9]{6,}$/.test(id)) return '';
+  return `\n<script async src="https://www.googletagmanager.com/gtag/js?id=${id}"></script>` +
+         `\n<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','${id}');</script>`;
+}
 function pageHtml(file, pagePath, ld) {
   const html = fs.readFileSync(path.join(__dirname, 'public', file), 'utf8');
   let inject = buildSocialTags(html, pagePath);
   // escape "<" so the JSON can't break out of the <script> tag
   if (ld) inject += `\n<script type="application/ld+json">${JSON.stringify(ld).replace(/</g, '\\u003c')}</script>`;
+  inject += gaSnippet();
   return html.replace('</head>', inject + '\n</head>');
 }
 const sendPage = (res, file, pagePath, ld) => {

← aa47ccf SEO: broaden OG/Twitter + per-page canonical to /services +  ·  back to Prestige Car Wash  ·  chore: v0.3.1 (session close — LHF/SWOT/Slideshow) 39653bd →