Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Jan 27, 2026

Summary

Implements blog-specific PostHog analytics events and fixes acquisition attribution issues for the blog launch.

Changes

Attribution Fix (posthog-provider.tsx)

  • Added $referrer and $referring_domain to $pageview events
  • Implemented SPA navigation tracking: previous URL is used as referrer for internal navigation
  • Preserved UTM parameters (utm_source, utm_medium, utm_campaign, utm_term, utm_content) in pageview events
  • Initial page load uses document.referrer for external attribution

Blog Analytics Events (analytics.ts)

  • blog_index_view - Fired on /blog with post_count
  • blog_post_view - Fired on /blog/[slug] with slug, title, tags, publish_date, publish_time_pt
  • blog_post_scroll_depth - Tracks 25%, 50%, 75%, 100% scroll milestones
  • blog_post_time_spent - Tracks engagement time in ms/seconds
  • blog_substack_click - Ready for use with MKT-72 Substack link

Blog Analytics Components (blog-analytics.tsx)

  • BlogIndexAnalytics - Client component for /blog index tracking
  • BlogPostAnalytics - Client component for individual post tracking with scroll depth and time spent

Testing

Verification plan per issue requirements:

  1. In PostHog "Live events", confirm events show expected properties for:
    • UTM landing (use ?utm_source=test&utm_medium=test&utm_campaign=test)
    • Referrer landing (navigate from another domain)
  2. Confirm sessions are not categorized as Direct when UTM/referrer is present
  3. Verify blog events fire with correct properties

Related Issues

  • MKT-74: Blog PostHog analytics events + fix acquisition attribution
  • Depends on MKT-72 for blog_substack_click integration with footer link

Important

Adds blog-specific PostHog analytics events and fixes acquisition attribution issues for the blog launch.

  • Attribution Fix (posthog-provider.tsx):
    • Added $referrer and $referring_domain to $pageview events.
    • Implemented SPA navigation tracking using previous URL as referrer.
    • Preserved UTM parameters in pageview events.
    • Initial page load uses document.referrer for external attribution.
  • Blog Analytics Events (analytics.ts):
    • blog_index_view - Fired on /blog with post_count.
    • blog_post_view - Fired on /blog/[slug] with slug, title, tags, publish_date, publish_time_pt.
    • blog_post_scroll_depth - Tracks 25%, 50%, 75%, 100% scroll milestones.
    • blog_post_time_spent - Tracks engagement time in ms/seconds.
    • blog_substack_click - Ready for use with MKT-72 Substack link.
  • Blog Analytics Components (blog-analytics.tsx):
    • BlogIndexAnalytics - Client component for /blog index tracking.
    • BlogPostAnalytics - Client component for individual post tracking with scroll depth and time spent.

This description was created by Ellipsis for 26a47e1. You can customize this summary. It will automatically update as commits are pushed.

- Add gray-matter for frontmatter parsing
- Create BlogPost type and zod schema for validation
- Implement PT timezone helpers (getNowPt, parsePublishTimePt)
- Implement content loading (getAllBlogPosts, getBlogPostBySlug)
- Implement isPublished for request-time publish gating
- Add validation for frontmatter and duplicate slugs
- Create content/blog directory for markdown files

Closes: MKT-67
…he Past

Adds the first canonical blog post to validate the content pipeline:
- Title: PRDs Are Becoming Artifacts of the Past
- Slug: prds-are-becoming-artifacts-of-the-past
- Status: published
- Publish date: 2026-01-12 at 9:00am PT

Content sourced from Office Hours S01E15 with Paige Bailey.

Closes: MKT-73
- Create blog index page at /blog
- Use force-dynamic for request-time publish gating
- Require Node.js runtime for filesystem reads
- Display posts with title, description, and date
- Add empty state when no posts are published
- Include tags display (up to 3)

Closes: MKT-68
- Create dynamic route for individual blog posts
- Use force-dynamic for request-time publish gating
- Require Node.js runtime for filesystem reads
- Return 404 for drafts, future posts, or invalid slugs
- Render Markdown with react-markdown + remark-gfm
- No raw HTML rendering (safe by default)
- Include consistent typography and styling

