fix(analytics): GTM/GA4 missing on /demo and other landing pages#5437
Conversation
GTM/GA4 script-src and connect-src allowlist entries are gated behind isHosted, which next.config.ts's build-time CSP bakes in from whatever NEXT_PUBLIC_APP_URL was resolved at build/boot time. Only the homepage route was overridden with the request-time CSP in proxy.ts, so every other landing page (including /demo) silently lost the googletagmanager.com/google-analytics.com allowlist and GTM never fired.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview Previously, The change always sets Routes that already set runtime CSP ( Reviewed by Cursor Bugbot for commit 7cac9f2. Configure here. |
|
@greptileai review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 363b18d. Configure here.
Greptile SummaryThis PR fixes GTM/GA4 analytics not firing on
Confidence Score: 4/5The change is safe to merge — it broadens CSP header coverage from one route to all landing pages, and the security posture of those pages improves or stays the same. The fix is minimal, targeted, and correct for its stated goal. The one notable gap is that authenticated users on
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Incoming Request] --> B{/api/*?}
B -- Yes --> C[CORS headers + early return]
B -- No --> D{/login or /signup?}
D -- Yes, with session --> E[Redirect to /workspace]
D -- Yes, no session --> F[generateRuntimeCSP + return]
D -- No --> G{/chat/*?}
G -- Yes --> H[Early return, CSP from next.config.ts]
G -- No --> I{/workspace/*?}
I -- No session --> J[Redirect to /login]
I -- With session --> K[generateRuntimeCSP + return]
I -- No --> L{/invite/* redirect?}
L -- Redirect --> M[Redirect to /login with callbackUrl]
L -- NextResponse.next --> N[Early return WITHOUT CSP headers]
L -- No --> O{Security block?}
O -- Yes --> P[403 Forbidden, strict CSP]
O -- No --> Q[Vary: User-Agent]
Q --> R[generateRuntimeCSP - BEFORE: only / - AFTER: all catch-all routes]
R --> S[track + return]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Incoming Request] --> B{/api/*?}
B -- Yes --> C[CORS headers + early return]
B -- No --> D{/login or /signup?}
D -- Yes, with session --> E[Redirect to /workspace]
D -- Yes, no session --> F[generateRuntimeCSP + return]
D -- No --> G{/chat/*?}
G -- Yes --> H[Early return, CSP from next.config.ts]
G -- No --> I{/workspace/*?}
I -- No session --> J[Redirect to /login]
I -- With session --> K[generateRuntimeCSP + return]
I -- No --> L{/invite/* redirect?}
L -- Redirect --> M[Redirect to /login with callbackUrl]
L -- NextResponse.next --> N[Early return WITHOUT CSP headers]
L -- No --> O{Security block?}
O -- Yes --> P[403 Forbidden, strict CSP]
O -- No --> Q[Vary: User-Agent]
Q --> R[generateRuntimeCSP - BEFORE: only / - AFTER: all catch-all routes]
R --> S[track + return]
|
handleInvitationRedirects returns NextResponse.next() for authenticated users, bypassing the catch-all block entirely, so it never picked up the runtime CSP fix in the same way. Same class of gap flagged by review.
|
@greptileai review |
|
@cursor review |
|
@greptileai review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 7cac9f2. Configure here.
Summary
/demo. Confirmed live viacurlagainstsim.aithatscript-src/connect-srcon/demoand/pricingare missinggoogletagmanager.com/google-analytics.com/analytics.ahrefs.com, while/has them.isHosted, whichnext.config.ts's build-timegetMainCSPPolicy()bakes in once at build/boot.apps/sim/proxy.tsonly overrides the response CSP with the request-timegenerateRuntimeCSP()for/,/login,/signup, and/workspace/*— every other route (all marketing/landing pages, including/demo) fell back to the stale build-time policy, which silently dropped the GTM allowlist.generateRuntimeCSP()to every remaining matched route inproxy.tsinstead of gating it topathname === '/'.Test plan
bun run vitest run proxy.test.ts— 11/11 passtsc --noEmitclean onproxy.tscurl -sL -D - -o /dev/null https://www.sim.ai/demo | grep -i content-security-policyincludesgoogletagmanager.com