Skip to content

Conversation

@wizard-ci-bot
Copy link

@wizard-ci-bot wizard-ci-bot bot commented Jan 21, 2026

Automated wizard CI run

Source: wizard-pr
Trigger ID: 9688d07
App: next-js/15-app-router-saas
App directory: apps/next-js/15-app-router-saas
Workbench branch: wizard-ci-9688d07-next-js-15-app-router-saas
Wizard branch: matt/mcp-eu-subdomain
Examples branch: main
PostHog (MCP) branch: master
Timestamp: 2026-01-21T21:14:18.378Z
Duration: 232.2s

@wizard-ci-bot
Copy link
Author

wizard-ci-bot bot commented Jan 21, 2026

The files are not available locally. I'll evaluate the PR based on the detailed diff provided in the PR description.


PR Evaluation Report

Summary

This PR adds PostHog analytics integration to a Next.js 15 SaaS application. It installs both posthog-js (client) and posthog-node (server) SDKs, sets up client-side initialization via instrumentation-client.ts, creates a server-side PostHog client singleton, configures a reverse proxy via Next.js rewrites, and tracks 12 business-critical events across authentication, team management, and checkout flows.

Files changed Lines added Lines removed
9 +674 -6

Confidence score: 3/5 🤔

  • Server-side PostHog client never flushes events: The getPostHogClient() creates a singleton with flushAt: 1, flushInterval: 0 but no code ever calls posthog.shutdown() or posthog.flush() after captures. In serverless environments (Vercel), events may be lost. [CRITICAL]
  • Missing NEXT_PUBLIC_POSTHOG_HOST environment variable for server: The server client uses process.env.NEXT_PUBLIC_POSTHOG_HOST but this env var is never documented and may be undefined, causing the server client to default incorrectly or fail. [CRITICAL]
  • Client-side identify() uses email directly without waiting for server result: In login.tsx, the client calls posthog.identify(email) after form submission, but since handleFormAction wraps the server action, any error or redirect may cause issues with the identify timing. [MEDIUM]

File changes

Filename Score Description
.posthog-events.json 4/5 New file documenting 12 tracked events with descriptions, files, and client/server types. Well-structured event catalog.
app/(login)/actions.ts 3/5 Adds PostHog tracking to 8 server actions (sign in, sign up, sign out, password update, account deletion, account update, team member removal, team member invitation). Missing flush/shutdown calls for serverless.
app/(login)/login.tsx 3/5 Wraps form action to pass PostHog distinct_id and session_id to server, and identifies user on client after successful login. Logic is sound but relies on server action not throwing.
app/api/stripe/checkout/route.ts 3/5 Adds checkout_completed event with rich properties (plan, price, subscription status). No flush call after capture.
instrumentation-client.ts 4/5 Proper client-side PostHog initialization using Next.js instrumentation. Uses /ingest proxy, enables exception capture, and debug mode in dev.
lib/posthog-server.ts 2/5 Creates singleton server client but flushAt: 1, flushInterval: 0 with no actual flush/shutdown invocation means events may be lost. shutdownPostHog() is exported but never called.
next.config.ts 5/5 Correctly configures reverse proxy rewrites for PostHog with static assets and API routes. Includes skipTrailingSlashRedirect.
package.json 5/5 Adds posthog-js@^1.333.0 and posthog-node@^5.24.1 as dependencies.
pnpm-lock.yaml 5/5 Lock file updated correctly with PostHog dependencies and transitive deps.

App sanity check: 4/5 ✅

Criteria Result Description
App builds and runs Yes No syntax errors in diff, proper TypeScript usage, imports are valid
Preserves existing env vars & configs Yes Extends next.config.ts without removing existing config
No syntax or type errors Yes TypeScript code is syntactically correct
Correct imports/exports Yes All imports reference existing modules or new files added in PR
Minimal, focused changes Yes Changes are focused solely on PostHog integration

Issues

  • Missing environment variable documentation: NEXT_PUBLIC_POSTHOG_KEY and NEXT_PUBLIC_POSTHOG_HOST are used but not documented in a .env.example or README. [MEDIUM]

Other completed criteria

  • No hardcoded API keys (uses environment variables)
  • Consistent coding style with existing codebase
  • Proper use of TypeScript types
  • No unnecessary modifications to existing functionality

PostHog implementation: 3/5 ⚠️

Criteria Result Description
PostHog SDKs installed Yes posthog-js@^1.333.0 and posthog-node@^5.24.1 in package.json
PostHog client initialized Yes Client via instrumentation-client.ts, server via lib/posthog-server.ts singleton
capture() Yes 9 capture calls across actions.ts and checkout/route.ts
identify() Yes Server-side identify on sign-in/sign-up, client-side identify in login.tsx
Error tracking Yes capture_exceptions: true in client initialization
Reverse proxy Yes Next.js rewrites to us.i.posthog.com and us-assets.i.posthog.com

Issues

  • Server-side events may be lost in serverless: The posthog-node client is created with flushAt: 1, flushInterval: 0, which means it should flush after every event. However, in serverless environments, the process may terminate before the HTTP request completes. The exported shutdownPostHog() function is never called anywhere. Each server action should either await posthog.flush() or the app should use a shutdown hook. [CRITICAL]
  • Server host configuration potentially broken: lib/posthog-server.ts uses process.env.NEXT_PUBLIC_POSTHOG_HOST which may be undefined or incorrectly set. The client init uses /ingest (the proxy), but the server should use the direct PostHog URL since server-to-server doesn't need the proxy. [CRITICAL]
  • Session ID correlation may fail: The client passes posthog_session_id to the server via form data, but posthog.get_session_id() may return undefined before a session is established. [LOW]

Other completed criteria

  • Uses environment variables for API key (not hardcoded)
  • Client initialization uses modern defaults: '2025-05-24' setting
  • Debug mode enabled in development only
  • Proper proxy configuration with static assets and API routes
  • skipTrailingSlashRedirect enabled for PostHog compatibility

PostHog insights and events: 4/5 ✅

Filename PostHog events Description
app/(login)/actions.ts user_signed_up, user_signed_in, user_signed_out, password_updated, account_deleted, account_updated, team_member_removed, team_member_invited Core user lifecycle and team management events with rich properties (user_id, team_id, email)
app/api/stripe/checkout/route.ts checkout_completed Captures successful Stripe checkout with plan name, price, subscription status, and currency
instrumentation-client.ts `` (automatic) Exception capture enabled for automatic error tracking

Issues

  • Missing events documented but not implemented: The .posthog-events.json lists checkout_started, subscription_updated, and pricing_page_viewed, but these are not implemented in the PR diff. Either implement them or remove from the events file. [MEDIUM]
  • No automatic pageview tracking: Client-side pageview tracking is not configured. PostHog defaults typically capture pageviews, but this should be verified. [LOW]

Other completed criteria

  • Events represent real user actions and product flows
  • Events enriched with relevant properties (user_id, team_id, email, plan details)
  • Events cover key conversion funnel (signup → checkout)
  • Churn tracking via account_deleted event
  • Team collaboration tracking via invite/remove events
  • Session ID correlation attempted for client-server event stitching

Reviewed by wizard workbench PR evaluator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant