← back to CelebritySignatures
AdSense Auto-ads integration (Steve request 2026-08-04): loader injected into every HTML response + /ads.txt route, both driven by ONE env var ADSENSE_PUB_ID (pub-XXXX, ca- prefix tolerated). No-ops safely when unset (0 loaders, ads.txt 404). Auto ads = no per-slot IDs; Google places units. Ready the instant a publisher id is set — needs an AdSense account + site approval (Steve-gated) (TK-10181)
6db34b04f31cba312771cd8d85af41d3c78d3e5e · 2026-08-04 10:53:10 -0700 · Steve Abrams
Files touched
Diff
commit 6db34b04f31cba312771cd8d85af41d3c78d3e5e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 4 10:53:10 2026 -0700
AdSense Auto-ads integration (Steve request 2026-08-04): loader injected into every HTML response + /ads.txt route, both driven by ONE env var ADSENSE_PUB_ID (pub-XXXX, ca- prefix tolerated). No-ops safely when unset (0 loaders, ads.txt 404). Auto ads = no per-slot IDs; Google places units. Ready the instant a publisher id is set — needs an AdSense account + site approval (Steve-gated) (TK-10181)
---
server.js | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/server.js b/server.js
index cd7b0bd..2a9f80c 100644
--- a/server.js
+++ b/server.js
@@ -72,6 +72,18 @@ const STRIPE_MURAL_KEY = STRIPE_LIVE ? _liveKey : _testKey;
const STRIPE_DOWNLOAD_KEY = _testKey;
const STRIPE_MODE = STRIPE_LIVE ? 'live' : 'test';
if (STRIPE_LIVE) console.log('⚠️ STRIPE LIVE MODE — murals charge REAL cards; downloads stay TEST'); else if (_testKey) console.log('Stripe test mode active (murals + downloads)');
+// ---- Google AdSense (Auto ads) ---------------------------------------------
+// Driven by ONE env var, ADSENSE_PUB_ID (stored as `pub-XXXXXXXXXXXXXXXX`; a
+// leading `ca-` is tolerated). When set, the loader is injected into every HTML
+// response and /ads.txt is served; when unset, everything no-ops so nothing
+// broken renders. Auto ads means Google places units itself — no per-slot IDs.
+const ADSENSE_PUB_ID = (envVal('ADSENSE_PUB_ID') || '').trim().replace(/^ca-/, '');
+const ADSENSE_TAG = /^pub-\d{10,}$/.test(ADSENSE_PUB_ID)
+ ? `<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-${ADSENSE_PUB_ID}" crossorigin="anonymous"></script>`
+ : '';
+const injectAds = html => (ADSENSE_TAG && typeof html === 'string' && html.includes('</head>') && !html.includes('adsbygoogle.js'))
+ ? html.replace('</head>', ADSENSE_TAG + '\n</head>') : html;
+if (ADSENSE_TAG) console.log(`AdSense Auto ads active (${ADSENSE_PUB_ID})`);
// Atomic in-process guard against concurrent double-credit for the same paid session
// (claimed synchronously before any await; the download-ledger is the restart-surviving backstop).
const USED_SIDS = new Set();
@@ -348,7 +360,7 @@ ${paid ? `<div class="ok">✓</div><h1>Order confirmed</h1>
<a class="btn" href="/murals">${paid ? 'Design another wall' : 'Back to the studio'}</a>
<p style="margin-top:20px"><a href="/">← Celebrity Signatures</a></p></div></body></html>`;
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
- res.end(body); return;
+ res.end(injectAds(body)); return;
}
// ===== CELEBRITY SIGNATURE UPLOADS (owned + commission-tracked) =====
@@ -571,7 +583,7 @@ ${museums.length ? `<div class="sec">In the collections of</div><div class="meta
<p style="margin-top:26px"><a href="/">← Browse all ${(await mergedSignatures()).length.toLocaleString()} signatures</a></p>
</div></body></html>`;
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'public, max-age=3600' });
- res.end(html); return;
+ res.end(injectAds(html)); return;
}
if (path === '/sitemap.xml' && M === 'GET') {
const sigs = await mergedSignatures();
@@ -587,6 +599,14 @@ ${museums.length ? `<div class="sec">In the collections of</div><div class="meta
res.end('User-agent: *\nAllow: /\nSitemap: https://celebsignatures.com/sitemap.xml\n');
return;
}
+ // AdSense ads.txt — required for the account to be authorized to serve ads.
+ // Served only once a publisher id is configured (else 404, so no broken file).
+ if (path === '/ads.txt' && M === 'GET') {
+ if (!ADSENSE_PUB_ID) { res.writeHead(404, { 'Content-Type': 'text/plain' }).end('not found'); return; }
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
+ res.end(`google.com, ${ADSENSE_PUB_ID}, DIRECT, f08c47fec0942fa0\n`);
+ return;
+ }
if (path.startsWith('/assets/')) path = '/public' + path;
if (path === '/favicon.ico') path = '/public/assets/favicon.png';
@@ -606,7 +626,13 @@ ${museums.length ? `<div class="sec">In the collections of</div><div class="meta
let html = await readFile(file, 'utf8');
html = html.replace('</body>', '<script src="/account.js"></script>\n</body>');
res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache' });
- res.end(html); return;
+ res.end(injectAds(html)); return;
+ }
+ // HTML pages: serve as text so the AdSense loader can be injected into <head>.
+ if (extname(file) === '.html') {
+ const html = await readFile(file, 'utf8');
+ res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache' });
+ res.end(injectAds(html)); return;
}
const body = await readFile(file);
← ea2f10b Live switch is now MURAL-ONLY (Steve go-live 2026-08-04): pe
·
back to CelebritySignatures
·
Accept rk_live_ restricted keys for the live Stripe key (lea 87f0e4a →