-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add mixpanel #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add mixpanel #129
Conversation
📝 WalkthroughWalkthroughThe 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 ( Changes
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
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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
42a9bb1 to
aaf7fa4
Compare
bf954c1 to
b385502
Compare
75b1671 to
d0aaf9d
Compare
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.
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 theonFinishcallback (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.
⛔ Files ignored due to path filters (1)
bun.lockis 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
AppContentis clean and allows theuseWalletAnalyticshook to be called within the provider context. This maintains existing routing behavior while adding analytics support.
56-64: LGTM!The
Appcomponent now properly composesAppContent, 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 solidEncapsulating all tracking behind a single
analyticsobject with ananalyticsEnabledgate and typed props keeps call sites clean and safe; the no-op behavior when disabled is especially helpful for local/dev environments.
| 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]) |
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.
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.
| // 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, | ||
| }) | ||
| } |
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.
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.
| // 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.
Integrates Mixpanel for product analytics.
Also fixed a bunch of issues related to lock file generation.
Changes
New Dependencies
mixpanel-browserSummary by CodeRabbit
New Features
VITE_ENABLE_ANALYTICSenvironment variable.Chores
✏️ Tip: You can customize this high-level summary in your review settings.