Skip to content

Replace Mixpanel with PostHog tracking on registry website#269

Open
james00012 wants to merge 3 commits into
mainfrom
james/mar-409-track-registry-website-activity-with-posthog
Open

Replace Mixpanel with PostHog tracking on registry website#269
james00012 wants to merge 3 commits into
mainfrom
james/mar-409-track-registry-website-activity-with-posthog

Conversation

@james00012

@james00012 james00012 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What

Switches the registry website (registry.comfy.org) from Mixpanel to PostHog, so its activity is measured in the same prod project as the other product surfaces. The registry was the one product surface not in PostHog, leaving it invisible in cross-surface active-user metrics.

How

  • Initialize posthog-js in _app.tsx using the same prod project config every other comfy web surface uses (key fallback phc_iKfK…, api_host t.comfy.org, person_profiles: 'identified_only'), with manual $pageview capture on client-side route changes.
  • Route the existing analytic singleton through PostHog (trackcapture, identifyidentify, setProfilesetPersonProperties), so all current call sites keep working unchanged.
  • Remove mixpanel-browser and @types/mixpanel-browser. GA4 is unchanged.
  • Gated on NEXT_PUBLIC_ENV=production, matching the prior Mixpanel gate.

Anonymous (logged-out) visitors are still captured: identified_only only suppresses person-profile creation, not $pageview events, which is what the active-users mart needs for anonymous DAU.

Follow-up

A separate data-platform change is needed to map $host = registry.comfy.org to a registry surface in int_events_unified; until then these events report as other in mart_active_users.

Linear: MAR-409

Copilot AI review requested due to automatic review settings June 18, 2026 16:32
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
registry-web Ready Ready Preview, Comment Jun 19, 2026 11:06pm

Request Review

@CLAassistant

CLAassistant commented Jun 18, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ benceruleanlu
❌ james00012
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR migrates from Mixpanel to PostHog analytics. It adds posthog-js as a dependency, refactors the Analytics class to call PostHog instead of Mixpanel, initializes PostHog in the app shell with manual pageview capture on route changes, and updates CI to use Node.js 22. You might say the analytics are no mix of two providers anymore! 🎯

Changes

PostHog Analytics Migration

Layer / File(s) Summary
PostHog dependency and Analytics class migration
package.json, src/analytic/analytic.ts
Adds posthog-js ^1.360.2 to dependencies and removes @types/mixpanel-browser. Renames MixpanelAnalytics to Analytics, replaces Mixpanel import with PostHog, simplifies constructor to only set isProduction flag, updates track()/identify()/setProfile() methods to call PostHog APIs in production, updates non-production console logs with new message formats, and changes singleton to instantiate Analytics.
PostHog initialization and pageview capture in MyApp
pages/_app.tsx
Adds useRouter and posthog-js imports. Conditionally initializes PostHog at module scope when NEXT_PUBLIC_ENV === 'production' and NEXT_PUBLIC_POSTHOG_KEY is present (autocapture disabled). Registers a routeChangeComplete listener that manually calls posthog.capture('$pageview') on each route change.

CI Infrastructure Update

Layer / File(s) Summary
Node.js version update
.github/workflows/react-ci.yml
Workflow's actions/setup-node updates node-version from 20 to 22.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant MyApp
  participant PostHog
  participant Analytics

  rect rgba(100, 149, 237, 0.5)
    note over MyApp: App initialization (production only)
    MyApp->>PostHog: posthog.init(key, { capture_pageview: false })
  end

  rect rgba(144, 238, 144, 0.5)
    note over Browser,PostHog: Route change
    Browser->>MyApp: routeChangeComplete event
    MyApp->>PostHog: posthog.capture('$pageview')
  end

  rect rgba(255, 165, 0, 0.5)
    note over Analytics,PostHog: User event tracking
    Analytics->>PostHog: posthog.capture(event, props)
    Analytics->>PostHog: posthog.identify(userId)
    Analytics->>PostHog: posthog.setPersonProperties(props)
  end
Loading
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
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
  • Commit unit tests in branch james/mar-409-track-registry-website-activity-with-posthog
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch james/mar-409-track-registry-website-activity-with-posthog

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds PostHog instrumentation to the registry website so activity on registry.comfy.org is included in cross-surface analytics, while keeping existing Mixpanel/GA4 call sites unchanged via the existing analytic singleton.

