4.6 KiB
TanStack Start - Docs
This tutorial shows how to integrate PostHog with a TanStack Start app for both client-side and server-side analytics.
Installation
Install the required packages:
Terminal
PostHog AI
npm install @posthog/react posthog-node
@posthog/react- React package for our JS Web SDK for client-side usageposthog-node- PostHog Node.js SDK for server-side event capture
Initialize PostHog on the client
Wrap your app with PostHogProvider in your root route with your project token, host, and other options.
src/routes/__root.tsx
PostHog AI
// src/routes/__root.tsx
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
import { PostHogProvider } from '@posthog/react'
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
}),
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<PostHogProvider
apiKey="<ph_project_token>"
options={{
api_host: 'https://us.i.posthog.com',
defaults: '2026-01-30',
capture_exceptions: true
}}
>
{children}
</PostHogProvider>
<Scripts />
</body>
</html>
)
}
Once the provider is in place, PostHog automatically captures pageviews, sessions, and web vitals.
Capture events on the client
Use the usePostHog hook from @posthog/react in any component to capture custom events:
src/routes/checkout.tsx
PostHog AI
import { usePostHog } from '@posthog/react'
function CheckoutButton({ orderId, total }: { orderId: string; total: number }) {
const posthog = usePostHog()
const handleClick = () => {
posthog.capture('checkout_started', {
order_id: orderId,
total: total,
})
}
return <button onClick={handleClick}>Checkout</button>
}
Identify users
Call posthog.identify() when a user logs in to link their events to a user ID:
TSX
PostHog AI
import { usePostHog } from '@posthog/react'
function LoginForm() {
const posthog = usePostHog()
const handleLogin = async (userId: string, email: string) => {
// ... your login logic
posthog.identify(userId, {
email: email,
})
posthog.capture('user_logged_in')
}
}
Call posthog.reset() on logout to clear the identified user.
Initialize PostHog on the server
Create a server-side PostHog client using posthog-node. Use a singleton pattern so you reuse the same client across requests:
src/utils/posthog-server.ts
PostHog AI
// src/utils/posthog-server.ts
import { PostHog } from 'posthog-node'
let posthogClient: PostHog | null = null
export function getPostHogClient() {
if (!posthogClient) {
posthogClient = new PostHog(
'<ph_project_token>',
{
host: 'https://us.i.posthog.com',
flushAt: 1,
flushInterval: 0,
},
)
}
return posthogClient
}
Capture events on the server
Use the server client in TanStack Start API routes to capture events server-side. Server-side capture is useful for tracking events that shouldn't be spoofable from the client, like purchases or authentication:
src/routes/api/checkout.ts
PostHog AI
// src/routes/api/checkout.ts
import { createFileRoute } from '@tanstack/react-router'
import { json } from '@tanstack/react-start'
import { getPostHogClient } from '../../utils/posthog-server'
export const Route = createFileRoute('/api/checkout')({
server: {
handlers: {
POST: async ({ request }) => {
const body = await request.json()
const posthog = getPostHogClient()
posthog.capture({
distinctId: body.userId,
event: 'item_purchased',
properties: {
item_id: body.itemId,
price: body.price,
source: 'api',
},
})
return json({ success: true })
},
},
},
})
The server-side capture call requires a distinctId (the user identifier), an event name, and optional properties.
Next steps
Installing the JS Web SDK and Node SDK means all of their functionality is available in your TanStack Start project. To learn more about this, have a look at our JS Web SDK docs and Node SDK docs.
Community questions
Ask a question
Was this page useful?
HelpfulCould be better