GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(analytics): GTM/GA4 missing on /demo and other landing pages by waleedlatif1 · Pull Request #5437 · simstudioai/sim

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Andy (marketing) reported GTM/GA4 key-event tracking not firing on /demo. Confirmed live via curl against sim.ai that script-src/connect-src on /demo and /pricing are missing googletagmanager.com/google-analytics.com/analytics.ahrefs.com, while / has them.
  • Root cause: those GTM/GA CSP entries are gated on isHosted, which next.config.ts's build-time getMainCSPPolicy() bakes in once at build/boot. apps/sim/proxy.ts only overrides the response CSP with the request-time generateRuntimeCSP() 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.
  • Fix: apply generateRuntimeCSP() to every remaining matched route in proxy.ts instead of gating it to pathname === '/'.

Test plan

  • bun run vitest run proxy.test.ts — 11/11 pass
  • tsc --noEmit clean on proxy.ts
  • Verify post-deploy: curl -sL -D - -o /dev/null https://www.sim.ai/demo | grep -i content-security-policy includes googletagmanager.com

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@waleedlatif1
fix(analytics): apply runtime CSP to all landing pages, not just /
27e3cf8
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.
@vercel

vercel Bot commented Jul 6, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 6, 2026 6:14pm

Request Review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@cursor

cursor Bot commented Jul 6, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

PR Summary

Low Risk
Broadens security headers to more HTML routes using the same runtime CSP helper already used on / and auth pages; no auth or data-path changes.

Overview
Fixes GTM/GA4 and other hosted analytics not loading on marketing pages (e.g. /demo, /pricing) by ensuring every non-API page that falls through proxy.ts gets request-time CSP instead of only /.

Previously, generateRuntimeCSP() (which includes googletagmanager.com / google-analytics.com when isHosted) was set only when pathname === '/'. Other matched routes kept the build-time CSP from next.config.ts, which could omit those domains and block tags.

The change always sets Content-Security-Policy, X-Content-Type-Options, and X-Frame-Options on the default NextResponse.next() path. Invite routes that continue without a login redirect now get the same runtime CSP headers.

