Skip to content

Track session metrics accurately#437

Merged
Producdevity merged 5 commits into
stagingfrom
fix/session-tracking-metrics
Jun 6, 2026
Merged

Track session metrics accurately#437
Producdevity merged 5 commits into
stagingfrom
fix/session-tracking-metrics

Conversation

@Producdevity

@Producdevity Producdevity commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Description

Tracks session metrics from actual client activity instead of fixed placeholders:

  • derives the sign-in method from Clerk OAuth account data, with email and Clerk fallbacks
  • counts route-driven page views for the session summary
  • counts basic document interactions for the session summary

Fixes #392

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactor
  • Other (please describe):

How Has This Been Tested?

  • Local build
  • Lint
  • Typecheck
  • Unit tests
  • Manual testing

Checks run:

  • ./node_modules/.bin/vitest run src/components/SessionTracker.test.tsx
  • ./node_modules/.bin/eslint src/components/SessionTracker.tsx src/components/SessionTracker.test.tsx
  • ./node_modules/.bin/next typegen
  • ./node_modules/.bin/tsc --noEmit
  • git diff --check

Screenshots (if applicable)

N/A

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have made corresponding changes to the documentation
  • I have checked that all checks (lint, typecheck, test) pass

Notes for reviewers

The temp worktree reused the already-installed dependency tree and generated Prisma client from the main checkout for local verification, then ran Next type generation before TypeScript to match the repo's types script order.

Summary by CodeRabbit

  • New Features
    • Improved sign-in attribution for analytics (OAuth/email/default) and consistent user attribution across session events.
    • More accurate session analytics: duration, page view counts, interaction tracking; page-view load time made optional.
  • Tests
    • Added tests for consent-respected analytics, session start/page view behavior, session end payloads, and sign-in attribution.
  • Chores
    • Switched analytics to Google Analytics, updated environment and CSP/configuration entries, and removed Vercel analytics packages.
  • Documentation
    • Privacy page "Last updated" date and third‑party description updated.

@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
emuready Ready Ready Preview, Comment Jun 6, 2026 2:07pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6adfdf2f-bb27-4e45-b817-a576b6a6963e

📥 Commits

Reviewing files that changed from the base of the PR and between d0f9673 and fd17056.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • .env.docker.example
  • .env.example
  • .env.test.example
  • next.config.ts
  • package.json
  • playwright.config.ts
  • pnpm-workspace.yaml
  • src/app/layout.tsx
  • src/app/privacy/page.tsx
  • src/lib/analytics/utils/sendAnalyticsEvent.test.ts
  • src/lib/analytics/utils/sendAnalyticsEvent.ts
  • src/lib/env.ts
  • tests/helpers/external-services.ts
  • tests/third-party-services.spec.ts
💤 Files with no reviewable changes (11)
  • tests/helpers/external-services.ts
  • playwright.config.ts
  • .env.example
  • .env.docker.example
  • src/app/layout.tsx
  • .env.test.example
  • tests/third-party-services.spec.ts
  • package.json
  • pnpm-workspace.yaml
  • next.config.ts
  • src/lib/env.ts

Walkthrough

SessionTracker now resolves Clerk sign-in method (OAuth/email/clerk), caches current userId, counts per-session page views and interactions, emits user.signedIn on userId transition, reports accumulated duration/pageViews/interactions on beforeunload, and includes tests plus an analytics pageView param change.

Changes

Session Tracking Improvements

Layer / File(s) Summary
Type contracts and sign-in resolution helpers
src/components/SessionTracker.tsx
Adds SignInMethod/ClerkUser aliases, interaction event list, provider→method mapper, getSignInMethod, and refs including currentUserIdRef, pageViewCountRef, and interaction counters.
Session init and userId sync
src/components/SessionTracker.tsx
Initializes session (sessionId, initial page-view start timestamp) and keeps currentUserIdRef synchronized with userId.
Sign-in attribution effect
src/components/SessionTracker.tsx
Emits analytics.user.signedIn on null→non-null Clerk user transitions using the resolved sign-in method (skips initial session start) and requires analytics consent.
Page view, optional loadTime, and feature discovery
src/components/SessionTracker.tsx, src/lib/analytics/analytics.ts
sessionStarted sends current userId; pageView now optionally accepts loadTime, increments a per-session page view counter, uses currentUserIdRef for userId, and triggers first-time feature discovery. (analytics.session.pageView.loadTime is now optional.)
Interaction counting
src/components/SessionTracker.tsx
Attaches capturing DOM listeners for configured interaction events and tallies interactions in a ref.
Session end with accumulated metrics
src/components/SessionTracker.tsx
beforeunload handler reports accumulated duration, pageViews, and interactions using refs and currentUserIdRef.
Comprehensive test suite
src/components/SessionTracker.test.tsx
Adds Vitest + React Testing Library tests with hoisted mocks for Clerk useUser, Next.js usePathname, cookie consent, and @/lib/analytics. Tests cover consent gating, lifecycle events, metrics accumulation, and OAuth/email/clerk attribution fallbacks.
sendAnalyticsEvent: remove Vercel track & GA-only dispatch
src/lib/analytics/utils/sendAnalyticsEvent.ts, src/lib/analytics/utils/sendAnalyticsEvent.test.ts
Removes @vercel/analytics track usage, merges params.metadata into event payload, logs in dev and returns early, and dispatches via Google Analytics (sendGAEvent) when GA_ID is present; tests updated accordingly.
Env, examples, and layout updates
src/lib/env.ts, .env*.example, src/app/layout.tsx
Removes Vercel-specific env toggle from examples, adds new public example vars, replaces Vercel analytics in layout with Google Analytics, and exposes new env flags (ENABLE_SW, DISABLE_COOKIE_BANNER).
CSP, deps, and test infra
next.config.ts, package.json, playwright.config.ts, pnpm-workspace.yaml, tests/helpers/*, tests/third-party-services.spec.ts
Updates CSP script/connect sources to include GTM and Cloudflare Insights, removes Vercel script source, deletes Vercel analytics/speed-insights dependencies, updates Playwright env overrides, adjusts pnpm allowBuilds, and removes Vercel speed-insights test mocks/patterns.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Producdevity/EmuReady#362: related layout telemetry/analytics wiring changes (both adjust GA/Kofi/Vercel analytics rendering and session/view tracking).
🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main objective of the PR—tracking session metrics accurately—which aligns with the primary changes across SessionTracker, analytics integration, and supporting configuration updates.
Description check ✅ Passed The description follows the template structure, includes the fixed issue number (#392), specifies the type of change (New feature), documents testing steps and checks performed, and completes all critical checklist items.
Linked Issues check ✅ Passed All three coding requirements from issue #392 are addressed: sign-in method derived from Clerk OAuth data with fallbacks [#392], per-session page view counting implemented [#392], and per-session interaction counting implemented [#392].
Out of Scope Changes check ✅ Passed Changes to analytics configuration (Vercel to Google Analytics migration) support the core tracking improvements by removing conflicting analytics integrations and are necessary for accurate session metric tracking.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/session-tracking-metrics
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/session-tracking-metrics

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.

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

Caution

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

⚠️ Outside diff range comments (1)
src/components/SessionTracker.tsx (1)

113-150: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

loadTime is measuring dwell time on the previous page, not the new route's load.

Line 149 resets pageLoadTimeRef after the current page view is emitted. On the next pathname change, Line 113 subtracts that stale timestamp, so a user who spends five minutes on /listings will report roughly five minutes of loadTime for /games. That writes inflated metrics into analytics.session.pageView and undermines the accuracy goal of this PR. Capture a route-start timestamp when navigation begins, or stop sending this field for client-side navigations until that signal exists.

🤖 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/components/SessionTracker.tsx` around lines 113 - 150, The current
loadTime calculation uses pageLoadTimeRef.current which is reset after emitting
a pageView, so on the next pathname change you end up reporting the previous
page's dwell as the new page's loadTime; to fix this, capture a route-start
timestamp when navigation begins (e.g., on your router's routeChangeStart or
equivalent) and set pageLoadTimeRef.current there, then only compute and include
loadTime in analytics.session.pageView when that route-start timestamp exists
(otherwise omit or null the loadTime); update references in this component
(pageLoadTimeRef, loadTime, analytics.session.pageView, pathname, the useEffect
depending on [analyticsAllowed, pathname]) so you no longer reset
pageLoadTimeRef.current only after emitting the pageView but instead set it at
navigation start and reset/update it after the corresponding pageView is sent.
🧹 Nitpick comments (1)
src/components/SessionTracker.test.tsx (1)

100-100: 💤 Low value

Consider adding a comment to explain the pageView count.

The assertion that pageView is called once verifies that user sign-in alone does not trigger additional page views (only pathname changes do). A brief comment would clarify this subtle invariant.

📝 Suggested comment
+    // pageView should still be 1 (user sign-in does not trigger pageView)
     expect(testState.analytics.session.pageView).toHaveBeenCalledOnce()
🤖 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/components/SessionTracker.test.tsx` at line 100, Add a brief inline
comment above the assertion in SessionTracker.test.tsx that explains why
expect(testState.analytics.session.pageView).toHaveBeenCalledOnce() is asserted
(i.e., to ensure that user sign-in does not create additional page views and
only pathname changes should increment pageView); place the comment directly
above the expect call so future readers understand the subtle invariant being
tested.
🤖 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 `@src/components/SessionTracker.test.tsx`:
- Around line 44-123: The tests are missing coverage for the analytics-privacy
path where testState.analyticsAllowed is false; add a new spec in
SessionTracker.test.tsx that sets testState.analyticsAllowed = false, renders
<SessionTracker />, waits briefly (e.g., via setTimeout or waitFor) and then
asserts that testState.analytics.session.sessionStarted and
testState.analytics.session.pageView were not called; reference the existing
test patterns (render(<SessionTracker />),
testState.analytics.session.sessionStarted,
testState.analytics.session.pageView) to mirror style and placement alongside
the other it(...) blocks.
- Around line 80-122: Add a new test in SessionTracker.test.tsx that exercises
the third branch of getSignInMethod by rendering <SessionTracker />, waiting for
testState.analytics.session.sessionStarted, then setting testState.user = { id:
'user-3', primaryEmailAddress: null } (no externalAccounts) and rerendering the
component; finally assert that testState.analytics.user.signedIn was called with
{ method: 'clerk', userId: 'user-3' } to verify the clerk fallback.
- Around line 44-49: Add explicit mock clearing to ensure tests are isolated:
update the test setup for the SessionTracker suite to call Jest's mock
reset/clear (e.g., jest.clearAllMocks() or jest.resetAllMocks()) in the
beforeEach or in an afterEach so mock call counts are reset between tests; apply
this change near the existing beforeEach block that sets
testState.analyticsAllowed, testState.pathname and testState.user so assertions
like toHaveBeenCalledOnce() only see calls from the current test.

---

Outside diff comments:
In `@src/components/SessionTracker.tsx`:
- Around line 113-150: The current loadTime calculation uses
pageLoadTimeRef.current which is reset after emitting a pageView, so on the next
pathname change you end up reporting the previous page's dwell as the new page's
loadTime; to fix this, capture a route-start timestamp when navigation begins
(e.g., on your router's routeChangeStart or equivalent) and set
pageLoadTimeRef.current there, then only compute and include loadTime in
analytics.session.pageView when that route-start timestamp exists (otherwise
omit or null the loadTime); update references in this component
(pageLoadTimeRef, loadTime, analytics.session.pageView, pathname, the useEffect
depending on [analyticsAllowed, pathname]) so you no longer reset
pageLoadTimeRef.current only after emitting the pageView but instead set it at
navigation start and reset/update it after the corresponding pageView is sent.

---

Nitpick comments:
In `@src/components/SessionTracker.test.tsx`:
- Line 100: Add a brief inline comment above the assertion in
SessionTracker.test.tsx that explains why
expect(testState.analytics.session.pageView).toHaveBeenCalledOnce() is asserted
(i.e., to ensure that user sign-in does not create additional page views and
only pathname changes should increment pageView); place the comment directly
above the expect call so future readers understand the subtle invariant being
tested.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 48437ec7-7d11-4083-ba7b-8d3cfb1948ee

📥 Commits

Reviewing files that changed from the base of the PR and between 5b70a20 and a91d31c.

📒 Files selected for processing (2)
  • src/components/SessionTracker.test.tsx
  • src/components/SessionTracker.tsx

Comment thread src/components/SessionTracker.test.tsx
Comment thread src/components/SessionTracker.test.tsx
Comment thread src/components/SessionTracker.test.tsx Outdated
@Producdevity Producdevity merged commit 172be73 into staging Jun 6, 2026
8 checks passed
@Producdevity Producdevity deleted the fix/session-tracking-metrics branch June 6, 2026 14:40
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.

feat: improve session tracking (SSO method, page views, interactions)

1 participant