Skip to content

Conversation

@0xApotheosis
Copy link
Member

@0xApotheosis 0xApotheosis commented Nov 26, 2025

Integrates Mixpanel for product analytics.
Also fixed a bunch of issues related to lock file generation.

Changes

  • Initialize Mixpanel SDK in app entry point with autocapture and 100% session replay
  • Add analytics utility (src/lib/mixpanel.ts) for type-safe event tracking
  • Add useWalletAnalytics hook to identify users and track wallet connections
  • Track key user actions:
    • Wallet Connect - when EVM/Solana wallet connects (also identifies user)
    • Chat Message Sent - when user sends a message
    • Swap - on successful swap completion
    • Send - on successful send transaction

New Dependencies

  • mixpanel-browser

Summary by CodeRabbit

  • New Features

    • Added optional analytics tracking capability, enabling users to track wallet connections, swap operations, send transactions, and chat interactions.
    • Analytics can be enabled in production or locally via the VITE_ENABLE_ANALYTICS environment variable.
  • Chores

    • Added analytics dependency and development tools.
    • Updated package configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

📝 Walkthrough

Walkthrough

The pull request implements comprehensive Mixpanel analytics tracking across the application. A new type-safe analytics wrapper controls event tracking for wallet connections, transactions, swaps, and chat messages. Analytics initialization is gated by an environment variable (VITE_ENABLE_ANALYTICS) or production flag.

Changes

Cohort / File(s) Summary
Analytics Infrastructure
apps/agentic-chat/src/lib/mixpanel.ts, apps/agentic-chat/src/main.tsx, README.md
New type-safe analytics wrapper exports an analytics object with methods for identifying users, tracking wallet connections, swaps, sends, and chat messages. Mixpanel initialization in main.tsx is conditional on production or VITE_ENABLE_ANALYTICS environment variable. README documents the new optional environment variable.
Analytics Hooks
apps/agentic-chat/src/hooks/useWalletAnalytics.ts, apps/agentic-chat/src/hooks/useSendExecution.ts, apps/agentic-chat/src/hooks/useSwapExecution.ts
New useWalletAnalytics hook tracks wallet connection changes and calls analytics identify/reset. useSendExecution and useSwapExecution now track successful send and swap operations with relevant asset and network details.
Component Integrations
apps/agentic-chat/src/app/app.tsx, apps/agentic-chat/src/providers/ChatProvider.tsx
App.tsx extracts routes into new AppContent component that invokes useWalletAnalytics. ChatProvider adds analytics tracking for chat message submissions.
Dependencies
apps/agentic-chat/package.json, package.json
Added mixpanel-browser dependency. Root package.json adds dev dependencies: @types/bun, @types/lodash, bun-types, and vite.

Sequence Diagram(s)

sequenceDiagram
    participant App as App Initialization
    participant Main as main.tsx
    participant Mixpanel as Mixpanel
    participant Analytics as analytics (wrapper)
    
    App->>Main: Start application
    Main->>Main: Check isProduction || VITE_ENABLE_ANALYTICS
    alt Analytics Enabled
        Main->>Mixpanel: Init with token
    else Analytics Disabled
        Main->>Analytics: No-op mode
    end
    
    rect rgb(200, 220, 240)
        Note over App,Analytics: User Interaction Phase
        App->>App: Mount AppContent
        App->>App: useWalletAnalytics detects wallet change
        App->>Analytics: trackWalletConnect(address, walletType)
        Analytics->>Mixpanel: Send event (if enabled)
    end
Loading
sequenceDiagram
    participant User as User
    participant Hook as Transaction Hook
    participant Analytics as analytics
    participant Mixpanel as Mixpanel
    
    User->>Hook: Execute transaction (send/swap)
    Hook->>Hook: Transaction succeeds
    
    rect rgb(200, 240, 200)
        Note over Hook,Mixpanel: Successful Transaction Flow
        Hook->>Analytics: trackSend() or trackSwap()
        Analytics->>Analytics: Check if enabled
        alt Enabled
            Analytics->>Mixpanel: Send event with details
        else Disabled
            Analytics->>Analytics: Return early (no-op)
        end
    end
    
    Hook->>User: Return result
