feat: add privacy policy; wire GA4 and Umami at build time
CI / ci (push) Successful in 2m13s

- /privacy/ page covering the contact form (Formspree), Umami, GA4 and
  server logs; linked from the footer
- Analytics.astro: GA4 alongside Umami, both limited to the production
  host so staging and local builds are not counted
- Dockerfile ARGs + CI build args from repo Actions variables
  GA_MEASUREMENT_ID and UMAMI_WEBSITE_ID (non-secret)
This commit is contained in:
bmr_bluecap committed 2026-10-23 13:49:56 -04:00
1 parent 375ee48ab1
commit 0c2b4a6ac6
7 files changed
+154 -8

No files matched your search

+26 -5
View File
@@ -1,15 +1,19 @@
---
/**
* Side-by-side visitor analytics (ADR-0005): PostHog + Umami, each gated by env vars so this is a
* no-op until configured. Set the PUBLIC_* vars at build time to enable either or both.
* Side-by-side visitor analytics, each gated by env vars so this is a no-op until configured.
* Set the PUBLIC_* vars at build time (Dockerfile ARGs, fed by CI) to enable any of them.
* - Umami: PUBLIC_UMAMI_SRC (script URL), PUBLIC_UMAMI_WEBSITE_ID — self-hosted, cookieless
* - GA4: PUBLIC_GA_MEASUREMENT_ID (G-XXXXXXXXXX)
* - PostHog: PUBLIC_POSTHOG_KEY, PUBLIC_POSTHOG_HOST (default https://us.i.posthog.com)
* - Umami: PUBLIC_UMAMI_SRC (script URL), PUBLIC_UMAMI_WEBSITE_ID
* Track the same event set in both to compare (see docs/seo-aeo-optimization.md §6b).
* Umami and GA4 only fire on the production host, so staging/LAN/local visits are not counted.
* Anything enabled here must be disclosed on /privacy/.
*/
const posthogKey = import.meta.env.PUBLIC_POSTHOG_KEY;
const posthogHost = import.meta.env.PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com";
const umamiSrc = import.meta.env.PUBLIC_UMAMI_SRC;
const umamiWebsiteId = import.meta.env.PUBLIC_UMAMI_WEBSITE_ID;
const gaId = import.meta.env.PUBLIC_GA_MEASUREMENT_ID;
const prodHost = new URL(import.meta.env.PUBLIC_SITE_URL ?? "https://www.bluecapstrategies.com").hostname;
---
{
@@ -23,6 +27,23 @@ const umamiWebsiteId = import.meta.env.PUBLIC_UMAMI_WEBSITE_ID;
{
umamiSrc && umamiWebsiteId && (
<script is:inline defer src={umamiSrc} data-website-id={umamiWebsiteId} />
<script is:inline defer src={umamiSrc} data-website-id={umamiWebsiteId} data-domains={prodHost} />
)
}
{
gaId && (
<script is:inline define:vars={{ gaId, prodHost }}>
if (location.hostname === prodHost) {
window.dataLayer = window.dataLayer || [];
window.gtag = function () { window.dataLayer.push(arguments); };
window.gtag("js", new Date());
window.gtag("config", gaId);
var s = document.createElement("script");
s.async = true;
s.src = "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(gaId);
document.head.appendChild(s);
}
</script>
)
}