Skip to content

D56 — full-platform telemetry: GA4 + Hotjar on every surface, content masked (3.26.0) - #705

Merged
jacoby149 merged 10 commits into
devfrom
jacoby149/web10-max-tracking-not-privacy
Aug 28, 2026
Merged

D56 — full-platform telemetry: GA4 + Hotjar on every surface, content masked (3.26.0)#705
jacoby149 merged 10 commits into
devfrom
jacoby149/web10-max-tracking-not-privacy

Conversation

@jacoby149

Copy link
Copy Markdown
Owner

What

D56: web10 tracks hard. GA4 + Hotjar on every user-facing surface (marketing-ui, web10-social, the authenticator ui/). Supersedes the old "platform surfaces stay recording-free" rule.

The recording is content-blind by construction: Hotjar initialises with maskAllText: true + blockAllImages: true (text blurred, images blocked — the operator sees cursor + layout + timing, never words or pictures); GA4 events stay content-free by convention (paths, actions, counts — never post text, media URLs, or PII). Max tracking, one exception: GA4 advertising_id: 'OFF' — we do not feed Google's ad network (the only sponsors a fan sees are the creator's, D50/D55). The trade is terms-level, not a consent popup: "it is the wrong platform for you if you arent ok with that."

Why

We compete with Meta and TikTok for the same attention, and their UX is the output of a decade of aggressive telemetry. A node that can't see its own usage is a blog from 2003. The telemetry exists to build the most competitive user experience — for the fan, and for the influencer whose audience it holds.

Changes

  • web10-social: masked Hotjar (canonical static.hotjar.com/c/hotjar-<id>.js?sv=6 snippet + hj('init', {hjid, maskAllText, blockAllImages})); GA4 moves to the max-tracking config (drops anonymize_ip, keeps advertising_id: 'OFF'); hotjarIdentify(username) on login
  • marketing-ui: gains GA4; Hotjar moves from the old script.hotjar.com + hj('initialize', id, version) to the canonical masked init (VITE_HOTJAR_VERSION retired)
  • ui/: new src/lib/analytics.ts (GA4 + masked Hotjar + trackPageview), installed in main.tsx with one pageview per load (query-parameter-driven, no router)
  • deploy: VITE_GA4_MEASUREMENT_ID + VITE_HOTJAR_SITE_ID baked at build time (Dockerfile ARG/ENV x3, compose passes GA4_MEASUREMENT_ID / HOTJAR_SITE_ID per env, empty = off; env examples updated)
  • KB: new knowledge-base/web10-v3/telemetry.md (the why, the use case, the technical how, the line it does not cross, logistics) + README links; D56 in decisions.md; plan.md + platform-telemetry lane
  • tests: new/extended unit suites per app (no-op without env, script load, masking config pinned, idempotency, identify); marketing-ui's existing beacon tests restored + merged

Verification

  • web10-social: 204 tests green, tsc clean, build clean (3 consecutive green runs)
  • marketing-ui: 232 tests green, tsc clean, build clean
  • ui: 116 tests green, tsc clean, build clean

No visual change — tracking is invisible by design (no screenshots applicable).

…otjar on every surface, content masked (3.26.0)

Operator: "ultimate privacy isnt what web10 is about ... we should just put
on max tracking like hotjar the shit out of the whole platform, we can blur
photos and text ... it is the wrong platform for you if you arent ok with
that" — "hotjar and google analytics" — "we do alot of telemetry to
compete with meta tik tok, to have the most competitive user experience."