Routes that already set runtime CSP (/login, /signup, /workspace/*) and /chat/* (CSP from config) are unchanged in intent; /api/* still only gets CORS.

Reviewed by Cursor Bugbot for commit 7cac9f2. Configure here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1
style: drop inline comment from proxy CSP fix
363b18d
@vercel
vercel Bot temporarily deployed to Preview July 6, 2026 18:09 Inactive
@waleedlatif1

waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1

waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cursor review

cursor[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cursor[bot]
cursor Bot reviewed Jul 6, 2026
View reviewed changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

✅ 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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@greptile-apps

greptile-apps Bot commented Jul 6, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes missing GTM/GA4 analytics tracking on marketing/landing pages like /demo and /pricing by broadening where generateRuntimeCSP() is applied in the middleware. Previously, the runtime CSP (which includes googletagmanager.com and google-analytics.com) was only set when pathname === '/'; now it is applied to every matched route that reaches the fall-through block, and /invite/* pages with an active session also receive it.

  • Removes the if (url.pathname === '/') guard in proxy(), so all non-API, non-chat routes that fall through receive the runtime CSP with GTM/GA4 allowlists.
  • Updates handleInvitationRedirects to attach CSP/security headers to the NextResponse.next() it returns for authenticated /invite/ visitors, closing the one remaining gap for those pages.

Confidence Score: 5/5

Safe to merge — the change correctly broadens runtime CSP coverage to all matched landing/marketing routes without affecting API paths, chat embeds, or auth redirects.

The two-line guard removal is minimal and mechanically correct. Every early-return branch (API, /login, /signup, /workspace, /invite/ redirect, suspicious-UA block) is untouched; only the fall-through path that previously left /demo and other landing pages without a runtime CSP is affected. The /invite/ authenticated-session fix closes the one remaining gap that existed before this PR. No new code paths are introduced that could regress existing behaviour.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/proxy.ts Broadens runtime CSP application from / only to all matched non-API, non-chat routes; also fixes /invite/ pages with an active session that previously returned a bare NextResponse.next(). Logic is correct and no new gaps are introduced.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Incoming Request] --> B{pathname starts with /api/?}
    B -->|Yes| C[Apply CORS headers & return]
    B -->|No| D[Check session cookie]
    D --> E[handleRootPathRedirects]
    E -->|Redirect| F[track & return redirect]
    E -->|null| G{pathname /login or /signup?}
    G -->|Yes, has session| H[Redirect to /workspace]
    G -->|Yes, no session| I[Apply runtime CSP & return]
    G -->|No| J{pathname starts with /chat/?}
    J -->|Yes| K[Return bare NextResponse — CSP from next.config.ts]
    J -->|No| L{pathname starts with /workspace?}
    L -->|Yes, no session| M[Redirect to /login]
    L -->|Yes, has session| N[Apply runtime CSP & return]
    L -->|No| O[handleInvitationRedirects]
    O -->|Unauthenticated redirect| P[track & return redirect to login]
    O -->|Authenticated — NEW| Q[Apply runtime CSP & return]
    O -->|null| R[handleSecurityFiltering]
    R -->|Suspicious UA| S[Return 403 Forbidden]
    R -->|null| T[Apply runtime CSP + Vary: User-Agent — FIXED]
    T --> U[track & return]

    style T fill:#d4edda,stroke:#28a745
    style Q fill:#d4edda,stroke:#28a745
Loading
%%{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{pathname starts with /api/?}
    B -->|Yes| C[Apply CORS headers & return]
    B -->|No| D[Check session cookie]
    D --> E[handleRootPathRedirects]
    E -->|Redirect| F[track & return redirect]
    E -->|null| G{pathname /login or /signup?}
    G -->|Yes, has session| H[Redirect to /workspace]
    G -->|Yes, no session| I[Apply runtime CSP & return]
    G -->|No| J{pathname starts with /chat/?}
    J -->|Yes| K[Return bare NextResponse — CSP from next.config.ts]
    J -->|No| L{pathname starts with /workspace?}
    L -->|Yes, no session| M[Redirect to /login]
    L -->|Yes, has session| N[Apply runtime CSP & return]
    L -->|No| O[handleInvitationRedirects]
    O -->|Unauthenticated redirect| P[track & return redirect to login]
    O -->|Authenticated — NEW| Q[Apply runtime CSP & return]
    O -->|null| R[handleSecurityFiltering]
    R -->|Suspicious UA| S[Return 403 Forbidden]
    R -->|null| T[Apply runtime CSP + Vary: User-Agent — FIXED]
    T --> U[track & return]

    style T fill:#d4edda,stroke:#28a745
    style Q fill:#d4edda,stroke:#28a745
Loading

Reviews (4): Last reviewed commit: "fix(analytics): apply runtime CSP to aut..." | Re-trigger Greptile

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@greptile-apps

greptile-apps Bot commented Jul 6, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes GTM/GA4 analytics not firing on /demo, /pricing, and other landing pages by extending runtime CSP header application from only the root path to all catch-all routes in proxy.ts. The root cause was that generateRuntimeCSP() (which includes isHosted-gated GTM domains) was only called when pathname === '/', so every other marketing page fell back to the stale build-time CSP that silently omitted those domains.

  • Root path guard removed: The if (url.pathname === '/') block is replaced with unconditional calls to generateRuntimeCSP(), X-Content-Type-Options, and X-Frame-Options for all routes that reach the catch-all block.
  • Scope is correct: Routes with early returns (/api/*, /login, /signup, /workspace, /chat/*, /invite/*) are unaffected; only the true catch-all paths (landing pages, marketing routes) gain the runtime CSP.

Confidence Score: 4/5

The 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 /invite/ pages still receive no runtime CSP because handleInvitationRedirects returns NextResponse.next() before the new header-setting code is reached. This is pre-existing behaviour but falls within the same class of issue the PR is addressing. All other routes are handled correctly, and X-Content-Type-Options / X-Frame-Options being applied more broadly is an improvement.

apps/sim/proxy.ts — specifically the handleInvitationRedirects early-return path at line 278, which exits without setting runtime CSP headers.

Important Files Changed

Filename Overview
apps/sim/proxy.ts Removes the pathname === '/' guard so generateRuntimeCSP() and security headers are applied to all catch-all routes; fix is correct but authenticated /invite/ pages still escape CSP via an early return in handleInvitationRedirects.

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]
Loading
%%{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]
Loading

Comments Outside Diff (1)

  1. apps/sim/proxy.ts, line 277-278 (link)

    P2 Authenticated /invite/ pages still bypass runtime CSP

    handleInvitationRedirects returns NextResponse.next() at line 186 when the visitor already has a session, and the proxy immediately returns that bare response at line 278 — before the new generateRuntimeCSP() call at line 286. Authenticated users landing on /invite/[id] therefore receive no runtime CSP, which means the GTM/GA4 domains are still absent on those pages. Since the PR's goal is to fix missing GTM tracking across all marketing-style routes, invite pages with a session are the one remaining gap.

Reviews (2): Last reviewed commit: "style: drop inline comment from proxy CS..." | Re-trigger Greptile

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1
fix(analytics): apply runtime CSP to authenticated /invite pages too
7cac9f2
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.
@waleedlatif1

waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1

waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cursor review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vercel
vercel Bot temporarily deployed to Preview July 6, 2026 18:14 Inactive
cursor[bot]
cursor Bot reviewed Jul 6, 2026
View reviewed changes
Comment thread apps/sim/proxy.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1

waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1

waleedlatif1 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

@cursor review

cursor[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cursor[bot]
cursor Bot reviewed Jul 6, 2026
View reviewed changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

✅ 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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@waleedlatif1
waleedlatif1 merged commit 89e5a14 into staging Jul 6, 2026
18 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1
waleedlatif1 deleted the fix/gtm-demo-page branch July 6, 2026 18:49
@waleedlatif1 waleedlatif1 mentioned this pull request Jul 7, 2026
v0.7.24: frontend perf improvements, md editor fixes, mailer fix, tools audit #5458
Merged

This branch was previously deployed

1 inactive deployment
Preview — 7cac9f2a Deployed Jul 6, 2026 by vercel[bot]
View deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@cursor cursor[bot] cursor[bot] left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@waleedlatif1
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.