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:
@@ -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 />
|
||||||
|
|||||||
22
components/PostHogPageView.tsx
Normal file
22
components/PostHogPageView.tsx
Normal 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
|
||||||
|
}
|
||||||
@@ -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}</>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
import posthog from 'posthog-js'
|
import posthog from 'posthog-js'
|
||||||
export { posthog }
|
export { posthog }
|
||||||
|
export { usePostHog } from 'posthog-js/react'
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user