Adding Analytics to My AI Product Description Generator with PostHog

December 5, 2025
webdev
analytics
nextjs
beginners

As I continue building my AI Product Description Generator, I realized I needed to understand how people would actually use the tool. After researching different options, I decided to add PostHog analytics to track user behavior and make data-driven improvements.

Why PostHog?

When choosing an analytics solution, several factors made PostHog stand out:

  1. Open Source: The entire platform is open source, which aligns with my development values
  2. Developer-First: Built specifically with developers in mind
  3. Next.js Integration: Clean documentation and easy setup with my tech stack
  4. Session Recordings: The ability to see how users interact with the UI
  5. Self-hostable: Option to self-host in the future if needed

Setting Up PostHog in Next.js

The setup process was straightforward. Here's how I added PostHog to my project:

  1. First, install the PostHog package:
npm install --save posthog-js
# or
yarn add posthog-js
# or
pnpm add posthog-js
  1. Add your environment variables to .env.local:
NEXT_PUBLIC_POSTHOG_KEY=your-project-key
NEXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com

These variables need to start with NEXT_PUBLIC_ to be accessible on the client side.

  1. For my Next.js app using the App Router, I created two key files:

First, a providers file for PostHog initialization:

// app/providers.tsx
'use client'
import posthog from 'posthog-js'
import { PostHogProvider } from 'posthog-js/react'
import { useEffect } from 'react'
const PostHogPageView = dynamic(() => import('./PostHogPageView'), {
  ssr: false,
})

export function PHProvider({
  children,
}: {
  children: React.ReactNode
}) {
  useEffect(() => {
      posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
        api_host: "/ingest",
        ui_host: "https://eu.posthog.com",
        person_profiles: 'identified_only',
        capture_pageview: false,
        capture_pageleave: true
      })
  }, []);

  return (
    <PostHogProvider client={posthog}>
      <PostHogPageView/>
      {children}
    </PostHogProvider>
  )
}

Note: We use dynamic import for PostHogPageView because it contains the useSearchParams hook, which would otherwise force the entire app into client-side rendering.

Then, a component to handle page view tracking (since Next.js is a single-page app):

// app/PostHogPageView.tsx
'use client'

import { usePathname, useSearchParams } from "next/navigation"
import { useEffect } from "react"
import { usePostHog } from 'posthog-js/react'

export default function PostHogPageView(): null {
  const pathname = usePathname()
  const searchParams = useSearchParams()
  const posthog = usePostHog()

  useEffect(() => {
    if (pathname && posthog) {
      let url = window.origin + pathname
      if (searchParams.toString()) {
        url = url + `?${searchParams.toString()}`
      }
      posthog.capture(
        '$pageview',
        {
          '$current_url': url,
        }
      )
    }
  }, [pathname, searchParams, posthog])
  
  return null
}

Finally, I integrated these components in my root layout:

// app/layout.tsx
import './globals.css'
import { PHProvider } from './providers'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <PHProvider>
        <body>
          <PostHogPageView />
          {children}
        </body>
      </PHProvider>
    </html>
  )
}

Setting Up a Reverse Proxy

To improve privacy and avoid ad-blockers, I also set up a reverse proxy using Next.js rewrites. Here's how:

  1. First, I added the proxy configuration to next.config.js:
// next.config.js
const nextConfig = {
  async rewrites() {
    return [
      {
        source: "/ingest/static/:path*",
        destination: "https://us-assets.i.posthog.com/static/:path*",
      },
      {
        source: "/ingest/:path*",
        destination: "https://us.i.posthog.com/:path*",
      },
      {
        source: "/ingest/decide",
        destination: "https://us.i.posthog.com/decide",
      },
    ];
  },
  // Required to support PostHog trailing slash API requests
  skipTrailingSlashRedirect: true,
}

module.exports = nextConfig
  1. Then, I updated the PostHog initialization to use the proxy:
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: "/ingest",
  ui_host: 'https://eu.posthog.com'  // Adjust if you're using EU cloud
  // ... other options
})

Note: If you're using PostHog's EU cloud (like I am), replace us with eu in all domains in the next.config.js file.

What I'm Planning to Track

I'm starting with basic events to understand user behavior:

  1. Core User Actions:
// Track when users attempt to generate descriptions
function handleGenerate() {
  posthog.capture('generate_description', {
    productType: product.type,
    inputLength: product.input.length
  })
}

// Track successful generations
function onGenerationSuccess(result) {
  posthog.capture('generation_success', {
    responseLength: result.length,
    timeToGenerate: performance.now() - startTime
  })
}

// Track errors
function onGenerationError(error) {
  posthog.capture('generation_error', {
    errorType: error.type,
    errorMessage: error.message
  })
}
  1. User Flow Events:
// Track form interactions
function trackFormInteraction(fieldName: string, action: string) {
  posthog.capture('form_interaction', {
    field: fieldName,
    action: action // focus, blur, change, etc.
  })
}

Questions I Want to Answer

By implementing analytics, I'm hoping to understand:

  1. User Behavior
  • How many descriptions do users typically generate?
  • What types of products are they describing?
  • Where do users get stuck in the process?
  1. Performance Metrics
  • How long do generations typically take?
  • Are there common error patterns?
  • What's the success rate of generations?
  1. Usage Patterns
  • What times are most active?
  • Which features are used most?
  • Do users return for multiple sessions?

Next Steps

Now that the basic setup is complete, my next steps are:

  1. Create Funnels
  • Track the complete user journey
  • Identify drop-off points
  • Measure conversion rates
  1. Set Up A/B Testing
  • Test different UI layouts
  • Experiment with form fields
  • Try various generation prompts
  1. Monitor Performance
  • Track load times
  • Measure API response times
  • Identify bottlenecks

Learning in Public

This is just the beginning of my analytics journey. I'll be sharing what I learn as I gather real user data and make improvements based on these insights.

Some questions I'm curious about:

  • What metrics do you track in your projects?
  • How do you balance privacy with data collection?
  • What analytics insights have surprised you the most?

I'd love to hear about your experiences with analytics and any suggestions for what I should be tracking. Drop your thoughts in the comments!


Keep following my journey:

Let's learn and build together! 🚀