Skip to content

Docs analytics: one funnel with coderhelm.com, nothing typed sent; self-host stays analytics-free - #224

Merged
nambok merged 1 commit into
mainfrom
feat/docs-analytics
Oct 26, 2026
Merged

nambok merged 1 commit into
mainfrom
feat/docs-analytics

Conversation

@nambok

@nambok nambok commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

docs.coderhelm.com, including the install guide, had no analytics. It now sends to the coderhelm.com property (G-T14Q1LDRC0), so the site, the docs and the install guide form one funnel. Nothing typed, nothing after ? or #, no email, region or install name is ever sent, and a test runs Google's real tag to check every hit. The install guide's trust line now says this. Self-hosted builds stay analytics-free; the dashboard did not check for that before, and now it does. Paired with CoderHelm/coderhelm-platform#307 (trust model wording).

Changes

Docs (docs/lib/analytics.ts, docs/components/analytics.tsx)

  • The tag loads only on docs.coderhelm.com, never on localhost, previews or a self-hosted docs build. It loads when the browser is idle or on the first interaction.
  • Page views fire on the first load and on every client-side navigation. page_location is origin plus path. Setting it in config also stops the tag's own history page views, so each page counts once.
  • Events: docs_search (once per open, no query), copy_markdown, copy_code, outbound_click (link_domain only, with AWS regions removed), install_step (the step name only).
  • Every hit passes through scrubHit() on its way out (sendBeacon, fetch or image):
    • URL values are cut to origin plus path, and AWS regions are removed.
    • Emails, search terms and form fields (form_destination and the like) are dropped.
    • Page views this code did not send are dropped.
    • This covers what Google's enhanced measurement adds. The real tag was seen sending form_destination before scrubbing.
  • Linker set with coderhelm.com and docs.coderhelm.com. Google signals and ad personalization are off. GA4 always anonymizes IPs, so anonymize_ip does nothing and is not set. The marketing site has no consent banner, so the docs have none either.

Install guide

  • The trust line comes from GUIDE_TRUST:
    • Private: "This page talks to AWS, GitHub and your own CoderHelm, and counts anonymous page views with Google Analytics. Nothing you type and nothing about your install is sent to CoderHelm or Google."
    • Hybrid: the same, with CoderHelm's name check. That line does not say nothing typed is sent, because the name you check does go to CoderHelm.
    • The Markdown twin and the marketing self-host page say the same.
  • "Install name" is now "Name in your AWS account". It has the new help text and the rule in one sentence: "Use 1 to 20 lowercase letters, digits or hyphens, starting with a letter." "What happens in AWS" and "What is happening" name the stack from it.
    • The default stays prod. Every resource name is coderhelm-<name>, so coderhelm would give coderhelm-coderhelm-* and a stack called coderhelm-coderhelm. The launch template's Stage default, the terminal installer and the docs (--stage prod, coderhelm/prod/...) all use prod.

CSP (infra/lib/docs-csp.json)

  • Both docs policies add https://www.googletagmanager.com to script-src. They add https://*.google-analytics.com https://*.analytics.google.com https://www.googletagmanager.com to connect-src and img-src. Everything else is unchanged.
  • The site and app CSPs listed only www.google-analytics.com and analytics.google.com. GA4 also sends to regional hosts (region1.google-analytics.com), so they now use the same wildcard hosts.

Dashboard (google-analytics.tsx)

  • No tag on a self-hosted install (isSelfHosted()) or on any host but app.coderhelm.com. Before, every self-hosted dashboard loaded CoderHelm's tag.
  • The first page view was lost: the effect ran before the tag's script defined gtag. gtag is now defined before the first call, so the call is queued.
  • Page views on route changes send origin plus path. Google signals are off.
  • The self-host CI job also runs the new spec.

Site: linker with the docs, Google signals and ad personalization off.

Verification

  • docs: unit 76/76 (new scripts/analytics.test.mjs), build, typecheck, check:links (4163 links, none broken), check:output (88 pages), e2e 80/80.
    • New e2e/analytics.spec.ts: Google's real gtag.js runs on https://docs.coderhelm.com under the production CSP, with hits answered locally.
    • No hit may carry a URL with a query string or fragment, the email typed, the setup key, the progress id, param_ or the region. This holds after the reader types into the form, launches and clicks the AWS link, whose address carries the email and setup key.
    • One page view per page, client-side navigation counted, no CSP violations, nothing loads on localhost.
  • infra: 27/27, including a new test for the site and app GA4 hosts. cdk synth is clean.
  • dashboard: UI lint, typecheck, build. Full e2e 1008/1008, including the new google-analytics.spec.ts: page views on first load and route change, origin plus path only, no tag when self-hosted or on localhost.
  • site: lint has 0 errors (8 warnings, none in these files). Build is clean.
  • Screenshots of the trust line at 1440 and 390, private and hybrid, and More options at 1440 and 390, taken locally.

… ? sent; self-host stays analytics-free

- docs: Google Analytics (G-T14Q1LDRC0) on docs.coderhelm.com only, loaded
  on idle or first interaction; page views on every client-side navigation;
  events for search used, Copy Markdown, copy code, outbound host and install
  guide step. Every hit passes a scrubber: URLs cut to origin and path, AWS
  regions, emails, search terms and form fields dropped, the tag's own
  history page views dropped. Linker with coderhelm.com; Google signals and
  ad personalization off.
- Install guide: the trust line says anonymous page views go to Google
  Analytics and nothing typed is sent; an e2e runs Google's real tag and
  holds every hit to it. "Install name" is now "Name in your AWS account",
  with plain help and a one-sentence rule; the default stays prod.
- CSP: both docs policies allow googletagmanager.com scripts and GA4 hosts;
  site and app connect-src now allow GA4's regional hosts.
- Dashboard: no tag on a self-hosted install or any host but
  app.coderhelm.com; the first page view is no longer lost; addresses sent
  without query strings.
- Site: linker with the docs, signals off; the self-host page says what the
  guide sends.
@nambok
nambok merged commit 6529830 into main Oct 26, 2026
5 checks passed
@nambok
nambok deleted the feat/docs-analytics branch October 26, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant