Skip to content

Conversation

@jakejarvis
Copy link
Owner

@jakejarvis jakejarvis commented Nov 15, 2025

Summary by CodeRabbit

  • New Features

    • Added server-side analytics tracking for domain page views.
  • Refactor

    • Unified analytics API and migrated components/hooks to the new tracking interface and hook.
    • Replaced direct analytics side-effects in several UI areas with hook-based tracking.
    • Removed copy-button telemetry and eliminated some client-side automatic analytics side-effects.
  • Tests

    • Updated analytics mocks to the unified interface and added a ResizeObserver mock.
  • Chores

    • Improved server-side error telemetry, instrumentation, and background task handling.

@vercel
Copy link

vercel bot commented Nov 15, 2025

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

Project Deployment Preview Comments Updated (UTC)
domainstack Ready Ready Preview Comment Nov 15, 2025 8:58pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

Replaces legacy capture-style analytics with a unified analytics object (client + server) and a useAnalytics hook; adds server-side analytics.track on the domain page; refactors client components, hooks, tests, and test setup to use the new API; removes some client-side telemetry calls.

Changes

Cohort / File(s) Summary
Core analytics API
lib/analytics/client.ts, lib/analytics/server.ts
Replaced exported captureClient/captureServer with a public analytics object exposing track(...) and trackException(...). Added useAnalytics() hook (client). Internal helpers wrap PostHog calls with try/catch and background flush semantics; some previously-exported helpers are now internal.
Server page instrumentation
app/[domain]/page.tsx
Added server-side call to analytics.track("report_viewed", { domain: normalized }) during server rendering before data prefetch.
Error instrumentation
instrumentation.ts
Replaced direct PostHog usage with analytics.trackException(error, { path, method }); renamed parameter errerror.
Client components — hook adoption
components/domain/domain-report-header.tsx, components/domain/domain-suggestions-client.tsx
Replaced captureClient imports with useAnalytics(); obtain analytics via the hook and call analytics.track(...) for events.
Client components — telemetry removed
components/copy-button.tsx, components/domain/domain-report-view.tsx
Removed analytics imports and tracking calls (copy/export/registration-related events); UI behavior and flows otherwise unchanged.
Hooks using analytics object
hooks/use-domain-export.ts, hooks/use-domain-search.ts
Replaced captureClient usage with analytics/useAnalytics, using analytics.track(...) for events and analytics.trackException(...) for errors; preserved hook signatures and control flow.
Tests and test setup
components/domain/domain-report-view.test.tsx, vitest.setup.ts
Removed mocks/assertions for captureClient; updated test mocks to provide analytics.track/trackException and a useAnalytics implementation. Added global ResizeObserver mock.
Background scheduling update
lib/ratelimit.ts
Replaced Vercel waitUntil usage with Next.js after for background analytics tasks on res.pending.

Sequence Diagram(s)

sequenceDiagram
  participant Comp as Client Component / Hook
  participant Hook as useAnalytics()
  participant AC as analytics (client)
  participant Page as Server Page (app/[domain]/page)
  participant AS as analytics (server)
  participant PH as PostHog SDK

  rect rgba(135,206,235,0.12)
  Note over Comp,Hook: Client-side event flow (hook)
  Comp->>Hook: call useAnalytics()
  Hook-->>Comp: { track, trackException }
  Comp->>AC: track(event, props)
  AC->>PH: posthog.capture(event, props)
  end

  rect rgba(255,228,196,0.12)
  Note over Page,AS: Server-side event during SSR
  Page->>AS: analytics.track("report_viewed", { domain })
  AS->>PH: posthog.capture(event, props)
  end
Loading

Poem

🐇 I swapped my hops for an object bright,
I track each nibble, click, and flight,
Hooks lend a paw and send the cheer,
Exceptions caught without a fear,
A carrot-hop for tidy sight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 pull request title accurately and specifically describes the main change: refactoring analytics integration to use unified tracking methods across both client and server implementations.
✨ 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 refactor/analytics-abstraction

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad37ee3 and eb8bb8e.

