Skip to content
This repository was archived by the owner on Jan 27, 2026. It is now read-only.

Commit cd00377

Browse files
authored
Merge pull request #9 from PostHog/framework-tanstack-start
tanstack start
2 parents 26a7339 + 18c3f52 commit cd00377

31 files changed

+8904
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ lerna-debug.log*
4747
# Testing
4848
coverage/
4949

50+
# TanStack Router generated files
51+
routeTree.gen.ts
52+
5053
# Build artifacts
5154
dist/
5255

basics/tanstack-start/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
count.txt
7+
.env
8+
.nitro
9+
.tanstack
10+
.wrangler
11+
.output
12+
.vinxi
13+
todos.json
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package-lock.json
2+
pnpm-lock.yaml
3+
yarn.lock
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"files.watcherExclude": {
3+
"**/routeTree.gen.ts": true
4+
},
5+
"search.exclude": {
6+
"**/routeTree.gen.ts": true
7+
},
8+
"files.readonlyInclude": {
9+
"**/routeTree.gen.ts": true
10+
}
11+
}

basics/tanstack-start/README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# PostHog TanStack Start example
2+
3+
This is a [TanStack Start](https://tanstack.com/start) example demonstrating PostHog integration with product analytics, session replay, feature flags, and error tracking.
4+
5+
## Features
6+
7+
- **Product analytics**: Track user events and behaviors
8+
- **Session replay**: Record and replay user sessions
9+
- **Error tracking**: Capture and track errors automatically
10+
- **User authentication**: Demo login system with PostHog user identification
11+
- **Server-side & client-side tracking**: Complete examples of both tracking methods
12+
- **Reverse proxy**: PostHog ingestion through Vite dev server proxy
13+
14+
## Getting started
15+
16+
### 1. Install dependencies
17+
18+
```bash
19+
npm install
20+
```
21+
22+
### 2. Configure environment variables
23+
24+
Create a `.env` file in the root directory:
25+
26+
```bash
27+
VITE_POSTHOG_KEY=your_posthog_project_api_key
28+
VITE_POSTHOG_HOST=https://us.i.posthog.com
29+
```
30+
31+
Get your PostHog API key from your [PostHog project settings](https://app.posthog.com/project/settings).
32+
33+
### 3. Run the development server
34+
35+
```bash
36+
npm run dev
37+
```
38+
39+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the app.
40+
41+
## Project structure
42+
43+
```
44+
src/
45+
├── components/
46+
│ └── Header.tsx # Navigation header with auth state
47+
├── contexts/
48+
│ └── AuthContext.tsx # Authentication context with PostHog integration
49+
├── lib/
50+
│ ├── posthog-client.ts # Client-side PostHog initialization
51+
│ └── posthog-server.ts # Server-side PostHog client
52+
├── routes/
53+
│ ├── __root.tsx # Root route with AuthProvider
54+
│ ├── index.tsx # Home/login page
55+
│ ├── burrito.tsx # Demo feature page with event tracking
56+
│ ├── profile.tsx # User profile with error tracking demo
57+
│ ├── api/
58+
│ │ └── auth/
59+
│ │ └── login.ts # Login API with server-side tracking
60+
│ └── _demo/ # TanStack Start demo examples
61+
└── styles.css # Global styles
62+
63+
vite.config.ts # Vite config with PostHog proxy
64+
.env # Environment variables
65+
```
66+
67+
## Key integration points
68+
69+
### Client-side initialization
70+
71+
PostHog is initialized on the client side in `lib/posthog-client.ts`:
72+
73+
```typescript
74+
import posthog from 'posthog-js'
75+
76+
export function initPostHog() {
77+
if (typeof window !== 'undefined') {
78+
posthog.init(import.meta.env.VITE_POSTHOG_KEY!, {
79+
api_host: '/ingest',
80+
ui_host: import.meta.env.VITE_POSTHOG_HOST || 'https://us.posthog.com',
81+
defaults: '2025-05-24',
82+
capture_exceptions: true,
83+
debug: import.meta.env.DEV,
84+
loaded: (posthog) => {
85+
if (import.meta.env.DEV) posthog.debug()
86+
},
87+
})
88+
}
89+
}
90+
```
91+
92+
The initialization happens in the root route's `useEffect` hook to ensure it runs only in the browser.
93+
94+
### Server-side setup
95+
96+
For server-side tracking, we use the `posthog-node` SDK with a singleton pattern:
97+
98+
```typescript
99+
import { PostHog } from 'posthog-node'
100+
101+
export function getPostHogClient() {
102+
if (!posthogClient) {
103+
posthogClient = new PostHog(
104+
process.env.VITE_POSTHOG_KEY || import.meta.env.VITE_POSTHOG_KEY!,
105+
{
106+
host: process.env.VITE_POSTHOG_HOST || import.meta.env.VITE_POSTHOG_HOST,
107+
flushAt: 1, // Send immediately
108+
flushInterval: 0 // No batching delay
109+
}
110+
)
111+
}
112+
return posthogClient
113+
}
114+
```
115+
116+
This client is used in API routes to track server-side events.
117+
118+
### Reverse proxy configuration
119+
120+
The Vite dev server is configured to proxy PostHog requests to avoid CORS issues and improve reliability:
121+
122+
```typescript
123+
server: {
124+
proxy: {
125+
'/ingest': {
126+
target: 'https://us.i.posthog.com',
127+
changeOrigin: true,
128+
rewrite: (path) => path.replace(/^\/ingest/, ''),
129+
secure: false,
130+
},
131+
},
132+
}
133+
```
134+
135+
This setup:
136+
- Avoids CORS issues
137+
- Bypasses ad blockers that might block PostHog
138+
- Improves data collection reliability
139+
- Keeps all requests on the same domain
140+
141+
### Authentication flow
142+
143+
1. User enters credentials on home page (`/`)
144+
2. Form submits to `/api/auth/login` API route
145+
3. Server captures `server_login` event with PostHog
146+
4. Client identifies user and captures `user_logged_in` event
147+
5. User is redirected to authenticated pages
148+
149+
### User identification
150+
151+
```typescript
152+
// User identification on login
153+
posthog.identify(username, {
154+
username: username,
155+
})
156+
```
157+
158+
### Event tracking
159+
160+
```typescript
161+
// Custom event tracking
162+
posthog.capture('burrito_considered', {
163+
total_considerations: user.burritoConsiderations + 1,
164+
username: user.username,
165+
})
166+
```
167+
168+
### Error tracking
169+
```typescript
170+
// Error tracking
171+
posthog.captureException(error)
172+
```
173+
174+
## Learn more
175+
176+
- [PostHog documentation](https://posthog.com/docs)
177+
- [TanStack Start documentation](https://tanstack.com/start)
178+
- [TanStack Router documentation](https://tanstack.com/router)
179+
- [PostHog React integration](https://posthog.com/docs/libraries/react)
180+
- [PostHog Node.js integration](https://posthog.com/docs/libraries/node)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @ts-check
2+
3+
import { tanstackConfig } from '@tanstack/eslint-config'
4+
5+
export default [...tanstackConfig]

0 commit comments

Comments
 (0)