diff --git a/scripts/build-site.mjs b/scripts/build-site.mjs index 3b9d0cc..fbbc084 100644 --- a/scripts/build-site.mjs +++ b/scripts/build-site.mjs @@ -18,6 +18,10 @@ const SITE_NAME = "CoreVideo"; // Cloudflare hosts. The token is public by design (it ships in every page). const ANALYTICS_BEACON = ` \n`; +// Initialize the data layer before loading the container. The site's CSP +// requires the initializer to be served as a separate script. +const GOOGLE_TAG_MANAGER = ` + `; const OG_IMAGE = `${PRIMARY_ORIGIN}/assets/corevideo-share.jpg`; const OG_IMAGE_ALT = "CoreVideo - Zoom participant video and audio as native OBS Studio sources"; @@ -923,6 +927,7 @@ function layout(page, content, options = {}) { +${GOOGLE_TAG_MANAGER} ${escapeHtml(fullTitle)} @@ -1310,6 +1315,7 @@ const DOCS_DESCRIPTION = const DOCS_CANONICAL = canonicalUrl("documentation/index.html"); const docsHtml = fs.readFileSync(path.join(docsDir, "index.html"), "utf8") + .replace(/()/i, `$1\n${GOOGLE_TAG_MANAGER}`) .replaceAll("iamfatness.github.io/CoreVideo", publicDocumentationUrl ? new URL("/documentation", publicDocumentationUrl).host + "/documentation" : "CoreVideo documentation") @@ -1355,6 +1361,11 @@ writeText( fs.readFileSync(path.join(siteAssetsDir, "docs-init.js"), "utf8"), ); +writeText( + "assets/google-tag-manager.js", + fs.readFileSync(path.join(siteAssetsDir, "google-tag-manager.js"), "utf8"), +); + // Bundled application fonts (Space Grotesk + IBM Plex Mono), self-hosted so // the CSP font-src 'self' policy allows them. const fontsSource = path.join(siteAssetsDir, "fonts"); diff --git a/site-assets/google-tag-manager.js b/site-assets/google-tag-manager.js new file mode 100644 index 0000000..cb30f8c --- /dev/null +++ b/site-assets/google-tag-manager.js @@ -0,0 +1,5 @@ +window.dataLayer = window.dataLayer || []; +function gtag() { + window.dataLayer.push(arguments); +} +gtag('js', new Date()); diff --git a/site-worker.js b/site-worker.js index 9d662a2..3916e17 100644 --- a/site-worker.js +++ b/site-worker.js @@ -2,7 +2,10 @@ import { handleReviewFeedback } from './review-feedback.js'; const SECURITY_HEADERS = { "content-security-policy": - "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; script-src 'self' https://cdn.jsdelivr.net https://static.cloudflareinsights.com; connect-src 'self' https://cloudflareinsights.com; font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'", + "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; " + + "script-src 'self' https://cdn.jsdelivr.net https://static.cloudflareinsights.com https://www.googletagmanager.com; " + + "connect-src 'self' https://cloudflareinsights.com https://www.googletagmanager.com https://*.google-analytics.com https://*.google.com; " + + "font-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'", "referrer-policy": "strict-origin-when-cross-origin", "x-content-type-options": "nosniff", }; diff --git a/wiki/Privacy-Policy.md b/wiki/Privacy-Policy.md index 5da5f92..ea2f0d3 100644 --- a/wiki/Privacy-Policy.md +++ b/wiki/Privacy-Policy.md @@ -1,6 +1,6 @@ # Privacy Policy -_Last updated: September 2026_ +_Last updated: November 2026_ ## Overview @@ -109,6 +109,14 @@ The documentation site at `corevideo.io` is served through Cloudflare and source - [Cloudflare Privacy Policy](https://www.cloudflare.com/privacypolicy/) - [GitHub Privacy Statement](https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement) +### Google Analytics (Website) + +The public pages on `corevideo.io` use Google Analytics through Google Tag +Manager to measure site usage, including page views. Google Analytics may use +cookies to distinguish visits. See [how Google uses information from sites that +use its services](https://policies.google.com/technologies/partner-sites) and the +[Google Analytics opt-out browser add-on](https://tools.google.com/dlpage/gaoptout). + --- ## Data Retention