Rework PostHog setup — use Next.js ingest proxy + posthog-js/react

Mirrors the proven pattern from gendersloty: rewrites /ingest/* to
the PostHog host so requests go through the same origin (no CORS,
no ad-blocker issues). Uses PostHogProvider and usePostHog from
posthog-js/react official React integration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tim Leikauf
2026-07-01 21:50:43 +02:00
parent eb228ba50b
commit 4274d680e1
5 changed files with 53 additions and 13 deletions

View File

@@ -4,6 +4,8 @@ import './globals.css'
import Nav from '@/components/ui/Nav' import Nav from '@/components/ui/Nav'
import Footer from '@/components/ui/Footer' import Footer from '@/components/ui/Footer'
import PostHogProvider from '@/components/PostHogProvider' import PostHogProvider from '@/components/PostHogProvider'
import { PostHogPageView } from '@/components/PostHogPageView'
import { Suspense } from 'react'
const cormorant = Cormorant_Garamond({ const cormorant = Cormorant_Garamond({
subsets: ['latin'], subsets: ['latin'],
@@ -47,6 +49,9 @@ export default function RootLayout({
}} }}
/> />
<PostHogProvider> <PostHogProvider>
<Suspense fallback={null}>
<PostHogPageView />
</Suspense>
<Nav /> <Nav />
<main>{children}</main> <main>{children}</main>
<Footer /> <Footer />

View File

@@ -0,0 +1,22 @@
'use client'
import { usePathname, useSearchParams } from 'next/navigation'
import { usePostHog } from 'posthog-js/react'
import { useEffect } from 'react'
export function PostHogPageView() {
const pathname = usePathname()
const searchParams = useSearchParams()
const posthog = usePostHog()
useEffect(() => {
if (pathname && posthog) {
let url = window.origin + pathname
const search = searchParams.toString()
if (search) url += `?${search}`
posthog.capture('$pageview', { $current_url: url })
}
}, [pathname, searchParams, posthog])
return null
}

View File

@@ -1,24 +1,18 @@
'use client' 'use client'
import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
import posthog from 'posthog-js' import posthog from 'posthog-js'
import { PostHogProvider as PHProvider } from 'posthog-js/react'
import { useEffect } from 'react'
export default function PostHogProvider({ children }: { children: React.ReactNode }) { export default function PostHogProvider({ children }: { children: React.ReactNode }) {
useEffect(() => { useEffect(() => {
posthog.init('phc_BHgg9S7CQqVShe7EMCdi86PxA49qcNaTsR9Nn5EGxRCT', { posthog.init('phc_BHgg9S7CQqVShe7EMCdi86PxA49qcNaTsR9Nn5EGxRCT', {
api_host: 'https://eu.posthog.com', api_host: '/ingest',
ui_host: 'https://analytics.hyggecraftery.com',
capture_pageview: false, capture_pageview: false,
persistence: 'memory', persistence: 'memory',
}) })
}, []) }, [])
const pathname = usePathname() return <PHProvider client={posthog}>{children}</PHProvider>
useEffect(() => {
// PostHog queues events automatically before init completes
posthog.capture('$pageview', { $current_url: window.location.href })
}, [pathname])
return <>{children}</>
} }

View File

@@ -1,2 +1,3 @@
import posthog from 'posthog-js' import posthog from 'posthog-js'
export { posthog } export { posthog }
export { usePostHog } from 'posthog-js/react'

View File

@@ -1,4 +1,22 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = {}; const nextConfig = {
async rewrites() {
return [
{
source: '/ingest/static/:path*',
destination: 'https://analytics.hyggecraftery.com/static/:path*',
},
{
source: '/ingest/:path*',
destination: 'https://analytics.hyggecraftery.com/:path*',
},
{
source: '/ingest/decide',
destination: 'https://analytics.hyggecraftery.com/decide',
},
]
},
skipTrailingSlashRedirect: true,
}
export default nextConfig; export default nextConfig