diff --git a/.changeset/wicked-paws-live.md b/.changeset/wicked-paws-live.md new file mode 100644 index 00000000..50f2ba07 --- /dev/null +++ b/.changeset/wicked-paws-live.md @@ -0,0 +1,5 @@ +--- +'@tanstack/create': minor +--- + +Add PostHog add-on diff --git a/packages/create/src/frameworks/react/add-ons/posthog/README.md b/packages/create/src/frameworks/react/add-ons/posthog/README.md new file mode 100644 index 00000000..735e9803 --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/README.md @@ -0,0 +1,9 @@ +## Setting up PostHog + +1. Create a PostHog account at [posthog.com](https://posthog.com) +2. Get your Project API Key from [Project Settings](https://app.posthog.com/project/settings) +3. Set `VITE_POSTHOG_KEY` in your `.env.local` + +### Optional Configuration + +- `VITE_POSTHOG_HOST` - Set this if you're using PostHog Cloud EU (`https://eu.i.posthog.com`) or self-hosting diff --git a/packages/create/src/frameworks/react/add-ons/posthog/assets/_dot_env.local.append b/packages/create/src/frameworks/react/add-ons/posthog/assets/_dot_env.local.append new file mode 100644 index 00000000..20b49c5f --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/assets/_dot_env.local.append @@ -0,0 +1,4 @@ +# PostHog configuration, get your key from https://app.posthog.com/project/settings +VITE_POSTHOG_KEY=phc_xxx +# Optional: PostHog API host (for self-hosted or EU cloud) +# VITE_POSTHOG_HOST=https://us.i.posthog.com diff --git a/packages/create/src/frameworks/react/add-ons/posthog/assets/src/integrations/posthog/provider.tsx b/packages/create/src/frameworks/react/add-ons/posthog/assets/src/integrations/posthog/provider.tsx new file mode 100644 index 00000000..47de048e --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/assets/src/integrations/posthog/provider.tsx @@ -0,0 +1,20 @@ +import posthog from 'posthog-js' +import { PostHogProvider as BasePostHogProvider } from '@posthog/react' +import type { ReactNode } from 'react' + +if (typeof window !== 'undefined' && import.meta.env.VITE_POSTHOG_KEY) { + posthog.init(import.meta.env.VITE_POSTHOG_KEY, { + api_host: import.meta.env.VITE_POSTHOG_HOST || 'https://us.i.posthog.com', + person_profiles: 'identified_only', + capture_pageview: false, + defaults: '2025-11-30', + }) +} + +interface PostHogProviderProps { + children: ReactNode +} + +export default function PostHogProvider({ children }: PostHogProviderProps) { + return {children} +} diff --git a/packages/create/src/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx b/packages/create/src/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx new file mode 100644 index 00000000..0a43d2e6 --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx @@ -0,0 +1,93 @@ +import { createFileRoute, Link } from '@tanstack/react-router' +import { usePostHog } from '@posthog/react' +import { useState } from 'react' + +export const Route = createFileRoute('/demo/posthog')({ + component: PostHogDemo, +}) + +function PostHogDemo() { + const posthog = usePostHog() + const [eventCount, setEventCount] = useState(0) + const posthogKey = import.meta.env.VITE_POSTHOG_KEY + const isConfigured = Boolean(posthogKey) && posthogKey !== 'phc_xxx' + + const trackEvent = ( + eventName: string, + properties?: Record, + ) => { + posthog.capture(eventName, properties) + setEventCount((c) => c + 1) + } + + return ( +
+
+

PostHog Demo

+ + {!isConfigured && ( +
+

+ Warning: VITE_POSTHOG_KEY is not configured. + Events won't be sent to PostHog. Add it to your{' '} + .env file. +

+
+ )} + +
+

+ Click the button below to send events to PostHog. Check your PostHog + dashboard to see them appear in real-time. +

+ + + + {isConfigured && ( +
+

Events sent this session:

+

{eventCount}

+
+ )} +
+ +

+ Open your{' '} + + PostHog Events + {' '} + page to see these events appear. +

+ +

+ Learn more in the{' '} + + PostHog React docs + + . +

+ +
+ + ← Back to Home + +
+
+
+ ) +} diff --git a/packages/create/src/frameworks/react/add-ons/posthog/files.json b/packages/create/src/frameworks/react/add-ons/posthog/files.json new file mode 100644 index 00000000..c7bc925b --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/files.json @@ -0,0 +1,5 @@ +[ + "src/integrations/posthog/provider.tsx", + "src/routes/demo/posthog.tsx", + "_dot_env.local.append" +] diff --git a/packages/create/src/frameworks/react/add-ons/posthog/info.json b/packages/create/src/frameworks/react/add-ons/posthog/info.json new file mode 100644 index 00000000..fad5e154 --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/info.json @@ -0,0 +1,28 @@ +{ + "name": "PostHog", + "description": "Product analytics, session replay, and feature flags", + "phase": "add-on", + "modes": ["file-router"], + "type": "add-on", + "category": "analytics", + "color": "#1D4AFF", + "priority": 20, + "link": "https://posthog.com", + "tailwind": true, + "routes": [ + { + "icon": "BarChart", + "url": "/demo/posthog", + "name": "PostHog", + "path": "src/routes/demo/posthog.tsx", + "jsName": "PostHogDemo" + } + ], + "integrations": [ + { + "type": "provider", + "jsName": "PostHogProvider", + "path": "src/integrations/posthog/provider.tsx" + } + ] +} diff --git a/packages/create/src/frameworks/react/add-ons/posthog/package.json b/packages/create/src/frameworks/react/add-ons/posthog/package.json new file mode 100644 index 00000000..ecd9ce89 --- /dev/null +++ b/packages/create/src/frameworks/react/add-ons/posthog/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "posthog-js": "^1.335.4", + "@posthog/react": "^1.7.0" + } +} diff --git a/packages/create/src/types.ts b/packages/create/src/types.ts index 56380cb4..aaeb8d1f 100644 --- a/packages/create/src/types.ts +++ b/packages/create/src/types.ts @@ -50,6 +50,7 @@ export const AddOnBaseSchema = z.object({ 'monitoring', 'cms', 'api', + 'analytics', 'i18n', 'tooling', 'other',