Changes:

  • Add posthog-js dependency and initialize PostHog in pages/_app.tsx, including manual $pageview capture on client-side route changes.
  • Dual-send analytics events through src/analytic/analytic.ts (Mixpanel + PostHog) behind the existing NEXT_PUBLIC_ENV=production gate.
  • Update lockfile to include PostHog and its transitive dependencies.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/analytic/analytic.ts Dual-sends track/identify/setProfile calls to PostHog in addition to Mixpanel.
pages/_app.tsx Initializes PostHog and captures $pageview events on route changes.
package.json Adds posthog-js dependency.
bun.lock Locks PostHog-related package versions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/analytic/analytic.ts
Comment thread src/analytic/analytic.ts
Comment thread src/analytic/analytic.ts
Comment thread pages/_app.tsx Outdated

@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: 6

🤖 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 `@pages/_app.tsx`:
- Around line 151-160: The useEffect hook for PostHog initialization uses the
variables `isProduction` and `posthogKey` in its body but has an empty
dependency array, violating React Hook rules. Update the dependency array at the
end of the useEffect to include both `isProduction` and `posthogKey` so the
effect properly re-runs when these values change.
- Around line 163-170: The useEffect hook that captures pageviews is missing
dependencies in its dependency array. The hook references variables isProduction
and posthogKey in its condition check, and also uses the posthog object to
capture events, but only includes router.events in the dependency array. Add
isProduction, posthogKey, and posthog to the dependency array to satisfy React
Hook lint rules and ensure the effect re-runs when these values change,
preventing stale closures and potential bugs.
- Around line 163-170: Add a check for router.isReady to the initial condition
guard in the useEffect hook to prevent duplicate pageview events during
hydration. Update the dependency array from [router.events] to [router.isReady,
posthogKey] to ensure the effect re-runs when the router is ready or when the
PostHog key changes, rather than re-registering listeners based on route event
references. This ensures the initial capturePageview() call and router event
listener are only set up after hydration completes.
- Around line 139-143: Remove the hardcoded PostHog API key from the fallback
value in the posthogKey variable assignment. Instead of using the nullish
coalescing operator with a hardcoded key as the default, require the
NEXT_PUBLIC_POSTHOG_KEY environment variable to be explicitly set by assigning
the environment variable directly or throwing an error if it is not defined,
ensuring configuration is managed through environment variables rather than
hardcoded values in the source code.

In `@src/analytic/analytic.ts`:
- Around line 39-46: The identify and track methods lack error handling around
PostHog calls, which means if PostHog fails (due to ad blockers, CSP violations,
or initialization failures), it could break the entire analytics pipeline. Wrap
the posthog.identify() call in the identify method and the corresponding PostHog
call in the track method with try-catch blocks to catch any errors that PostHog
might throw. Log the error using console.error or a logger to maintain
visibility, but allow Mixpanel and the rest of the application to continue
functioning normally even if PostHog fails.
- Around line 28-37: The track() method (and identify() and setProfile()
methods) call PostHog without safely handling the case where it hasn't finished
initializing yet, relying on the unreliable private _isInitialized property.
Replace any checks using posthog._isInitialized with optional chaining when
invoking PostHog methods (e.g., mixpanel.track and posthog.capture in the track
method, and corresponding calls in identify() and setProfile()). This safely
handles uninitialized PostHog state without depending on private internal APIs
that may change across SDK versions.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 421202ec-9ff6-4581-8c07-44ff3d8f7470

📥 Commits

Reviewing files that changed from the base of the PR and between a047c17 and 115141a.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • package.json
  • pages/_app.tsx
  • src/analytic/analytic.ts

Comment thread pages/_app.tsx Outdated
Comment thread pages/_app.tsx Outdated
Comment thread pages/_app.tsx Outdated
Comment thread src/analytic/analytic.ts
Comment thread src/analytic/analytic.ts
@james00012 james00012 force-pushed the james/mar-409-track-registry-website-activity-with-posthog branch from 115141a to 9a87ff1 Compare June 18, 2026 16:39
@james00012 james00012 changed the title Add PostHog tracking to registry website Replace Mixpanel with PostHog tracking on registry website Jun 18, 2026
@socket-security

socket-security Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedposthog-js@​1.390.28310080100100

View full report

@socket-security

