feat: track trial banner impressions and CTA clicks in PostHog#1699
feat: track trial banner impressions and CTA clicks in PostHog#1699WcaleNieWolny wants to merge 7 commits intomainfrom
Conversation
📝 WalkthroughWalkthroughAdds PostHog analytics to TrialBanner: tracks banner visibility and CTA clicks, sending trial_days_left and org_gid; updates pushEvent to accept optional properties passed to posthog.capture. Changes
Sequence Diagram(s)sequenceDiagram
participant User as "User (viewer / clicker)"
participant Banner as "TrialBanner.vue"
participant Config as "LocalConfig (getLocalConfig)"
participant PH as "PostHog Service (pushEvent)"
User->>Banner: view page / move mouse / click CTA
Banner->>Config: getLocalConfig()
Config-->>Banner: { org_gid, trial_days_left, supaHost }
Banner->>PH: pushEvent(eventName, supaHost, { trial_days_left, org_gid })
PH->>PH: posthog.capture(eventName, properties)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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 |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/dashboard/TrialBanner.vue`:
- Around line 18-20: The import statements in TrialBanner.vue are out of the
required sort order and trigger perfectionist/sort-imports (CI fails); reorder
the imports so they follow the project's import sorting rules (e.g., group
external packages first, then internal services/stores), placing pushEvent and
getLocalConfig in the correct alphabetical/grouped positions relative to
useOrganizationStore, then run bun lint:fix to confirm the fix; check the import
lines that reference useOrganizationStore, pushEvent, and getLocalConfig to
verify ordering.
There was a problem hiding this comment.
Pull request overview
Adds PostHog instrumentation for the dashboard trial banner, and extends the existing pushEvent helper to support custom event properties so funnel events can include org/trial context.
Changes:
- Extend
pushEventto accept optionalpropertiesand forward them toposthog.capture. - Track
trial_banner_shownwhen the trial banner becomes active. - Track
trial_banner_cta_clickedwhen the “View Plans” CTA is clicked, includingtrial_days_leftandorg_gid.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/services/posthog.ts | Extends pushEvent to accept optional event properties for PostHog capture calls. |
| src/components/dashboard/TrialBanner.vue | Emits PostHog events for banner impression and CTA click, attaching org/trial properties. |
- pushEvent properties now typed as Record<string, string|number|boolean|null> to prevent accidental non-serializable values (Vue refs, Dates, etc.) - Time tick now starts when account-age check could still flip (trial user with apps, not yet 3h old) instead of only when banner is visible, so showBanner can turn true without a page reload - Mousemove listener still gated on showBanner (expensive)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/dashboard/TrialBanner.vue`:
- Around line 145-154: The watcher on showBanner currently calls
trackBannerEvent('trial_banner_shown') on every false→true transition (and
re-attaches mousemove), causing duplicate impressions; add a one-shot guard
(e.g., a boolean like hasTrackedTrialBanner) scoped near the component setup and
check it inside the watcher so trackBannerEvent is only invoked once (set
hasTrackedTrialBanner=true after firing), but keep the existing
window.addEventListener/ removeEventListener logic for handleMouseMove so the
mouse tracking still attaches/detaches on visibility changes.
| // Only attach the mousemove listener (expensive) when the banner is visible. | ||
| watch(showBanner, (visible) => { | ||
| if (visible) { | ||
| trackBannerEvent('trial_banner_shown') | ||
| window.addEventListener('mousemove', handleMouseMove) | ||
| } | ||
| else { | ||
| window.removeEventListener('mousemove', handleMouseMove) | ||
| if (tickInterval) { | ||
| clearInterval(tickInterval) | ||
| tickInterval = null | ||
| } | ||
| } | ||
| }, { immediate: true }) |
There was a problem hiding this comment.
trial_banner_shown can fire more than once if the org store refreshes.
The watcher fires on every false → true transition of showBanner. If useOrganizationStore polls/refreshes in the background and briefly nullifies currentOrganization, showBanner drops to false then immediately returns to true, emitting a second impression event and inflating the PostHog funnel count.
Guard with a one-shot flag:
🛡️ Proposed fix — emit only on the first impression
+const bannerShownTracked = ref(false)
+
watch(showBanner, (visible) => {
if (visible) {
- trackBannerEvent('trial_banner_shown')
+ if (!bannerShownTracked.value) {
+ trackBannerEvent('trial_banner_shown')
+ bannerShownTracked.value = true
+ }
window.addEventListener('mousemove', handleMouseMove)
}
else {
window.removeEventListener('mousemove', handleMouseMove)
}
}, { immediate: true })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/dashboard/TrialBanner.vue` around lines 145 - 154, The watcher
on showBanner currently calls trackBannerEvent('trial_banner_shown') on every
false→true transition (and re-attaches mousemove), causing duplicate
impressions; add a one-shot guard (e.g., a boolean like hasTrackedTrialBanner)
scoped near the component setup and check it inside the watcher so
trackBannerEvent is only invoked once (set hasTrackedTrialBanner=true after
firing), but keep the existing window.addEventListener/ removeEventListener
logic for handleMouseMove so the mouse tracking still attaches/detaches on
visibility changes.
|



Summary
pushEventinsrc/services/posthog.tsto accept optional propertiestrial_banner_shownwhen the trial banner becomes visibletrial_banner_cta_clickedwhen user clicks the "View Plans" CTAtrial_days_leftandorg_gidpropertiesPostHog Funnel
trial_banner_shown→trial_banner_cta_clicked→User visit(plans page) → checkoutTest plan
trial_banner_shownevent appears in PostHog with correct propertiestrial_banner_cta_clickedevent appears in PostHog with correct propertiespushEventcallers (onboarding steps) still work without third argumentSummary by CodeRabbit