Loading
sequenceDiagram
    participant User as User
    participant ChatProvider as ChatProvider
    participant Analytics as analytics
    
    User->>ChatProvider: Submit message
    ChatProvider->>Analytics: trackChatMessage()
    Analytics->>Analytics: Check if enabled
    ChatProvider->>ChatProvider: Send message
    ChatProvider->>User: Confirm
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Multiple files with consistent analytics-tracking patterns reduce overall review complexity
  • New infrastructure files (mixpanel.ts, useWalletAnalytics.ts) require careful logic review to ensure proper initialization and wallet state tracking
  • Integration points across hooks and providers are straightforward additions but warrant verification that analytics calls don't interfere with existing transaction/chat flows
  • Environment variable gating and feature flag logic should be confirmed to work correctly in both production and local development scenarios

Poem

🐰 Hop along with the data flow so bright,
Analytics now track each wallet and write,
Swaps, sends, and chats find their way,
To Mixpanel's halls, where events play,
A toggle to switch them on and on high,
Watch metrics hop up into the sky!

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add mixpanel' accurately summarizes the main change: integrating Mixpanel analytics into the application. It is concise, clear, and specific enough for a teammate to understand the primary objective.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mixpanel

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.

@vercel
Copy link

vercel bot commented Nov 26, 2025

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

Project Deployment Preview Comments Updated (UTC)
shapeshift-agentic Ready Ready Preview Comment Nov 27, 2025 0:46am

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)

128-140: Track chat messages after successful send to avoid inflating metrics.

The analytics event is tracked before the message is sent (line 135), which means failed attempts will also be counted. This could inflate your "Chat Message Sent" metrics.

Consider one of these approaches:

Option 1: Track after successful send

 const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
   e.preventDefault()
   if (!input.trim()) return

   const messageToSend = input
   setInput('')