📒 Files selected for processing (2)
  • lib/analytics/server.ts (3 hunks)
  • lib/ratelimit.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
lib/analytics/server.ts (1)
lib/analytics/client.ts (1)
  • analytics (26-29)
🔇 Additional comments (3)
lib/ratelimit.ts (1)

5-5: LGTM! Clean migration to Next.js after().

The switch from Vercel's waitUntil to Next.js's after() correctly preserves the background execution semantics for rate limit analytics. Error handling appropriately ensures graceful degradation if after() is unavailable.

Also applies to: 69-71

lib/analytics/server.ts (2)

11-25: LGTM! Appropriate scope change.

Converting getServerPosthog to an internal function correctly encapsulates the implementation while the public analytics object provides a cleaner API surface.


27-49: LGTM! Correct use of React cache().

Wrapping getDistinctId with React's cache() ensures that multiple calls within the same request reuse the same distinct ID, which is the correct pattern for server components.


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.

@codecov
Copy link

codecov bot commented Nov 15, 2025

Codecov Report

❌ Patch coverage is 60.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.38%. Comparing base (d4a43c8) to head (eb8bb8e).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
hooks/use-domain-export.ts 33.33% 2 Missing ⚠️
components/domain/domain-report-header.tsx 50.00% 1 Missing ⚠️
components/domain/domain-suggestions-client.tsx 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #181      +/-   ##
==========================================
- Coverage   69.39%   69.38%   -0.01%     
==========================================
  Files         103      103              
  Lines        2908     2904       -4     
  Branches      891      889       -2     
==========================================
- Hits         2018     2015       -3     
  Misses        551      551              
+ Partials      339      338       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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: 4

Caution

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

⚠️ Outside diff range comments (1)
lib/analytics/server.ts (1)

11-25: Restore getServerPosthog export or refactor instrumentation.ts to fix breaking change.

The function getServerPosthog is no longer exported from lib/analytics/server.ts, but instrumentation.ts (line 17-18) still imports and calls it. This will cause a runtime error: export 'getServerPosthog' was not found in '@/lib/analytics/server'. Either re-export the function or update the instrumentation file to use the exported analytics object instead.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4a43c8 and 47b32c0.

📒 Files selected for processing (11)
  • app/[domain]/page.tsx (2 hunks)
  • components/copy-button.tsx (1 hunks)
  • components/domain/domain-report-header.tsx (3 hunks)
  • components/domain/domain-report-view.test.tsx (0 hunks)
  • components/domain/domain-report-view.tsx (1 hunks)
  • components/domain/domain-suggestions-client.tsx (4 hunks)
  • hooks/use-domain-export.ts (3 hunks)
  • hooks/use-domain-search.ts (3 hunks)
  • lib/analytics/client.ts (1 hunks)
  • lib/analytics/server.ts (3 hunks)
  • vitest.setup.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • components/domain/domain-report-view.test.tsx
🧰 Additional context used
🧬 Code graph analysis (7)
components/domain/domain-suggestions-client.tsx (1)
lib/analytics/client.ts (2)
  • analytics (25-28)
  • useAnalytics (41-46)
components/domain/domain-report-header.tsx (1)
lib/analytics/client.ts (2)
  • analytics (25-28)
  • useAnalytics (41-46)
app/[domain]/page.tsx (1)
lib/analytics/server.ts (1)
  • analytics (55-103)
lib/analytics/client.ts (1)
lib/analytics/server.ts (1)
  • analytics (55-103)
hooks/use-domain-export.ts (2)
lib/analytics/client.ts (1)
  • analytics (25-28)
lib/analytics/server.ts (1)
  • analytics (55-103)
lib/analytics/server.ts (1)
lib/analytics/client.ts (1)
  • analytics (25-28)
hooks/use-domain-search.ts (2)
lib/analytics/client.ts (1)
  • analytics (25-28)
lib/analytics/server.ts (1)
  • analytics (55-103)
