Integration React React Router 7 Framework
PostHogOfficialCreated by PostHog
- Skill
- Tool integration
- Data and AI
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive workflow for adding PostHog analytics, session replay, feature flags, and error tracking to React Router v7 Framework applications. It emphasizes a hybrid approach, utilizing client-side initialization for user identification and event tracking, while requiring server-side middleware to maintain session correlation and capture critical business operations. The skill includes strict guidelines on React best practices, such as avoiding useEffect for event handling, and provides a clear, multi-step process for implementation.
What it does
- Guides the integration of PostHog into React Router v7 Framework mode projects.
- Provides a structured 4-step workflow for setup, editing, revision, and conclusion.
- Defines patterns for server-side and client-side event tracking.
- Establishes best practices for user identification and error tracking.
- Includes reference examples for middleware and component-level implementation.
- Enforces the use of environment variables for secure configuration.
When to use it
- When you need to add product analytics to a React Router v7 Framework application.
- When you need to implement session replay and feature flags in a React Router environment.
- When you need to track critical business events on both the client and server sides.
- When you want to ensure your analytics implementation follows established React and PostHog best practices.
Advantages
- Ensures consistent event tracking across client and server boundaries.
- Promotes clean code by discouraging misuse of useEffect.
- Provides a clear, repeatable process for integration.
- Maintains user session correlation using standard header-based tracing.
Usage examples
- “How do I initialize PostHog in my React Router v7 application?”
- The skill directs you to configure the PostHogProvider in entry.client.tsx using your project token and host from environment variables.
- “Should I track user login on the server or client?”
- The skill specifies that user identification must occur on the client-side, while server-side events should be used for critical business operations like authentication endpoints.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/posthog/integration-react-react-router-7-framework/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip integration-react-react-router-7-framework.zip -d .agents/skills
Documentation by PostHog
PostHog integration for React Router v7 - Framework mode
This skill helps you add PostHog analytics to React Router v7 - Framework mode applications.
Workflow
Follow these steps in order to complete the integration:
basic-integration-1.0-begin.md- PostHog Setup - Begin ← Start herebasic-integration-1.1-edit.md- PostHog Setup - Editbasic-integration-1.2-revise.md- PostHog Setup - Revisebasic-integration-1.3-conclude.md- PostHog Setup - Conclusion
Reference files
references/EXAMPLE.md- React Router v7 - Framework mode example project codereferences/react-router-v7-framework-mode.md- React router v7 framework mode (remix v3) - docsreferences/identify-users.md- Identify users - docsreferences/basic-integration-1.0-begin.md- PostHog setup - beginreferences/basic-integration-1.1-edit.md- PostHog setup - editreferences/basic-integration-1.2-revise.md- PostHog setup - revisereferences/basic-integration-1.3-conclude.md- PostHog setup - conclusion
The example project shows the target implementation pattern. Consult the documentation for API details.
Key principles
Environment variables: Always use environment variables for PostHog keys. Never hardcode them.
Minimal changes: Add PostHog code alongside existing integrations. Don't replace or restructure existing code.
Match the example: Your implementation should follow the example project's patterns as closely as possible.
Framework guidelines
For feature flags, use useFeatureFlagEnabled() or useFeatureFlagPayload() hooks - they handle loading states and external sync automatically
Add analytics capture in event handlers where user actions occur, NOT in useEffect reacting to state changes
Do NOT use useEffect for data transformation - calculate derived values during render instead
Do NOT use useEffect to respond to user events - put that logic in the event handler itself
Do NOT use useEffect to chain state updates - calculate all related updates together in the event handler
Do NOT use useEffect to notify parent components - call the parent callback alongside setState in the event handler
To reset component state when a prop changes, pass the prop as the component's key instead of using useEffect
useEffect is ONLY for synchronizing with external systems (non-React widgets, browser APIs, network subscriptions)
Identifying users
Identify users during login and signup events. Refer to the example code and documentation for the correct identify pattern for this framework. If both frontend and backend code exist, pass the client-side session and distinct ID using X-POSTHOG-DISTINCT-ID and X-POSTHOG-SESSION-ID headers to maintain correlation.
Error tracking
Add PostHog error tracking to relevant files, particularly around critical user flows and API boundaries.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.0 KiB
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md3.0 KiB
- references/EXAMPLE.md32.2 KiB
- references/basic-integration-1.0-begin.md2.1 KiB
- references/basic-integration-1.1-edit.md2.5 KiB
- references/basic-integration-1.2-revise.md937 B
- references/basic-integration-1.3-conclude.md1.6 KiB
- references/identify-users.md8.1 KiB
- references/react-router-v7-framework-mode.md14.9 KiB
references/react-router-v7-framework-mode.md
React Router V7 framework mode (Remix V3) - Docs
This guide walks you through setting up PostHog for React Router V7 in framework mode. If you're using React Router in another mode, find the guide for that mode in the React Router page. If you're using React with another framework, go to the React integration guide.
1
Install client-side SDKs
Required
First, you'll need to install
posthog-jsand@posthog/reactusing your package manager. These packages allow you to capture client-side events.PostHog AI
npm
npm install --save posthog-js @posthog/reactYarn
yarn add posthog-js @posthog/reactpnpm
pnpm add posthog-js @posthog/reactBun
bun add posthog-js @posthog/reactIn framework mode, you'll also need to set
posthog-jsand@posthog/reactas external packages in yourvite.config.tsfile to avoid SSR errors.vite.config.ts
PostHog AI
// ... imports export default defineConfig({ plugins: [tailwindcss(), reactRouter(), tsconfigPaths()], ssr: { noExternal: ['posthog-js', '@posthog/react'] } });2
Add your environment variables
Required
Add your environment variables to your
.env.localfile and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in your project settings. If you're using Vite, includingVITE_PUBLIC_in their names ensures they are accessible in the frontend..env.local
PostHog AI
VITE_PUBLIC_POSTHOG_TOKEN=<ph_project_token> VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com3
Add the PostHogProvider to your app
Required
In framework mode, your app enters from the
app/entry.client.tsxfile. In this file, you'll need to initialize the PostHog SDK and pass it to your app through thePostHogProvidercontext.app/entry.client.tsx
PostHog AI
import { startTransition, StrictMode } from "react"; import { hydrateRoot } from "react-dom/client"; import { HydratedRouter } from "react-router/dom"; import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); startTransition(() => { hydrateRoot( document, {/* Pass PostHog client through PostHogProvider */} <PostHogProvider client={posthog}> <StrictMode> <HydratedRouter /> </StrictMode> </PostHogProvider>, ); });To help PostHog track your user sessions across the client and server, you'll need to add the
__add_tracing_headers: ['your-backend-domain1.com', 'your-backend-domain2.com', ...]option to your PostHog initialization. This adds theX-POSTHOG-DISTINCT-IDandX-POSTHOG-SESSION-IDheaders to your requests, which we'll later use on the server-side.TypeError: Cannot read properties of undefined
If you see the error
TypeError: Cannot read properties of undefined (reading '...')this is likely because you tried to call a posthog function when posthog was not initialized (such as during the initial render). On purpose, we still render the children even if PostHog is not initialized so that your app still loads even if PostHog can't load.To fix this error, add a check that posthog has been initialized such as:
React
PostHog AI
useEffect(() => { posthog?.capture('test') // using optional chaining (recommended) if (posthog) { posthog.capture('test') // using an if statement } }, [posthog])Typescript helps protect against these errors.
Verify client-side events are captured
Checkpoint
Confirm that you can capture client-side events and see them in your PostHog project
At this point, you should be able to capture client-side events and see them in your PostHog project. This includes basic events like page views and button clicks that are autocaptured.
You can also try to capture a custom event to verify it's working. You can access PostHog in any component using the
usePostHoghook.TSX
PostHog AI
import { usePostHog } from '@posthog/react' function App() { const posthog = usePostHog() return <button onClick={() => posthog?.capture('button_clicked')}>Click me</button> }You should see these events in a minute or two in the activity tab.
4
Access PostHog methods
Required
On the client-side, you can access the PostHog client using the
usePostHoghook. This hook returns the initialized PostHog client, which you can use to call PostHog methods. For example:TSX
PostHog AI
import { usePostHog } from '@posthog/react' function App() { const posthog = usePostHog() return <button onClick={() => posthog?.capture('button_clicked')}>Click me</button> }For a complete list of available methods, see the posthog-js documentation.
5
Identify your user
Recommended
Now that you can capture basic client-side events, you'll want to identify your user so you can associate users with captured events.
Generally, you identify users when they log in or when they input some identifiable information (e.g. email, name, etc.). You can identify users by calling the
identifymethod on the PostHog client:TSX
PostHog AI
export default function Login() { const { user, login } = useAuth(); const posthog = usePostHog(); const handleLogin = async (e: React.FormEvent) => { // existing code to handle login... const user = await login({ email, password }); posthog?.identify(user.email, { email: user.email, name: user.name, } ); posthog?.capture('user_logged_in'); }; return ( <div> {/* ... existing code ... */} <button onClick={handleLogin}>Login</button> </div> ); }PostHog automatically generates anonymous IDs for users before they're identified. When you call identify, a new identified person is created. All previous events tracked with the anonymous ID link to the new identified distinct ID, and all future captures on the same browser associate with the identified person.
6
Create an error boundary
Recommended
PostHog can capture exceptions thrown in your app through an error boundary. React Router in framework mode has a built-in error boundary that you can use to capture exceptions. You can create an error boundary by exporting
ErrorBoundaryfrom yourapp/root.tsxfile.app/root.tsx
PostHog AI
import { usePostHog } from '@posthog/react' export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { const posthog = usePostHog(); posthog?.captureException(error); // other error handling code... return ( <div> <h1>Something went wrong</h1> <p>{error.message}</p> </div> ); }This automatically captures exceptions thrown in your React Router app using the
posthog.captureException()method.7
Tracking element visibility
Recommended
The
PostHogCaptureOnViewedcomponent enables you to automatically capture events when elements scroll into view in the browser. This is useful for tracking impressions of important content, monitoring user engagement with specific sections, or understanding which parts of your page users are actually seeing.The component wraps your content and sends a
$element_viewedevent to PostHog when the wrapped element becomes visible in the viewport. It only fires once per component instance.Basic usage:
React
PostHog AI
import { PostHogCaptureOnViewed } from '@posthog/react' function App() { return ( <PostHogCaptureOnViewed name="hero-banner"> <div>Your important content here</div> </PostHogCaptureOnViewed> ) }With custom properties:
You can include additional properties with the event to provide more context:
React
PostHog AI
<PostHogCaptureOnViewed name="product-card" properties={{ product_id: '123', category: 'electronics', price: 299.99 }} > <ProductCard /> </PostHogCaptureOnViewed>Tracking multiple children:
Use
trackAllChildrento track each child element separately. This is useful for galleries or lists where you want to know which specific items were viewed:React
PostHog AI
<PostHogCaptureOnViewed name="product-gallery" properties={{ gallery_type: 'featured' }} trackAllChildren > <ProductCard id="1" /> <ProductCard id="2" /> <ProductCard id="3" /> </PostHogCaptureOnViewed>When
trackAllChildrenis enabled, each child element sends its own event with achild_indexproperty indicating its position.Custom intersection observer options:
You can customize when elements are considered "viewed" by passing options to the
IntersectionObserver:React
PostHog AI
<PostHogCaptureOnViewed name="footer" observerOptions={{ threshold: 0.5, // Element is 50% visible rootMargin: '0px' }} > <Footer /> </PostHogCaptureOnViewed>The component passes all other props to the wrapper
div, so you can add styling, classes, or other HTML attributes as needed.8
Install server-side SDKs
Recommended
Install the PostHog Node SDK using your package manager. This is the SDK you'll use to capture server-side events.
PostHog AI
npm
npm install posthog-node --saveYarn
yarn add posthog-nodepnpm
pnpm add posthog-nodeBun
bun add posthog-node9
Create a server-side middleware
Recommended
Next, create a server-side middleware to help you capture server-side events. This middleware helps you achieve the following:
Initialize a PostHog client
Fetch the session and distinct ID from the
X-POSTHOG-SESSION-IDandX-POSTHOG-DISTINCT-IDheaders and pass them to your request as a context. This automatically identifies the user and session for you in all subsequent event captures.Calls
shutdown()on the PostHog client to ensure all events are sent before the request is completed.
app/lib/posthog-middleware.ts
PostHog AI
import { PostHog } from "posthog-node"; import type { RouterContextProvider } from "react-router"; import type { Route } from "../+types/root"; export interface PostHogContext extends RouterContextProvider { posthog?: PostHog; } export const posthogMiddleware: Route.MiddlewareFunction = async ({ request, context }, next) => { const posthog = new PostHog(process.env.VITE_PUBLIC_POSTHOG_TOKEN!, { host: process.env.VITE_PUBLIC_POSTHOG_HOST!, flushAt: 1, flushInterval: 0, }); const sessionId = request.headers.get('X-POSTHOG-SESSION-ID'); const distinctId = request.headers.get('X-POSTHOG-DISTINCT-ID'); (context as PostHogContext).posthog = posthog; const response = await posthog.withContext( { sessionId: sessionId ?? undefined, distinctId: distinctId ?? undefined }, next ); await posthog.shutdown().catch(() => {}); return response; };Then, you'll need to register the middleware in your app in the
app/root.tsxfile by exporting it in theRoute.MiddlewareFunction[]array.app/root.tsx
PostHog AI
import { posthogMiddleware } from './lib/posthog-middleware'; export const middleware: Route.MiddlewareFunction[] = [ posthogMiddleware, // other middlewares... ];Verify server-side events are captured
Checkpoint
Confirm that you can capture server-side events and see them in your PostHog project
At this point, you should be able to capture server-side events and see them in your PostHog project.
In a route, you can access the PostHog client from the context and capture an event. The middleware assigns the session ID and the distinct ID. This ensures that the system associates events with the correct user and session.
app/routes/api.checkout.ts
PostHog AI
import type { PostHogContext } from "../lib/posthog-middleware"; export async function action({ request, context }: Route.ActionArgs) { const body = await request.json(); // ... existing code ... // Access the PostHog client from the context and capture an event const posthog = (context as PostHogContext).posthog; posthog?.capture({ event: 'checkout_completed' }); return Response.json({ success: true, // ... existing code ... }); }10
Next steps
Recommended
Now that you've set up PostHog for React Router, you can start capturing events and exceptions in your app.
To get the most out of PostHog, you should familiarize yourself with the following:
PostHog Web SDK docs: Learn more about the PostHog Web SDK and how to use it on the client-side.
PostHog Node SDK docs: Learn more about the PostHog Node SDK and how to use it on the server-side.
Identify users: Learn more about how to identify users in your app.
Group analytics: Learn more about how to use group analytics in your app.
PostHog AI: After capturing events, use PostHog AI to help you understand your data and build insights.
Feature flags and experiments: Feature flag and experiment setup is the same as React. You can find more details in the React integration guide.
Community questions
Ask a question
Was this page useful?
HelpfulCould be better
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- PostHog
- Publisher
- PostHog (Official)
- Source
- PostHog/skills · skills/posthog/integration/skills/react-react-router-7-framework · commit a5d30e7
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- PostHog/skills
AutoGineer is not affiliated with or endorsed by PostHog or PostHog.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download integration-react-react-router-7-framework.zip