Skip to content

feat: track trial banner impressions and CTA clicks in PostHog#1699

Open
WcaleNieWolny wants to merge 7 commits intomainfrom
feat/trial-banner-tracking
Open

feat: track trial banner impressions and CTA clicks in PostHog#1699
WcaleNieWolny wants to merge 7 commits intomainfrom
feat/trial-banner-tracking

Conversation

@WcaleNieWolny
Copy link
Contributor

@WcaleNieWolny WcaleNieWolny commented Feb 25, 2026

Summary

  • Extends pushEvent in src/services/posthog.ts to accept optional properties
  • Tracks trial_banner_shown when the trial banner becomes visible
  • Tracks trial_banner_cta_clicked when user clicks the "View Plans" CTA
  • Both events include trial_days_left and org_gid properties

PostHog Funnel

trial_banner_showntrial_banner_cta_clickedUser visit (plans page) → checkout

Test plan

  • Log in as a trial user with an app created and account 3+ hours old
  • Verify trial_banner_shown event appears in PostHog with correct properties
  • Click the "View Plans" CTA
  • Verify trial_banner_cta_clicked event appears in PostHog with correct properties
  • Verify existing pushEvent callers (onboarding steps) still work without third argument

Summary by CodeRabbit

  • New Features
    • Trial banner now records impressions and CTA clicks to improve measurement of trial engagement.
    • Event tracking updated to allow richer contextual properties with analytics events for better insights.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
TrialBanner analytics
src/components/dashboard/TrialBanner.vue
Adds event tracking: emits trial_banner_shown when banner becomes visible, starts/stops mousemove listener and periodic tick, and logs trial_banner_cta_clicked on CTA via pushEvent with trial_days_left and org_gid.
PostHog service
src/services/posthog.ts
Extends pushEvent(nameEvent, supaHost, properties?); adds JsonPrimitive and PostHogProperties types and forwards optional properties to posthog.capture.

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)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped to the banner with ears all a-twitch,
I nudged the CTA and sent data in a stitch,
Days left and orgs in a gentle refrain,
PostHog notes footsteps across the plain —
A rabbit’s small cheer for events well-tracked.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main changes: adding PostHog tracking for trial banner impressions and CTA clicks.
Description check ✅ Passed Description covers all required template sections with clear summary, comprehensive test plan, and implementation details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/trial-banner-tracking

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@WcaleNieWolny WcaleNieWolny marked this pull request as ready for review February 25, 2026 13:35
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Contributor

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

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edd91bb and b87a075.

📒 Files selected for processing (2)
  • src/components/dashboard/TrialBanner.vue
  • src/services/posthog.ts

Copy link
Contributor

Copilot AI left a comment

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 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 pushEvent to accept optional properties and forward them to posthog.capture.
  • Track trial_banner_shown when the trial banner becomes active.
  • Track trial_banner_cta_clicked when the “View Plans” CTA is clicked, including trial_days_left and org_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.

WcaleNieWolny and others added 3 commits February 25, 2026 14:54
- 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)
Copy link
Contributor

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

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5364c9 and 3a7cba1.

📒 Files selected for processing (2)
  • src/components/dashboard/TrialBanner.vue
  • src/services/posthog.ts

Comment on lines +145 to 154
// 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 })
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

@sonarqubecloud
Copy link

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