Closes: MKT-69
- Add structured-data.ts with Article, CollectionPage, and BreadcrumbList schemas
- Integrate JSON-LD into /blog index page (Blog collection + breadcrumbs)
- Integrate JSON-LD into /blog/[slug] page (Article + post breadcrumbs)
- Export structured data utilities from blog module index

MKT-70
- Add analytics.ts with blog-specific tracking events:
  - trackBlogIndexView: Track blog index views with post count
  - trackBlogPostView: Track individual post views with metadata
  - trackBlogPostScrollDepth: Track reading progress (25%, 50%, 75%, 100%)
  - trackBlogPostTimeSpent: Track time spent on posts
  - trackBlogPostShare: Track social share clicks
  - trackBlogPostCTAClick: Track CTA engagement

- Add BlogIndexAnalytics and BlogPostAnalytics client components
- Integrate analytics into /blog and /blog/[slug] pages

Attribution is handled by PostHog save_referrer and save_campaign_params.

MKT-74
@roomote roomote bot requested review from cte, jr and mrubens as code owners January 27, 2026 19:53
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. Enhancement New feature or request labels Jan 27, 2026
@roomote roomote bot changed the title feat(blog): add PostHog analytics events for blog pages MKT-74: Add blog PostHog analytics events and fix acquisition attribution Jan 27, 2026
- Fix $pageview to include $referrer, $referring_domain, and UTM params
- Track previous URL for SPA navigation referrer attribution
- Rename events to blog_index_view and blog_post_view (per spec)
- Add publish_time_pt property to blog_post_view
- Add trackBlogSubstackClick function for use with MKT-72
@roomote
Copy link
Contributor Author

roomote bot commented Jan 27, 2026

Rooviewer Clock   See task on Roo Cloud

All previously flagged issues have been resolved. The latest commit fixes the client-side import issue by using direct imports from @/lib/blog/types and @/lib/blog/analytics instead of the barrel export. LGTM!

  • Missing publish_time_pt in BlogPostAnalyticsProps interface and the post object passed to BlogPostAnalytics - causes blog_post_view events to have undefined for this property
  • Potential duplicate blog_post_time_spent events when both visibilitychange handler and component cleanup fire
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

@roomote
Copy link
Contributor Author

roomote bot commented Jan 27, 2026

Rooviewer Clock   See task on Roo Cloud

Reviewed the blog analytics implementation. Found 1 issue related to missing data in analytics events.

  • publish_time_pt is missing from BlogPostAnalytics props and the component invocation, causing blog_post_view events to send undefined for this field

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Comment on lines 91 to 93
// Track time spent when component unmounts
const timeSpent = Date.now() - effectStartTime
trackBlogPostTimeSpent(post as BlogPost, timeSpent)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When a user navigates away from a blog post, both the visibilitychange handler (line 75-78) and this cleanup function can fire trackBlogPostTimeSpent, resulting in duplicate events. Consider adding a flag to track whether time-spent has already been recorded, or remove the tracking from one of these locations.

Fix it with Roo Code or mention @roomote and request a fix.

@mp-roocode mp-roocode self-assigned this Jan 27, 2026
mp-roocode and others added 4 commits January 27, 2026 16:39
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
@roomote
Copy link
Contributor Author

roomote bot commented Jan 28, 2026

Fixaroo Clock   See task on Roo Cloud

Fixed the reported issues. All local checks passed.

View commit | Revert commit

- Add trackedTimeSpent ref to track if time-spent event already fired
- Check flag in visibilitychange handler and cleanup function
- Remove duplicate interface declaration in BlogPostAnalyticsProps
- Remove duplicate BlogPostAnalytics component opening tag
@mp-roocode
Copy link
Collaborator

@roomote
Copy link
Contributor Author

roomote bot commented Jan 28, 2026

Fixaroo Clock   See task on Roo Cloud

Fixed the build failure by updating blog-analytics.tsx to import directly from specific modules (@/lib/blog/types and @/lib/blog/analytics) instead of the barrel file, avoiding the Node.js fs module dependency. All local checks passed.

View commit | Revert commit

@github-actions
Copy link
Contributor

🚀 Preview deployed!

Your changes have been deployed to Vercel:

Preview URL: https://roo-code-website-hsz8g5vgy-roo-code.vercel.app

This preview will be updated automatically when you push new commits to this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

2 participants