Skip to content

Optional Gizmo Analytics integration (cookieless web analytics)#54

Open
sudomichael wants to merge 2 commits into
webdevcody:mainfrom
sudomichael:add-gizmo-analytics
Open

Optional Gizmo Analytics integration (cookieless web analytics)#54
sudomichael wants to merge 2 commits into
webdevcody:mainfrom
sudomichael:add-gizmo-analytics

Conversation

@sudomichael

@sudomichael sudomichael commented May 18, 2026

Copy link
Copy Markdown

Heads up

Noticed the README's note about not adding things without prior approval — happy to close this if it's not a fit. Keeping the surface minimal: 3 files, ~15 lines, no new dependencies (script loads from CDN), and fully opt-in (gated on NEXT_PUBLIC_GIZMO_KEY — leaving it unset disables the integration entirely).

Summary

Adds Gizmo Analytics as a second analytics option alongside PostHog. Gizmo is cookieless and privacy-friendly, so no cookie banner is required under CNIL / EDPB guidance — useful as a complement to PostHog for kits where the user wants basic traffic analytics without consent infrastructure.

Changes

  • src/env.tsNEXT_PUBLIC_GIZMO_KEY registered as z.string().optional() in the client schema + runtimeEnv, following the existing t3-env pattern.
  • src/app/layout.tsx<Script> mounted conditionally when env.NEXT_PUBLIC_GIZMO_KEY is present. Uses afterInteractive strategy so it doesn't compete with LCP.
  • .env.sample — New section with comment + signup link.

Test plan

  • Key unset → no script tag in HTML, no network request
  • Key set → script loads after interactive, pageview fires
  • pnpm build succeeds, type check clean
  • PostHog integration untouched

Happy to adjust naming, placement, or close this if it's outside the kit's scope.

Summary by CodeRabbit

  • New Features
    • Added optional Gizmo Analytics integration that can be enabled by setting the public Gizmo key; if unset, analytics remain disabled.
  • Chores
    • Updated environment sample to include the new optional Gizmo Analytics key and inline documentation for enabling/disabling the integration.

Review Change Stack

Cookieless web analytics, gated on NEXT_PUBLIC_GIZMO_KEY so it's
fully opt-in. Leaving the env var unset disables the integration
entirely — no script renders, no network request.

- src/env.ts: NEXT_PUBLIC_GIZMO_KEY as z.string().optional() in
  the client schema + runtimeEnv
- src/app/layout.tsx: <Script> mounted only when the key is set;
  uses afterInteractive strategy
- .env.sample: new section with explanatory comment

No new dependencies (script loads from CDN). No required config.

https://gizmoanalytics.io
@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83c19121-584f-4720-8552-04548bb6b22b

📥 Commits

Reviewing files that changed from the base of the PR and between bffa030 and 257da25.

📒 Files selected for processing (1)
  • src/env.ts

📝 Walkthrough

Walkthrough

This PR adds optional Gizmo Analytics integration: NEXT_PUBLIC_GIZMO_KEY is defined in the env schema and sample, and the app root layout conditionally injects the Gizmo analytics script only when that key is set.

Changes

Gizmo Analytics Integration

Layer / File(s) Summary
Environment variable schema and sample configuration
src/env.ts, .env.sample
NEXT_PUBLIC_GIZMO_KEY is added to the client environment schema as z.string().min(1).optional(), mapped into runtimeEnv from process.env, and included in .env.sample with a blank placeholder and comment to disable if unset.
Analytics script injection in app layout
src/app/layout.tsx
env and Next Script are imported in the root layout; a <Script src="https://gizmoanalytics.io/script.js" strategy="afterInteractive" /> is rendered only when env.NEXT_PUBLIC_GIZMO_KEY is present.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant NextLayout
  participant RuntimeEnv
  participant GizmoCDN
  Browser->>NextLayout: load page (client)
  NextLayout->>RuntimeEnv: read NEXT_PUBLIC_GIZMO_KEY
  alt key present
    NextLayout->>GizmoCDN: inject <Script src="https://gizmoanalytics.io/script.js">
    GizmoCDN-->>Browser: deliver analytics script
  else key absent
    NextLayout-->>Browser: do not inject script
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A Gizmo key hops into view,
Optional, quiet, and light as dew,
The layout asks, "Shall I load you?"
If set, a script will skip right through,
Hooray — analytics, just for you! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding an optional Gizmo Analytics integration. It accurately reflects the changeset across all three files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/app/layout.tsx (2)

87-87: ⚡ Quick win

Consider lazyOnload strategy for non-critical analytics.

The afterInteractive strategy loads the script after the page becomes interactive, which can still impact Core Web Vitals. For analytics that don't need immediate execution, strategy="lazyOnload" defers loading until browser idle time, improving performance metrics. This is a common pattern for third-party analytics.