-  analytics.trackChatMessage()
-
-  await chat.sendMessage({
+  await chat.sendMessage({
     text: messageToSend,
   })
+
+  analytics.trackChatMessage()
 }

Option 2: Track in the onFinish callback
Move the tracking to the onFinish callback (lines 82-89) alongside conversation saving, which only fires on successful completion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2e0ccea and a392768.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • README.md (1 hunks)
  • apps/agentic-chat/package.json (1 hunks)
  • apps/agentic-chat/src/app/app.tsx (2 hunks)
  • apps/agentic-chat/src/hooks/useSendExecution.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useSwapExecution.ts (2 hunks)
  • apps/agentic-chat/src/hooks/useWalletAnalytics.ts (1 hunks)
  • apps/agentic-chat/src/lib/mixpanel.ts (1 hunks)
  • apps/agentic-chat/src/main.tsx (2 hunks)
  • apps/agentic-chat/src/providers/ChatProvider.tsx (2 hunks)
  • package.json (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
apps/agentic-chat/src/providers/ChatProvider.tsx (1)
apps/agentic-chat/src/lib/mixpanel.ts (1)
  • analytics (8-53)
apps/agentic-chat/src/hooks/useSwapExecution.ts (1)
apps/agentic-chat/src/lib/mixpanel.ts (1)
  • analytics (8-53)
apps/agentic-chat/src/app/app.tsx (3)
apps/agentic-chat/src/hooks/useWalletAnalytics.ts (1)
  • useWalletAnalytics (7-36)
apps/agentic-chat/src/app/dashboard/page.tsx (1)
  • Dashboard (9-28)
apps/agentic-chat/src/lib/wagmi-config.ts (1)
  • wagmiConfig (24-24)
apps/agentic-chat/src/hooks/useSendExecution.ts (1)
apps/agentic-chat/src/lib/mixpanel.ts (1)
  • analytics (8-53)
🔇 Additional comments (8)
README.md (1)

10-10: LGTM!

The documentation clearly indicates that analytics is optional and can be enabled for local builds. This is helpful for developers.

package.json (1)

36-56: LGTM!

The addition of development dependencies for Bun types, Lodash types, and Vite is appropriate for improved type safety and build tooling. These changes have no runtime impact.

apps/agentic-chat/src/hooks/useSendExecution.ts (1)

211-216: LGTM!

The analytics tracking is correctly placed after the successful send execution and within the try block, ensuring only successful transactions are tracked.

apps/agentic-chat/src/hooks/useSwapExecution.ts (1)

259-266: LGTM!

The analytics tracking is correctly placed after the successful swap execution and within the try block, ensuring only successful swaps are tracked.

apps/agentic-chat/src/app/app.tsx (2)

44-54: LGTM!

The extraction of routing logic into AppContent is clean and allows the useWalletAnalytics hook to be called within the provider context. This maintains existing routing behavior while adding analytics support.


56-64: LGTM!

The App component now properly composes AppContent, maintaining the same provider hierarchy while enabling analytics initialization.

apps/agentic-chat/package.json (1)

38-38: No issues found with mixpanel-browser version 2.72.0.

Verification confirms:

  • Version 2.72.0 exists on npm and is the latest available release
  • No known security vulnerabilities detected
  • Using the caret range (^2.72.0) is standard practice and allows future patch and minor updates

The dependency addition is valid and safe.

apps/agentic-chat/src/lib/mixpanel.ts (1)

7-53: Centralized analytics wrapper looks solid

Encapsulating all tracking behind a single analytics object with an analyticsEnabled gate and typed props keeps call sites clean and safe; the no-op behavior when disabled is especially helpful for local/dev environments.

Comment on lines +7 to +35
export function useWalletAnalytics() {
const { evmAddress, solanaAddress } = useWalletConnection()
const prevEvmAddress = useRef<string | undefined>(undefined)
const prevSolanaAddress = useRef<string | undefined>(undefined)

useEffect(() => {
// Track EVM wallet connection
if (evmAddress && evmAddress !== prevEvmAddress.current) {
analytics.identify(evmAddress, { walletType: 'evm' })
analytics.trackWalletConnect({ address: evmAddress, walletType: 'evm' })
}
prevEvmAddress.current = evmAddress
}, [evmAddress])

useEffect(() => {
// Track Solana wallet connection
if (solanaAddress && solanaAddress !== prevSolanaAddress.current) {
analytics.identify(solanaAddress, { walletType: 'solana' })
analytics.trackWalletConnect({ address: solanaAddress, walletType: 'solana' })
}
prevSolanaAddress.current = solanaAddress
}, [solanaAddress])

useEffect(() => {
// Reset analytics when both wallets disconnect
if (!evmAddress && !solanaAddress && (prevEvmAddress.current || prevSolanaAddress.current)) {
analytics.reset()
}
}, [evmAddress, solanaAddress])
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Reset effect never fires; prev refs are overwritten before the check

On disconnect, prevEvmAddress.current and prevSolanaAddress.current are updated to match the new (falsy) values before the third useEffect runs. That means the condition

!evmAddress && !solanaAddress && (prevEvmAddress.current || prevSolanaAddress.current)

is never true, so analytics.reset() is effectively unreachable and analytics state is never cleared when the last wallet disconnects.

A simple fix is to track “did we ever have any wallet connected?” as a separate boolean ref, rather than reusing the per‑wallet prev refs:

   const { evmAddress, solanaAddress } = useWalletConnection()
   const prevEvmAddress = useRef<string | undefined>(undefined)
   const prevSolanaAddress = useRef<string | undefined>(undefined)
+  const hasWalletRef = useRef(false)

@@
   useEffect(() => {
     // Reset analytics when both wallets disconnect
-    if (!evmAddress && !solanaAddress && (prevEvmAddress.current || prevSolanaAddress.current)) {
-      analytics.reset()
-    }
+    const hasWallet = Boolean(evmAddress || solanaAddress)
+
+    if (!hasWallet && hasWalletRef.current) {
+      analytics.reset()
+    }
+
+    hasWalletRef.current = hasWallet
   }, [evmAddress, solanaAddress])
 }

(Minor/nit: the two “track wallet connection” effects are nearly identical; you could factor out a small helper to reduce duplication, but that’s optional.)

🤖 Prompt for AI Agents
In apps/agentic-chat/src/hooks/useWalletAnalytics.ts around lines 7 to 35, the
reset effect never fires because prevEvmAddress.current and
prevSolanaAddress.current are updated to falsy values before the third useEffect
runs; change the logic to track "hadAnyWalletConnected" as a separate
useRef<boolean>(false) (set it true whenever an evmAddress or solanaAddress is
newly detected, before overwriting per-wallet prev refs), then update the reset
effect to check !evmAddress && !solanaAddress && hadAnyWalletConnected.current
and call analytics.reset() and set hadAnyWalletConnected.current = false after
reset; keep the per-wallet prev refs for connection-change detection but do not
rely on them for the global reset condition.

Comment on lines +13 to +24
// Initialize Mixpanel (disabled in dev unless VITE_ENABLE_ANALYTICS is set)
const isProduction = import.meta.env.PROD
const analyticsEnabled = isProduction || import.meta.env.VITE_ENABLE_ANALYTICS === 'true'

if (analyticsEnabled) {
mixpanel.init('c7ded934ffc012d90c2c3f3f2e8fd8aa', {
debug: !isProduction,
track_pageview: false,
persistence: 'localStorage',
autocapture: false,
})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Move Mixpanel token to environment variable.

The Mixpanel project token is hardcoded (line 18), which makes it harder to rotate or use different tokens for different environments (staging, production, etc.). While Mixpanel tokens are client-side and inherently public, using an environment variable is best practice for configuration management.

Apply this diff:

 if (analyticsEnabled) {
-  mixpanel.init('c7ded934ffc012d90c2c3f3f2e8fd8aa', {
+  mixpanel.init(import.meta.env.VITE_MIXPANEL_TOKEN, {
     debug: !isProduction,
     track_pageview: false,
     persistence: 'localStorage',
     autocapture: false,
   })
 }

Then add to your .env.example:

VITE_MIXPANEL_TOKEN=your_mixpanel_token_here

Note: The PR description mentions "100% session replay" but I don't see session replay configured in the init options. If session replay is intended, you may need to add the appropriate configuration.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Initialize Mixpanel (disabled in dev unless VITE_ENABLE_ANALYTICS is set)
const isProduction = import.meta.env.PROD
const analyticsEnabled = isProduction || import.meta.env.VITE_ENABLE_ANALYTICS === 'true'
if (analyticsEnabled) {
mixpanel.init('c7ded934ffc012d90c2c3f3f2e8fd8aa', {
debug: !isProduction,
track_pageview: false,
persistence: 'localStorage',
autocapture: false,
})
}
// Initialize Mixpanel (disabled in dev unless VITE_ENABLE_ANALYTICS is set)
const isProduction = import.meta.env.PROD
const analyticsEnabled = isProduction || import.meta.env.VITE_ENABLE_ANALYTICS === 'true'
if (analyticsEnabled) {
mixpanel.init(import.meta.env.VITE_MIXPANEL_TOKEN, {
debug: !isProduction,
track_pageview: false,
persistence: 'localStorage',
autocapture: false,
})
}
🤖 Prompt for AI Agents
In apps/agentic-chat/src/main.tsx around lines 13 to 24, the Mixpanel project
token is hardcoded; replace the literal token with a value read from an
environment variable (e.g., import.meta.env.VITE_MIXPANEL_TOKEN) and fallback
gracefully if it's missing, then add
VITE_MIXPANEL_TOKEN=your_mixpanel_token_here to .env.example; additionally, if
"100% session replay" is intended, include the appropriate session replay
configuration option in the mixpanel.init call per Mixpanel docs.

@premiumjibles premiumjibles merged commit 6909d11 into main Nov 27, 2025
4 checks passed
@premiumjibles premiumjibles deleted the mixpanel branch November 27, 2025 00:54
@coderabbitai coderabbitai bot mentioned this pull request Nov 27, 2025
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.

3 participants