Every user-facing surface is tracked (GA4 + Hotjar on marketing-ui,
web10-social, and the authenticator ui/). Supersedes the old
"platform surfaces stay recording-free" rule. The recording is
content-blind by construction: Hotjar initialises with maskAllText +
blockAllImages (text blurred, images blocked — cursor + layout + timing,
never words or pictures); GA4 events stay content-free by convention.
Max tracking, one exception: advertising_id OFF (we don't feed Google's
ad network — the only sponsors a fan sees are the creator's, D50/D55).
The trade is terms-level, not a consent popup.

- web10-social: masked Hotjar (canonical static.hotjar.com snippet +
  hj('init', {hjid, maskAllText, blockAllImages})); GA4 moves to the
  max-tracking config (drops anonymize_ip, keeps advertising_id OFF);
  hotjarIdentify(username) on login
- marketing-ui: gains GA4; Hotjar moves from the old script.hotjar.com
  + hj('initialize', id, version) to the canonical masked init
  (VITE_HOTJAR_VERSION retired)
- ui/: new src/lib/analytics.ts (GA4 + masked Hotjar + trackPageview),
  installed in main.tsx with one pageview per load (query-parameter-
  driven, no router)
- deploy: VITE_GA4_MEASUREMENT_ID + VITE_HOTJAR_SITE_ID baked at build
  time (Dockerfile ARG/ENV x3, compose passes GA4_MEASUREMENT_ID /
  HOTJAR_SITE_ID per env, empty = off; env examples updated)
- KB: new knowledge-base/web10-v3/telemetry.md (the why, the use case,
  the technical how, the line it does not cross, logistics) + README
  links; D56 in decisions.md; plan.md + platform-telemetry lane
- tests: new/extended unit suites per app (no-op without env, script
  load, masking config pinned, idempotency, identify); marketing-ui's
  existing beacon tests restored + merged
… — the docs stop reading anti-analytics (3.26.1)

Operator: "can you updated the decisions the knowledge base, everything?
because it as very anti analytics, but now that we arent doing the
encryption privacy angle, we are trying to be influencer friendly, give
them a better deal than these garbo social platforms, it changes the
game!"

The reframe: web10 is a data-policy platform that tracks hard. The
incumbents' UX is the output of a decade of aggressive telemetry, and
web10 now runs the same engine (GA4 + masked Hotjar, D56) with a data
policy they can't offer — content never tracked, never sold, never fed
to the ad machine; the only ads are the creator's (D50/D55).

- thesis.md: new "and it tracks hard (D56)" section — the data-policy
  frame is not a no-telemetry frame; the line (content is never
  tracked; advertising features off; the trade stated in the terms,
  not a consent popup)
- manifesto.md: "nobody is mining you" narrowed to what it was always
  about — the creator's content and the fan's words/pictures are never
  scanned, sold, or fed to an ad machine — plus the candid parenthetical
  (we watch how people use the place, that's how it stays this good)
- AGENTS.md: Telemetry (D56) paragraph in "What web10 is" — the
  operating rule: do not tighten or privacy-wash tracking without
  re-reading D56
- README.md: premise table gains the "Built like the best, owned like
  yours" row
- design.md: self-hosted-fonts rule drops the stale "privacy-first
  product" justification (fonts are a core rendering dependency —
  reliability + control; telemetry scripts are a different category);
  FontAwesome retirement drops the "privacy leak" framing
- plan.md + platform-telemetry lane ticked (3.26.1)
…g-ui) + fix(ui) + docs(kb): telemetry IDs runtime-configurable from the Node Config UI (3.27.0)

Operator: "you need to make it addable from the auth ui right? to change
those ids!"

3.26.0 baked the GA4/Hotjar IDs at build time (Vite env -> Dockerfile
ARG), so changing them required a redeploy. Now the IDs live in
node_config (ClickHouse, same table as every other node setting) and are
resolved at runtime.

- API: NodeConfig + ConfigUpdate gain ga4_measurement_id +
  hotjar_site_id; effective_config() defaults them to ""; new public
  GET /telemetry endpoint (no token — the IDs are public identifiers, not
  secrets; CORS is wildcard so every surface reads it pre-login)
- Auth UI: a Telemetry card in the Node Config panel (GA4 + Hotjar
  inputs, blank = off, applies live on next page load)
- All three surfaces: resolveTelemetryIds() (GET /telemetry; node
  authoritative, build-time env is the dev fallback) + loadGa4/loadHotjar
  (idempotent) + installTelemetry(); the authenticator fires its one
  pageview after GA4 is ready
- Fix (exposed by the feature): the Node Config save was broken —
  saveConfig + saveAdmins sent a flat body but POST /config/update takes
  two body models (token: Token + update: ConfigUpdate) and expects
  {token:{token}, update:{...}}, so every save 422'd. A configUpdate
  helper builds the correct nested shape; pinned by new UI tests

Tests: 5 new API tests + new/extended unit suites per app + new
configTelemetry.test.tsx. 801 API + 205 social + 235 marketing-ui + 122 ui
green, tsc clean, builds clean. KB: telemetry.md updated + D56 addendum.
…v collision

dev assigned its own 3.26.0 (social feed e2e) + 3.26.1 (ad dissemination)
in parallel. Per the union-merge renumber procedure, the already-merged
(dev) entries keep their numbers; mine move to the next free numbers
strictly above dev's max (3.26.1). My 3.27.0 (runtime config) is unchanged.
Updated the [✓ x.y.z] refs in plan.md + the platform-telemetry lane to
match. dev's 3.26.0 feed ref (parallel-execution.md:223) untouched.
…27.3

dev landed 3.26.2 (Trending) + 3.26.1 (ads) in parallel, colliding with my
renumbered 3.26.2/3.26.3. Per the union-merge renumber procedure, dev's
entries keep their numbers; mine move to the next free numbers strictly
above dev's max (3.26.2): telemetry build 3.26.2->3.27.1, positioning
3.26.3->3.27.2, runtime config 3.27.0->3.27.3. Updated the [✓ x.y.z] refs
in plan.md + the platform-telemetry lane. dev's 3.26.2 Trending ref
(parallel-execution.md:228) untouched.
@jacoby149
jacoby149 merged commit 6f8607e into dev Aug 28, 2026
13 checks passed
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