🔇 Additional comments (19)
components/copy-button.tsx (1)

17-34: Verify: Analytics tracking removed - is this intentional?

The copy_clicked event tracking has been completely removed from this component. Given that the PR is about refactoring analytics (not removing it), this appears to be an unintentional loss of telemetry.

If this removal was intentional, please confirm. Otherwise, consider restoring analytics tracking using the new API:

+"use client";
+
 import { Check, ClipboardCheck, Copy } from "lucide-react";
 import { useRef, useState } from "react";
 import { toast } from "sonner";
 import { Button } from "@/components/ui/button";
+import { useAnalytics } from "@/lib/analytics/client";

 interface CopyButtonProps {
   value: string;
   label?: string;
 }

 export function CopyButton({ value, label }: CopyButtonProps) {
+  const analytics = useAnalytics();
   const [copied, setCopied] = useState(false);
   const resetTimerRef = useRef<number | null>(null);

   const handleCopy = () => {
     navigator.clipboard.writeText(value);
+
+    analytics.track("copy_clicked", {
+      label,
+      value_length: value.length,
+    });

     toast.success("Copied!", {
components/domain/domain-report-view.tsx (1)

79-117: LGTM - Analytics moved to server-side.

The removal of client-side analytics side effects from this component aligns with the PR's objective to consolidate tracking. Based on the AI summary, domain page view tracking has been moved to the server-side in app/[domain]/page.tsx.

Please confirm that the server-side tracking in app/[domain]/page.tsx captures the equivalent analytics events that were previously tracked here (e.g., registration state resolution events).

components/domain/domain-report-header.tsx (2)

8-8: LGTM - Clean migration to new analytics API.

The import has been correctly updated to use the new useAnalytics hook.


25-37: LGTM - Proper hook usage and event tracking.

The component correctly initializes analytics via the useAnalytics() hook and uses analytics.track() for event tracking, following the recommended pattern for React components.

vitest.setup.ts (2)

4-20: LGTM - Comprehensive mock updates for new analytics API.

The test mocks have been properly updated to reflect the new analytics API surface:

  • Server analytics mock provides async track and trackException methods
  • Client analytics mock provides both the analytics object and useAnalytics hook
  • All mocks use vi.fn() for proper test spy capabilities

25-30: LGTM - ResizeObserver mock added.

The ResizeObserver mock is correctly implemented with spies for observe, unobserve, and disconnect methods, which is necessary for jsdom-based tests.

hooks/use-domain-export.ts (3)

4-4: LGTM - Correct import for hook context.

Using the analytics object directly (rather than useAnalytics hook) is the correct pattern for custom hooks, as documented in lib/analytics/client.ts.


58-58: LGTM - Clean event tracking.

The export click event is properly tracked using the new API.


87-92: LGTM - Proper exception handling.

The error tracking correctly wraps non-Error objects into Error instances before passing to trackException, ensuring type safety.

hooks/use-domain-search.ts (3)

9-9: LGTM - Correct import for hook context.

Using the analytics object directly is appropriate for custom hooks, as per the API documentation.


82-85: LGTM - Search submission tracking.

The event tracking has been properly migrated to the new API while preserving the event name and payload structure.


107-110: LGTM - Invalid input tracking.

The error tracking maintains the same event name and payload structure with the new API.

lib/analytics/client.ts (2)

5-19: LGTM - Robust error handling.

Both track and trackException functions are wrapped in try-catch blocks to prevent analytics failures from breaking the application. This is a best practice for analytics implementations.


21-28: LGTM - Clear API surface for non-React contexts.

The analytics object provides a clean interface for use in hooks and other non-component code.

components/domain/domain-suggestions-client.tsx (4)

15-15: LGTM - Correct import for component usage.

Using the useAnalytics hook is the recommended pattern for React components.


33-33: LGTM - Proper hook initialization.

The analytics hook is correctly initialized at the component level.


107-110: LGTM - Suggestion click tracking.

The event tracking has been properly migrated while preserving the event name and payload structure.


118-120: LGTM - History clear tracking.

The history clear event is properly tracked using the new API.

lib/analytics/server.ts (1)

27-49: No external usage detected—change is safe.

Verification confirms that getDistinctId is not imported or referenced outside lib/analytics/server.ts. The visibility change from exported to internal poses no breaking changes.

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

♻️ Duplicate comments (1)
lib/analytics/server.ts (1)

11-49: Critical: shutdown() on a shared PostHog client can break analytics after the first event

You’re initializing a module-scoped sharedClient and then calling await client.shutdown() on every track/trackException call. In the PostHog Node SDK, shutdown() is meant as a terminal operation (flush + close) for short-lived processes. On a reused client, this can make subsequent captures no-op or error, effectively disabling server-side analytics once the first event is processed. This is the same issue previously flagged on earlier revisions.

To keep the fire-and-forget semantics while avoiding tearing down the shared client, you can switch to flush() (or explicitly reset sharedClient after shutdown). For example:

@@ export const analytics = {
   track: (
     event: string,
     properties: Record<string, unknown>,
     distinctId?: string,
   ) => {
@@
-      // flush events to posthog
+      // flush events to PostHog without shutting down the shared client
       try {
-        await client.shutdown();
+        await client.flush();
       } catch {
         // no-op
       }
@@
   trackException: (
     error: Error,
     properties: Record<string, unknown>,
     distinctId?: string | null,
   ) => {
@@
-      // flush events to posthog
+      // flush events to PostHog without shutting down the shared client
       try {
-        await client.shutdown();
+        await client.flush();
       } catch {
         // no-op
       }

If you prefer to keep shutdown() for some reason, you should at least clear the module-scoped client so the next call reinitializes a fresh instance:

-      try {
-        await client.shutdown();
-      } catch {
-        // no-op
-      }
+      try {
+        await client.shutdown();
+      } catch {
+        // no-op
+      } finally {
+        sharedClient = null;
+      }

Please double-check the exact behavior in your posthog-node version to confirm whether shutdown() allows safe reuse of the client; if not, one of the above patterns will be safer long-term.

Confirm in the official `posthog-node` documentation for your exact version whether `shutdown()` is intended for per-process teardown (and not for per-event use) and whether a client can safely be reused after calling `shutdown()`. Also check the recommended pattern for long-lived servers vs. short-lived serverless functions (e.g., using `flush()` for the former).

Also applies to: 51-129

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47b32c0 and 91ce358.

📒 Files selected for processing (4)
  • app/[domain]/page.tsx (2 hunks)
  • instrumentation.ts (2 hunks)
  • lib/analytics/client.ts (1 hunks)
  • lib/analytics/server.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
lib/analytics/server.ts (1)
lib/analytics/client.ts (1)
  • analytics (26-29)
lib/analytics/client.ts (1)
lib/analytics/server.ts (1)
  • analytics (58-130)
app/[domain]/page.tsx (1)
lib/analytics/server.ts (1)
  • analytics (58-130)
instrumentation.ts (1)
lib/analytics/server.ts (1)
  • analytics (58-130)
🔇 Additional comments (2)
app/[domain]/page.tsx (1)

5-5: Server-side pageview tracking looks correct and non-blocking

Importing the server analytics helper and calling analytics.track("report_viewed", { domain: normalized }) post-canonicalization is consistent with the new fire-and-forget server API and avoids blocking render.

Also applies to: 51-52

lib/analytics/client.ts (1)

4-50: Client analytics wrapper and hook are clean and aligned with server API

The track/trackException wrappers with defensive try/catch, exported analytics object, and useAnalytics returning a memoized { track, trackException } give a consistent, low-friction client API that matches the server-side shape. Nice job addressing the stable-reference concern with useMemo.

@jakejarvis jakejarvis merged commit b7df544 into main Nov 15, 2025
6 checks passed
@jakejarvis jakejarvis deleted the refactor/analytics-abstraction branch November 15, 2025 21:01
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.

2 participants