⚡ Proposed optimization
-            strategy="afterInteractive"
+            strategy="lazyOnload"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/layout.tsx` at line 87, The analytics Script currently uses
strategy="afterInteractive" which can affect Core Web Vitals; locate the Script
element in src/app/layout.tsx (the one with strategy="afterInteractive") and
change its strategy prop to "lazyOnload" so the analytics script is deferred
until the browser is idle; ensure the Script import/usage (Script component and
its strategy prop) is updated accordingly and verify that any analytics that
require immediate execution are not relying on this script before switching.

84-89: Consider adding Subresource Integrity (SRI) verification to the external analytics script.

The script is loaded from gizmoanalytics.io, which is confirmed as the official domain for Gizmo Analytics, a privacy-friendly, cookieless analytics service. However, the script lacks Subresource Integrity (SRI) verification. While not critical for analytics, adding an integrity hash would improve security against potential CDN compromise. If feasible, retrieve the expected hash from Gizmo Analytics and add an integrity attribute to the Script component.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/layout.tsx` around lines 84 - 89, The external <Script> inclusion of
Gizmo Analytics in layout.tsx lacks Subresource Integrity: update the Script JSX
(the Script component that uses src="https://gizmoanalytics.io/script.js" and
data-key={env.NEXT_PUBLIC_GIZMO_KEY}) to include an integrity attribute with the
official SRI hash from Gizmo Analytics and add crossorigin="anonymous" so the
browser can verify the resource; obtain the correct SHA384/sha256 SRI value from
Gizmo Analytics/CSP provider and add it as integrity="sha...".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/env.ts`:
- Line 35: The env schema currently allows empty strings for
NEXT_PUBLIC_GIZMO_KEY because it uses z.string().optional(); update the
validation for the NEXT_PUBLIC_GIZMO_KEY field in the schema (in src/env.ts) to
require a non-empty string when present (e.g., change to a string with min(1)
and keep optional) so empty values are rejected and you won't render a Script
with an empty data-key.

---

Nitpick comments:
In `@src/app/layout.tsx`:
- Line 87: The analytics Script currently uses strategy="afterInteractive" which
can affect Core Web Vitals; locate the Script element in src/app/layout.tsx (the
one with strategy="afterInteractive") and change its strategy prop to
"lazyOnload" so the analytics script is deferred until the browser is idle;
ensure the Script import/usage (Script component and its strategy prop) is
updated accordingly and verify that any analytics that require immediate
execution are not relying on this script before switching.
- Around line 84-89: The external <Script> inclusion of Gizmo Analytics in
layout.tsx lacks Subresource Integrity: update the Script JSX (the Script
component that uses src="https://gizmoanalytics.io/script.js" and
data-key={env.NEXT_PUBLIC_GIZMO_KEY}) to include an integrity attribute with the
official SRI hash from Gizmo Analytics and add crossorigin="anonymous" so the
browser can verify the resource; obtain the correct SHA384/sha256 SRI value from
Gizmo Analytics/CSP provider and add it as integrity="sha...".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b53d4c99-811e-4249-93a8-b5e809cd89e5

📥 Commits

Reviewing files that changed from the base of the PR and between f77845a and bffa030.

📒 Files selected for processing (3)
  • .env.sample
  • src/app/layout.tsx
  • src/env.ts

Comment thread src/env.ts Outdated
z.string().optional() allowed empty strings through, which would
render <Script data-key="" />. Tighten to .min(1).optional() so
an explicitly-empty key is rejected; absent key remains the
disable path. Suggested by CodeRabbit on webdevcody#54.
@sudomichael

Copy link
Copy Markdown
Author

Thanks for the review @coderabbitai — addressed:

1. Reject empty NEXT_PUBLIC_GIZMO_KEY strings: pushed 257da25z.string().min(1).optional(). Empty string would have rendered <Script data-key="" /> which is broken. Good catch.

2. strategy="lazyOnload" vs afterInteractive: keeping afterInteractive. The kit's existing PostHog integration loads as the default (no <Script> strategy at all), and the Gizmo tracker is ~1KB — switching just this one tracker to lazyOnload would diverge from the kit's pattern without a real Web Vitals win at that size. Open to changing if @webdevcody prefers.

3. SRI integrity hash: skipping intentionally. gizmoanalytics.io/script.js is built per-deployment (config gets baked in), so a static SRI hash would break every consumer on every release. None of the major web-analytics trackers (Plausible, Umami, PostHog, GA, Fathom) publish SRI hashes for this reason. Documented expectation in the upstream docs.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@sudomichael Thanks for the detailed follow-ups!

  1. Empty string validation ✅ — z.string().min(1).optional() is exactly right. Confirmed fix looks good.

  2. afterInteractive strategy — Agreed. Matching the kit's existing PostHog pattern is the right call. At ~1KB the timing difference is negligible, and consistency within the codebase matters more here.

  3. SRI hash — The per-deployment baked-config argument is correct and well-reasoned. A static hash would be a maintenance hazard for every downstream consumer. The precedent from Plausible, Umami, PostHog, etc. supports this stance.

All three points are well resolved. The PR looks good to me! 🐇

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