socket-security Bot commented Jun 18, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm posthog-js is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package.jsonnpm/posthog-js@1.390.2

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/posthog-js@1.390.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm posthog-js is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package.jsonnpm/posthog-js@1.390.2

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/posthog-js@1.390.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm preact is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: ?npm/posthog-js@1.390.2npm/preact@10.29.2

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/preact@10.29.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Send registry.comfy.org analytics to PostHog instead of Mixpanel so it
is measured in the same project as the other product surfaces. Reads the
project key from NEXT_PUBLIC_POSTHOG_KEY (set per environment, like the
Mixpanel key was), initializes posthog-js in _app, captures $pageview on
route changes, and routes track/identify/setProfile through the analytic
singleton. GA4 is unchanged. Gated on NEXT_PUBLIC_ENV=production.
@james00012 james00012 force-pushed the james/mar-409-track-registry-website-activity-with-posthog branch from 9a87ff1 to adb27fe Compare June 18, 2026 16:50
Copilot AI review requested due to automatic review settings June 18, 2026 16:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

Comment thread pages/_app.tsx
Comment thread src/analytic/analytic.ts
Comment thread src/analytic/analytic.ts
Comment thread src/analytic/analytic.ts
- Skip analytics in non-browser contexts; the analytic singleton is
  imported by server-side route handlers (GitHub OAuth) that call track().
- Move posthog.init to module scope (browser-guarded) so it runs before
  any child-component effect, avoiding pre-init capture calls.
benceruleanlu
benceruleanlu previously approved these changes Jun 19, 2026

@benceruleanlu benceruleanlu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Make sure to set the env var!

Copilot AI review requested due to automatic review settings June 19, 2026 22:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@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: 2

🤖 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 @.github/workflows/react-ci.yml:
- Line 19: The Node.js version in the CI workflow is set to 22, but the
`@types/node` dependency in package.json is pinned to version ^20.19.13, creating
a mismatch between the runtime and type definitions. Update the `@types/node`
entry in package.json to use version ^22.x to align the TypeScript type checking
with the Node.js 22 runtime being used in CI and ensure consistency between
development types and actual runtime APIs.

In `@src/analytic/analytic.ts`:
- Around line 19-40: The track, identify, and setProfile methods all include an
early return guard that checks typeof window === "undefined", which prevents
server-side API routes from sending analytics events to PostHog. Remove or
modify this guard in all three methods so that server-side calls from routes
like app/api/auth/github/route.ts can successfully send analytics data to
PostHog instead of silently dropping them. Consider whether the window check is
actually necessary for PostHog operations or if it can be removed entirely to
allow both server and client-side analytics to flow through.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 046aef2a-ac55-4335-994e-f8bdf79976bb

📥 Commits

Reviewing files that changed from the base of the PR and between 115141a and 43b8c5a.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • .github/workflows/react-ci.yml
  • package.json
  • pages/_app.tsx
  • src/analytic/analytic.ts

uses: actions/setup-node@v2
with:
node-version: "20"
node-version: "22"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify Node.js 22 compatibility with pinned type definitions and dependencies.

# Test 1: Check `@types/node` version constraint and Node 22 compatibility
echo "=== Checking `@types/node` version ==="
rg -A2 '"`@types/node`"' package.json

# Test 2: Search for explicit Node version engines constraint
echo "=== Checking engines field in package.json ==="
rg '"engines"' package.json -A3

# Test 3: Check if there are local type definitions that assume Node 20 APIs
echo "=== Searching for Node-specific type references ==="
rg -i 'node\.versions|process\.versions|--node' --type=ts --type=tsx -A2 -B2 src/ || echo "No explicit version checks found"

# Test 4: Look for any Node 22 related comments or configuration
echo "=== Searching for Node version comments ==="
rg -i 'node.*2[0-2]|node.*version' . -g '!node_modules' -g '!.git' || echo "No Node version notes found"

Repository: Comfy-Org/registry-web

Length of output: 50425


Update @types/node to align with Node.js 22 runtime.

The CI now runs Node.js 22, but the project pins @types/node to ^20.19.13. While the gap won't turn your types upside-down (your dev dependencies like Vite and Vitest already support Node 22 types), this creates a version mismatch: TypeScript type checking validates against Node 20 APIs while code executes on Node 22. This deviation could quietly slip Node 22-specific APIs past type checking if they're ever used.

