Display anonymous analytics for generated public audit pages inside the internal dashboard using the self-hosted Rybbit API. The internal dashboard itself is not tracked. Rybbit data is fetched per API on demand rather than regularly synchronized into Convex.
Acceptance Criteria
#1 Rybbit tracking runs only on public audit pages, not on internal dashboard routes
#2 Dashboard can fetch Rybbit API data for pageviews, custom events, and outbound link clicks for audit pages
#3 Per-audit analytics show opened yes/no, view count, last view, CTA clicks, website-link clicks, and device type where available
#4 Campaign analytics aggregate audit opens and CTA activity by campaign, niche, region, and timeframe
#5 Rybbit API failures are shown gracefully and do not break the rest of the dashboard
Implementation Plan
Add Rybbit tracking snippet or event calls only to public audit pages.
Add server-side Rybbit API client using secrets.
Build per-audit analytics panel in the dashboard.
Build campaign-level analytics summaries.
Add graceful loading, caching if useful, and error states for API failures.
Implementation Notes
Started implementation pass for Rybbit public-audit tracking and dashboard analytics surfaces.
Implemented public-audit-only Rybbit tracking, on-demand Rybbit API routes for audit/campaign activity, per-audit summary helper, dashboard Rybbit error handling, and campaign-level overall Rybbit signals. AC4 remains open for full grouping by campaign/niche/region/timeframe because Rybbit events still need a stronger audit-to-campaign join model. Verification: pnpm test 305/305; pnpm lint 0 errors.