[object Object]

← back to CelebritySignatures

AdSense onboarding: add /privacy policy page + site-wide footer link (celebsignatures.com)

4bbb6283b64fbe9371dfbe888c917c57d809bf23 · 2026-08-05 15:00:13 -0700 · Steve

Privacy policy discloses the 4 real data touchpoints (AdSense pub-5278231299883833,
GA4 G-2HEVP6TD0J, Stripe payments, first-party auth/localStorage) with ad/analytics
opt-out links — the missing-privacy-policy gap was the one blocker to AdSense approval.
Footer injected server-side at the injectAds chokepoint so the policy is linked on
every page (Google requires a discoverable policy).

Files touched

Diff

commit 4bbb6283b64fbe9371dfbe888c917c57d809bf23
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Aug 5 15:00:13 2026 -0700

    AdSense onboarding: add /privacy policy page + site-wide footer link (celebsignatures.com)
    
    Privacy policy discloses the 4 real data touchpoints (AdSense pub-5278231299883833,
    GA4 G-2HEVP6TD0J, Stripe payments, first-party auth/localStorage) with ad/analytics
    opt-out links — the missing-privacy-policy gap was the one blocker to AdSense approval.
    Footer injected server-side at the injectAds chokepoint so the policy is linked on
    every page (Google requires a discoverable policy).
---
 public/privacy.html | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 server.js           |  17 ++++++++-
 2 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/public/privacy.html b/public/privacy.html