Recommended fix:
Update @types/node to ^22.x in package.json to keep your types and runtime in sync—no version-related bugs slipping through!

🤖 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 @.github/workflows/react-ci.yml at line 19, The Node.js version in the CI
workflow is set to 22, but the `@types/node` dependency in package.json is pinned
to version ^20.19.13, creating a mismatch between the runtime and type
definitions. Update the `@types/node` entry in package.json to use version ^22.x
to align the TypeScript type checking with the Node.js 22 runtime being used in
CI and ensure consistency between development types and actual runtime APIs.

Comment thread src/analytic/analytic.ts
Comment on lines +19 to 40
if (typeof window === "undefined") return;
if (this.isProduction) {
mixpanel.track(event, properties);
posthog.capture(event, properties);
} else {
console.log(`Mixpanel Track - Event: ${event}, Properties: ${JSON.stringify(properties)}`);
console.log(`Track - Event: ${event}, Properties: ${JSON.stringify(properties)}`);
}
}

public identify(distinctId: string): void {
if (typeof window === "undefined") return;
if (this.isProduction) {
mixpanel.identify(distinctId);
posthog.identify(distinctId);
} else {
console.log(`Mixpanel Identify - Distinct ID: ${distinctId}`);
console.log(`Identify - Distinct ID: ${distinctId}`);
}
}

public setProfile(updates: UserProfile): void {
if (typeof window === "undefined") return;
if (this.isProduction) {
mixpanel.people.set(updates);
posthog.setPersonProperties(updates);
} else {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify server-side call sites that now no-op due `typeof window` guards.
# Expected: any matches under app/api, pages/api, or server route handlers indicate dropped events.

rg -n -C2 'analytic\.(track|identify|setProfile)\(' --type ts --type tsx
rg -n -C2 'import analytic from ["'\''].*analytic["'\'']' --type ts --type tsx
rg -n -C2 'export (async )?function (GET|POST|PUT|PATCH|DELETE)|route\.ts' --type ts --type tsx

Repository: Comfy-Org/registry-web

Length of output: 150


🏁 Script executed:

#!/bin/bash
# Search for analytic method calls (track, identify, setProfile) in the codebase
# without the problematic tsx type filter

echo "=== Searching for analytic method calls ==="
rg -n -C2 'analytic\.(track|identify|setProfile)\(' --type ts

echo ""
echo "=== Searching for analytic imports ==="
rg -n -C2 'import.*analytic' --type ts

echo ""
echo "=== Checking for the OAuth callback route file ==="
find . -name "*github*callback*" -o -name "*route.ts" | head -20

echo ""
echo "=== Inspecting analytic.ts structure ==="
cat -n src/analytic/analytic.ts | head -50

Repository: Comfy-Org/registry-web

Length of output: 14992


Server-side analytics are silently dropped by the window guard—that's no jest, events fail to manifest.

Lines 19, 28, and 37 return early on server, but app/api/auth/github/route.ts (line 43) and app/api/auth/github/callback/route.ts (lines 75, 87) call analytic.track() from server-side API routes. This means OAuth verification events never reach PostHog, silently dropping critical auth fidelity data.

Suggested fix direction
 import posthog from "posthog-js";
+// server transport should be added (e.g., posthog-node) for non-browser callers

 class Analytics {
   public track(event: string, properties?: object): void {
-    if (typeof window === "undefined") return;
+    if (typeof window === "undefined") {
+      // send via server analytics client here
+      return;
+    }
     if (this.isProduction) {
       posthog.capture(event, properties);
     }
   }
 }
🤖 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/analytic/analytic.ts` around lines 19 - 40, The track, identify, and
setProfile methods all include an early return guard that checks typeof window
=== "undefined", which prevents server-side API routes from sending analytics
events to PostHog. Remove or modify this guard in all three methods so that
server-side calls from routes like app/api/auth/github/route.ts can successfully
send analytics data to PostHog instead of silently dropping them. Consider
whether the window check is actually necessary for PostHog operations or if it
can be removed entirely to allow both server and client-side analytics to flow
through.

@benceruleanlu benceruleanlu enabled auto-merge (squash) June 19, 2026 23:03
@benceruleanlu benceruleanlu disabled auto-merge June 19, 2026 23:27
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.

4 participants