new file mode 100644
index 0000000..3da57df
--- /dev/null
+++ b/public/privacy.html
@@ -0,0 +1,108 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Privacy Policy · CelebritySignatures</title>
+<meta name="description" content="Privacy policy for celebsignatures.com — what we collect, how advertising and analytics cookies are used, payment processing, and your choices.">
+<link rel="canonical" href="https://celebsignatures.com/privacy">
+<style>
+  :root{--bg:#f7f5f0;--card:#fff;--ink:#1a1a1a;--line:#e6e3dc;--muted:#6b6b6b}
+  *{box-sizing:border-box}
+  body{margin:0;background:var(--bg);color:var(--ink);font:400 16px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
+  .wrap{max-width:760px;margin:0 auto;padding:40px 20px 80px}
+  header a.home{color:var(--muted);text-decoration:none;font:600 12px/1 -apple-system,sans-serif;letter-spacing:.14em;text-transform:uppercase}
+  header a.home:hover{color:var(--ink)}
+  h1{font-size:30px;font-weight:700;margin:22px 0 4px}
+  .eff{color:var(--muted);font-size:13px;margin-bottom:28px}
+  h2{font-size:19px;font-weight:700;margin:34px 0 8px}
+  p,li{color:#2a2a2a}
+  a{color:#1a5490}
+  ul{padding-left:20px}
+  .card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:20px 24px;margin-top:22px}
+  code{background:#efece5;padding:1px 6px;border-radius:5px;font-size:14px}
+  footer.pp{margin-top:40px;padding-top:20px;border-top:1px solid var(--line);color:var(--muted);font-size:13px}
+</style>
+</head>
+<body>
+<div class="wrap">
+  <header><a class="home" href="/">← CelebritySignatures</a></header>
+  <h1>Privacy Policy</h1>
+  <div class="eff">Effective 5 August 2026 · celebsignatures.com</div>
+
+  <p>This Privacy Policy explains what information CelebritySignatures ("we", "us")
+  collects when you use <strong>celebsignatures.com</strong> (the "Site"), how we use it,
+  and the choices you have. By using the Site you agree to this policy.</p>
+
+  <h2>1. Information we collect</h2>
+  <ul>
+    <li><strong>Account information</strong> — if you create an account, we store the email
+      address and password (hashed) you provide, and any signatures or content you upload or
+      save to your account.</li>
+    <li><strong>Usage &amp; device data</strong> — standard server logs (IP address, browser
+      type, pages requested, timestamps) generated automatically when you visit.</li>
+    <li><strong>Cookies &amp; local storage</strong> — a first-party session cookie to keep
+      you signed in, and browser <code>localStorage</code> to remember display preferences and
+      game high scores on your device. Third-party cookies set by the services in Sections 3–5.</li>
+  </ul>
+
+  <h2>2. How we use information</h2>
+  <ul>
+    <li>To operate the Site, sign you in, and save your content and preferences.</li>
+    <li>To process mural and signature-file orders you place.</li>
+    <li>To understand aggregate usage and improve the Site.</li>
+    <li>To display advertising that helps keep the Site free.</li>
+  </ul>
+
+  <h2>3. Advertising (Google AdSense)</h2>
+  <p>We use <strong>Google AdSense</strong> (publisher ID <code>pub-5278231299883833</code>) to
+  serve advertisements. Third-party vendors, including Google, use cookies to serve ads based on
+  your prior visits to this and other websites. Google's use of advertising cookies enables it
+  and its partners to serve ads to you based on your visits to this and/or other sites on the
+  Internet.</p>
+  <p>You may opt out of personalized advertising by visiting
+  <a href="https://www.google.com/settings/ads" rel="noopener noreferrer" target="_blank">Google Ads Settings</a>.
+  You can opt out of a third-party vendor's use of cookies for personalized advertising at
+  <a href="https://www.aboutads.info/choices/" rel="noopener noreferrer" target="_blank">aboutads.info</a>
+  or <a href="https://optout.networkadvertising.org/" rel="noopener noreferrer" target="_blank">NAI opt-out</a>.
+  For more on how Google uses data, see
+  <a href="https://policies.google.com/technologies/partner-sites" rel="noopener noreferrer" target="_blank">Google's partner-sites policy</a>.</p>
+
+  <h2>4. Analytics (Google Analytics)</h2>
+  <p>We use <strong>Google Analytics 4</strong> (measurement ID <code>G-2HEVP6TD0J</code>) to
+  measure aggregate, anonymized usage of the Site. Google Analytics sets cookies to distinguish
+  users and sessions. You can install the
+  <a href="https://tools.google.com/dlpage/gaoptout" rel="noopener noreferrer" target="_blank">Google Analytics Opt-out Browser Add-on</a>
+  to prevent this data collection.</p>
+
+  <h2>5. Payments (Stripe)</h2>
+  <p>Purchases (murals and signature files) are processed by <strong>Stripe</strong>. When you
+  check out, your payment-card details are entered directly with Stripe and are handled under
+  <a href="https://stripe.com/privacy" rel="noopener noreferrer" target="_blank">Stripe's Privacy Policy</a>.
+  We do not store your full card number on our servers.</p>
+
+  <h2>6. Your choices &amp; data requests</h2>
+  <p>You can clear cookies and local storage in your browser at any time, and opt out of
+  personalized ads and analytics using the links above. To access, correct, or delete the
+  personal information associated with your account, email us at
+  <a href="mailto:info@designerwallcoverings.com">info@designerwallcoverings.com</a> and we will
+  respond within a reasonable time.</p>
+
+  <h2>7. Third-party links</h2>
+  <p>The Site links to external sources (e.g. Wikimedia Commons and museum collections). Those
+  sites have their own privacy practices, which we do not control.</p>
+
+  <h2>8. Children</h2>
+  <p>The Site is not directed to children under 13, and we do not knowingly collect personal
+  information from them.</p>
+
+  <h2>9. Changes</h2>
+  <p>We may update this policy from time to time. Material changes will be reflected by the
+  "Effective" date above.</p>
+
+  <h2>10. Contact</h2>
+  <p>Questions about this policy? Email
+  <a href="mailto:info@designerwallcoverings.com">info@designerwallcoverings.com</a>.</p>
+</div>
+</body>
+</html>
diff --git a/server.js b/server.js
index fc3d9f2..65188cd 100644
--- a/server.js
+++ b/server.js
@@ -90,8 +90,22 @@ const AD_SLOTS = { gallery: (envVal('ADSENSE_SLOT_GALLERY') || '').trim(), artic
 const ADSENSE_CONFIG = ADSENSE_TAG
   ? `<script>window.__ADPUB=${JSON.stringify('ca-' + ADSENSE_PUB_ID)};window.__ADSLOTS=${JSON.stringify(AD_SLOTS)};</script><script src="/assets/ads.js" defer></script>`
   : '';
-const injectAds = html => (ADSENSE_TAG && typeof html === 'string' && html.includes('</head>') && !html.includes('adsbygoogle.js'))
+const _injectAdTags = html => (ADSENSE_TAG && typeof html === 'string' && html.includes('</head>') && !html.includes('adsbygoogle.js'))
   ? html.replace('</head>', ADSENSE_TAG + ADSENSE_CONFIG + '\n</head>') : html;
+// Site-wide footer — injected before </body> on every HTML response so the
+// AdSense-required Privacy Policy link is discoverable on every page (Google
+// rejects sites whose policy isn't linked). Kept in the ad chokepoint so all
+// four page-serving call sites inherit it with no per-site edits.
+const FOOTER = '<footer class="site-footer" style="margin:40px 0 0;padding:22px 16px;border-top:1px solid #e6e3dc;background:#f7f5f0;color:#6b6b6b;font:400 13px/1.7 -apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,sans-serif;text-align:center">'
+  + '<div>© 2026 CelebritySignatures · celebsignatures.com</div>'
+  + '<nav style="margin-top:6px"><a href="/" style="color:#6b6b6b;text-decoration:none">Home</a> · '
+  + '<a href="/game" style="color:#6b6b6b;text-decoration:none">Game</a> · '
+  + '<a href="/murals" style="color:#6b6b6b;text-decoration:none">Murals</a> · '
+  + '<a href="/privacy" style="color:#6b6b6b;text-decoration:none">Privacy Policy</a> · '
+  + '<a href="mailto:info@designerwallcoverings.com" style="color:#6b6b6b;text-decoration:none">Contact</a></nav></footer>';
+const injectFooter = html => (typeof html === 'string' && html.includes('</body>') && !html.includes('site-footer'))
+  ? html.replace('</body>', FOOTER + '\n</body>') : html;
+const injectAds = html => injectFooter(_injectAdTags(html));
 if (ADSENSE_TAG) { const live = Object.entries(AD_SLOTS).filter(([, v]) => v).map(([k]) => k); console.log(`AdSense active (${ADSENSE_PUB_ID}) — reserved zones live: ${live.length ? live.join(', ') : 'none yet (awaiting slot ids)'}`); }
 // 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).
@@ -620,6 +634,7 @@ ${museums.length ? `<div class="sec">In the collections of</div><div class="meta
 
     if (path.startsWith('/assets/')) path = '/public' + path;
     if (path === '/favicon.ico') path = '/public/assets/favicon.png';
+    if (path === '/privacy' || path === '/privacy.html') path = '/public/privacy.html';
     if (path === '/account.js') path = '/public/account.js';
     if (path === '/api/murals-catalog') path = '/data/murals-catalog.json';
     if (path === '/api/signature-evolution') path = '/data/signature-evolution.json';

← 7cd0f6a chore: fix game tagline (Five→Six ways), add version 1.0.0 (  ·  back to CelebritySignatures  ·  backend: add POST /api/auth/delete (Apple 5.1.1(v) account d 77c8879 →