diff --git a/contents/docs/integrate/_snippets/install-react.mdx b/contents/docs/integrate/_snippets/install-react.mdx
index 3a7cfd6762eb..f4b003f98ffe 100644
--- a/contents/docs/integrate/_snippets/install-react.mdx
+++ b/contents/docs/integrate/_snippets/install-react.mdx
@@ -1,4 +1,4 @@
-> For Next.js, we recommend following the [Next.js integration guide](/docs/integrate/next-js) instead.
+> For React-based frameworks, we recommend the [Next.js integration guide](/docs/libraries/next-js) and [Next.js integration guide](/docs/libraries/remix) instead.
1. Install [`posthog-js`](https://github.com/posthog/posthog-js) and `@posthog/react` using your package manager:
@@ -6,14 +6,14 @@ import InstallReactPackageManagers from "./install-react-package-managers.mdx"
-2. Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project API key and host in [your project settings](https://us.posthog.com/settings/project). Including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend.
+2. Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project API key and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, include `VITE_PUBLIC_` in their names ensures they are accessible in the frontend.
```shell file=.env.local
VITE_PUBLIC_POSTHOG_KEY=
VITE_PUBLIC_POSTHOG_HOST=
```
-3. Integrate PostHog at the root of your app (such as `main.jsx` if you are using Vite).
+3. Integrate PostHog at the root of your app (such as `main.jsx` for Vite apps and `root.tsx` for React Router V7).
```react
// src/main.jsx
@@ -21,19 +21,19 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
-import posthog from 'posthog-js';
-import { PostHogProvider } from '@posthog/react'
+import posthog from 'posthog-js'; // +
+import { PostHogProvider } from '@posthog/react' // +
-posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {
- api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
- defaults: '',
-});
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, { // +
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, // +
+ defaults: '', // +
+}); // +
createRoot(document.getElementById('root')).render(
-
+ // +
-
+ // +
,
)
```
@@ -45,22 +45,3 @@ import CalloutBox from 'components/Docs/CalloutBox'
Do not directly import `posthog` apart from installation as shown above. This will likely cause errors as the library might not be initialized yet. Initialization is handled automatically when you use the `PostHogProvider` and `usePostHog` hook.
-
-
- Using React Router v7?
-
- You need to set `posthog-js` and `@posthog/react` as external packages in your `vite.config.ts` file to avoid SSR errors.
-
- ```ts file=vite.config.ts
- // ... imports
-
- export default defineConfig({
- plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
- ssr: {
- noExternal: ['posthog-js', '@posthog/react']
- }
- });
- ```
-
- See our [Remix docs](/docs/libraries/remix) for more details.
-
\ No newline at end of file
diff --git a/contents/docs/libraries/react-router/_snippets/react-router-decision-tree.tsx b/contents/docs/libraries/react-router/_snippets/react-router-decision-tree.tsx
new file mode 100644
index 000000000000..9dd94d3f5a6c
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/react-router-decision-tree.tsx
@@ -0,0 +1,72 @@
+import React from 'react'
+import { DecisionTree } from 'components/Docs/DecisionTree'
+import type { DecisionTreeQuestion, DecisionTreeRecommendation } from 'components/Docs/DecisionTree'
+
+const questions: DecisionTreeQuestion[] = [
+ {
+ id: 'version',
+ question: 'Pick the right guide for you',
+ description: 'Check your package.json file for the react-router version.',
+ options: [
+ { value: 'v7', label: '7.x.x (React Router V7)' },
+ { value: 'v6', label: '6.x.x (React Router V6)' },
+ ],
+ },
+ {
+ id: 'v7-mode',
+ question: 'Which React Router V7 mode are you using?',
+ description: 'How are your routes configured and defined?',
+ condition: (answers) => answers.version === 'v7',
+ options: [
+ { value: 'framework', label: 'Using react-router.config.ts' },
+ { value: 'data', label: 'Using ' },
+ { value: 'declarative', label: 'Using ' },
+ ],
+ },
+]
+
+const getRecommendation = (answers: Record): DecisionTreeRecommendation => {
+ if (answers.version === 'v6') {
+ return {
+ title: 'React Router V6',
+ path: '/docs/libraries/react-router/react-router-v6',
+ reason: 'You are using React Router V6. Follow the React Router V6 guide for setup instructions.',
+ }
+ }
+
+ if (answers['v7-mode'] === 'framework') {
+ return {
+ title: 'React Router V7 - Framework mode',
+ path: '/docs/libraries/react-router/react-router-v7-framework-mode',
+ reason: 'You are using React Router V7 in framework mode (Remix V3). This is the default mode and functions as an SSR framework.',
+ }
+ }
+
+ if (answers['v7-mode'] === 'data') {
+ return {
+ title: 'React Router V7 - Data mode',
+ path: '/docs/libraries/react-router/react-router-v7-data-mode',
+ reason: 'You are using React Router V7 in data mode. This mode is for building SPAs with APIs like loader, action, and useFetcher.',
+ }
+ }
+
+ if (answers['v7-mode'] === 'declarative') {
+ return {
+ title: 'React Router V7 - Declarative mode',
+ path: '/docs/libraries/react-router/react-router-v7-declarative-mode',
+ reason: 'You are using React Router V7 in declarative mode. This mode is for building SPAs with basic routing.',
+ }
+ }
+
+ return {
+ title: 'React Router setup',
+ path: '/docs/libraries/react-router',
+ reason: 'Follow the React Router docs to identify your version and mode.',
+ }
+}
+
+const ReactRouterDecisionTree: React.FC = () => {
+ return
+}
+
+export default ReactRouterDecisionTree
diff --git a/contents/docs/libraries/react-router/_snippets/step-access-posthog-methods.mdx b/contents/docs/libraries/react-router/_snippets/step-access-posthog-methods.mdx
new file mode 100644
index 000000000000..331085f40dfc
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/step-access-posthog-methods.mdx
@@ -0,0 +1,15 @@
+
+
+On the client-side, you can access the PostHog client using the `usePostHog` hook. This hook returns the initialized PostHog client, which you can use to call PostHog methods. For example:
+
+```tsx
+import { usePostHog } from '@posthog/react'
+
+function App() {
+ const posthog = usePostHog()
+ return
+}
+```
+
+For a complete list of available methods, see the [posthog-js documentation](/docs/libraries/js).
+
diff --git a/contents/docs/libraries/react-router/_snippets/step-env-variables.mdx b/contents/docs/libraries/react-router/_snippets/step-env-variables.mdx
new file mode 100644
index 000000000000..b96561e6eb8a
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/step-env-variables.mdx
@@ -0,0 +1,7 @@
+Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project API key and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend.
+
+```shell file=.env.local
+VITE_PUBLIC_POSTHOG_KEY=
+VITE_PUBLIC_POSTHOG_HOST=
+```
+
diff --git a/contents/docs/libraries/react-router/_snippets/step-identify-user.mdx b/contents/docs/libraries/react-router/_snippets/step-identify-user.mdx
new file mode 100644
index 000000000000..14a865bd1acc
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/step-identify-user.mdx
@@ -0,0 +1,33 @@
+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 `identify` method on the PostHog client:
+
+```tsx
+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 (
+
+ {/* ... existing code ... */}
+
+
+ );
+}
+```
+
+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.
+
diff --git a/contents/docs/libraries/react-router/_snippets/step-install-client-sdks.mdx b/contents/docs/libraries/react-router/_snippets/step-install-client-sdks.mdx
new file mode 100644
index 000000000000..5431fa8042c7
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/step-install-client-sdks.mdx
@@ -0,0 +1,2 @@
+First, you'll need to install [`posthog-js`](https://github.com/posthog/posthog-js) and `@posthog/react` using your package manager. These packages allow you to capture **client-side** events.
+
diff --git a/contents/docs/libraries/react-router/_snippets/step-next-steps.mdx b/contents/docs/libraries/react-router/_snippets/step-next-steps.mdx
new file mode 100644
index 000000000000..1c8b1ce93220
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/step-next-steps.mdx
@@ -0,0 +1,11 @@
+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](/docs/libraries/js): Learn more about the PostHog Web SDK and how to use it on the client-side.
+- [PostHog Node SDK docs](/docs/libraries/node): Learn more about the PostHog Node SDK and how to use it on the server-side.
+- [Identify users](/docs/product-analytics/identify): Learn more about how to identify users in your app.
+- [Group analytics](/docs/product-analytics/group-analytics): Learn more about how to use group analytics in your app.
+- [PostHog AI](/docs/posthog-ai): After capturing events, use PostHog AI to help you understand your data and build insights.
+- [Feature flags and experiments](/docs/libraries/react#feature-flags): Feature flag and experiment setup is the same as React. You can find more details in the React integration guide.
+
diff --git a/contents/docs/libraries/react-router/_snippets/step-verify-client-events.mdx b/contents/docs/libraries/react-router/_snippets/step-verify-client-events.mdx
new file mode 100644
index 000000000000..3807a5f67e23
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/step-verify-client-events.mdx
@@ -0,0 +1,15 @@
+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](/docs/product-analytics/autocapture).
+
+You can also try to capture a custom event to verify it's working. You can access PostHog in any component using the `usePostHog` hook.
+
+```tsx
+import { usePostHog } from '@posthog/react'
+
+function App() {
+ const posthog = usePostHog()
+ return
+}
+```
+
+You should see these events in a minute or two in the [activity tab](https://app.posthog.com/activity/explore).
+
diff --git a/contents/docs/libraries/react-router/_snippets/tracking-element-visibility.mdx b/contents/docs/libraries/react-router/_snippets/tracking-element-visibility.mdx
new file mode 100644
index 000000000000..99f7d03c4b14
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/tracking-element-visibility.mdx
@@ -0,0 +1,71 @@
+The `PostHogCaptureOnViewed` component 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_viewed` event to PostHog when the wrapped element becomes visible in the viewport. It only fires once per component instance.
+
+**Basic usage:**
+
+```react
+import { PostHogCaptureOnViewed } from '@posthog/react'
+
+function App() {
+ return (
+
+
Your important content here
+
+ )
+}
+```
+
+**With custom properties:**
+
+You can include additional properties with the event to provide more context:
+
+```react
+
+
+
+```
+
+**Tracking multiple children:**
+
+Use `trackAllChildren` to track each child element separately. This is useful for galleries or lists where you want to know which specific items were viewed:
+
+```react
+
+
+
+
+
+```
+
+When `trackAllChildren` is enabled, each child element sends its own event with a `child_index` property indicating its position.
+
+**Custom intersection observer options:**
+
+You can customize when elements are considered "viewed" by passing options to the `IntersectionObserver`:
+
+```react
+
+
+
+```
+
+The component passes all other props to the wrapper `div`, so you can add styling, classes, or other HTML attributes as needed.
+
diff --git a/contents/docs/libraries/react-router/_snippets/typeerror-section.mdx b/contents/docs/libraries/react-router/_snippets/typeerror-section.mdx
new file mode 100644
index 000000000000..86d68cc90e32
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/typeerror-section.mdx
@@ -0,0 +1,16 @@
+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
+useEffect(() => {
+ posthog?.capture('test') // using optional chaining (recommended)
+
+ if (posthog) {
+ posthog.capture('test') // using an if statement
+ }
+}, [posthog])
+```
+
+Typescript helps protect against these errors.
+
diff --git a/contents/docs/libraries/react-router/_snippets/usage-warning.mdx b/contents/docs/libraries/react-router/_snippets/usage-warning.mdx
new file mode 100644
index 000000000000..ed86cd1d2a65
--- /dev/null
+++ b/contents/docs/libraries/react-router/_snippets/usage-warning.mdx
@@ -0,0 +1,6 @@
+
+
+When using React Router, you should not directly import `posthog` from `posthog-js` other than during initialization. Instead, use the `usePostHog` hook to access the PostHog client to ensure PostHog is initialized before use.
+
+
+
diff --git a/contents/docs/libraries/react-router/index.mdx b/contents/docs/libraries/react-router/index.mdx
new file mode 100644
index 000000000000..95c304e1333c
--- /dev/null
+++ b/contents/docs/libraries/react-router/index.mdx
@@ -0,0 +1,57 @@
+---
+title: React Router
+sidebarTitle: React Router
+sidebar: Docs
+showTitle: true
+github: 'https://github.com/PostHog/posthog-js'
+platformLogo: reactRouter
+features:
+ eventCapture: true
+ userIdentification: true
+ autoCapture: true
+ sessionRecording: true
+ featureFlags: true
+ groupAnalytics: true
+ surveys: true
+ llmAnalytics: false
+ errorTracking: true
+---
+
+import Tab from "components/Tab"
+import ReactInstall from '../../integrate/_snippets/install-react.mdx'
+import ReactRouterDecisionTree from './_snippets/react-router-decision-tree'
+
+This guide walks you through setting up PostHog for React Router. React Router V7 has [**three** distinct](https://reactrouter.com/start/modes) modes, and each requires a different setup. If you're still on React Router V6, we have a guide for that, too.
+
+## Which version/mode am I using?
+
+
+
+
+Differentiating between React Router versions and modes
+
+Here's are quick tips to help you figure out which version/mode you're using:
+
+First, check your `package.json` file for the `react-router` version. If it's `7.x.x`, you're using React Router V7. If it's `6.x.x`, you're using React Router V6.
+
+Then check your project to distinguish between the different modes:
+- If you see a `react-router.config.ts` file, you're using React Router V7 in framework mode.
+- If your router is configured like this: `` with router being a `createBrowserRouter` instance, you're using React Router V7 in data mode.
+- Finally, if your router has `` and `` elements, you're using React Router V7 in declarative mode.
+
+Follow the [React Router docs](https://reactrouter.com/start/modes) for more details.
+
+
+
+## React Router guides
+
+React Router V7 has [**three** distinct](https://reactrouter.com/start/modes) modes, and each requires a different setup. Some modes require only the client-side React SDK, while others require **both** the client-side React SDK and the server-side Node SDK.
+
+Follow the [React Router docs](https://reactrouter.com/start/modes) to find out which mode you're using, then follow the guide for that mode:
+
+| Guide | Description |
+|------|-------------|
+| [V7 - Framework mode (Remix V3)](/docs/libraries/react-router/react-router-v7-framework-mode) | This is the default mode. In framework mode, React Router functions as an SSR (server-side rendering) framework. |
+| [V7 - Declarative mode](/docs/libraries/react-router/react-router-v7-declarative-mode) | In declarative mode, you can build SPAs (single-page applications) with basic routing. |
+| [V7 - Data mode](/docs/libraries/react-router/react-router-v7-data-mode) | Data mode is also for building SPAs, but comes with APIs like loader, action, and useFetcher. |
+| [React Router V6](/docs/libraries/react-router/react-router-v6) | React Router V6 is for building SPAs and has features similar to React Router V7 in declarative or data mode. |
\ No newline at end of file
diff --git a/contents/docs/libraries/react-router/react-router-v6.mdx b/contents/docs/libraries/react-router/react-router-v6.mdx
new file mode 100644
index 000000000000..f8dc8848c90e
--- /dev/null
+++ b/contents/docs/libraries/react-router/react-router-v6.mdx
@@ -0,0 +1,224 @@
+---
+title: React Router V6
+sidebarTitle: React Router V6
+sidebar: Docs
+showTitle: true
+github: 'https://github.com/PostHog/posthog-js'
+platformLogo: reactRouter
+features:
+ eventCapture: true
+ userIdentification: true
+ autoCapture: true
+ sessionRecording: true
+ featureFlags: true
+ groupAnalytics: true
+ surveys: true
+ llmAnalytics: false
+ errorTracking: true
+tableOfContents: [
+ {
+ url: 'install-client-side-sdks',
+ value: 'Install client-side SDKs',
+ depth: 1,
+ },
+ {
+ url: 'add-your-environment-variables',
+ value: 'Add your environment variables',
+ depth: 1,
+ },
+ {
+ url: 'add-the-posthogprovider-to-your-app',
+ value: 'Add the PostHogProvider to your app',
+ depth: 1,
+ },
+ {
+ url: 'verify-client-side-events-are-captured',
+ value: 'Verify client-side events are captured',
+ depth: 1,
+ },
+ {
+ url: 'access-posthog-methods',
+ value: 'Access PostHog methods',
+ depth: 1,
+ },
+ {
+ url: 'identify-your-user',
+ value: 'Identify your user',
+ depth: 1,
+ },
+ {
+ url: 'create-an-error-boundary',
+ value: 'Create an error boundary',
+ depth: 1,
+ },
+ {
+ url: 'tracking-element-visibility',
+ value: 'Tracking element visibility',
+ depth: 1,
+ },
+ {
+ url: 'set-up-server-side-analytics',
+ value: 'Set up server-side analytics',
+ depth: 1,
+ },
+ {
+ url: 'next-steps',
+ value: 'Next steps',
+ depth: 1,
+ },
+]
+---
+
+
+import { Steps, Step } from 'components/Docs/Steps'
+import InstallReactPackageManagers from "../../integrate/_snippets/install-react-package-managers.mdx"
+import InstallNodePackageManagers from "../../integrate/_snippets/install-node-package-managers.mdx"
+import UsageWarning from "./_snippets/usage-warning.mdx"
+import StepInstallClientSdks from "./_snippets/step-install-client-sdks.mdx"
+import StepEnvVariables from "./_snippets/step-env-variables.mdx"
+import StepVerifyClientEvents from "./_snippets/step-verify-client-events.mdx"
+import StepAccessPostHogMethods from "./_snippets/step-access-posthog-methods.mdx"
+import StepIdentifyUser from "./_snippets/step-identify-user.mdx"
+import StepNextSteps from "./_snippets/step-next-steps.mdx"
+import TypeErrorSection from "./_snippets/typeerror-section.mdx"
+import TrackingElementVisibility from "./_snippets/tracking-element-visibility.mdx"
+
+This guide walks you through setting up PostHog for React Router V6. If you're using React Router v7, find the guide for that mode in the [React Router page](/docs/libraries/react-router). If you're using React with another framework, go to the [React integration guide](/docs/libraries/react).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+In declarative mode, you'll need to wrap your `BrowserRouter` with the `PostHogProvider` context. This passes an initialized PostHog client to your app.
+
+```tsx file=src/main.tsx
+import { StrictMode } from "react";
+import ReactDOM from "react-dom/client";
+import { BrowserRouter, Routes, Route } from "react-router";
+
+import posthog from 'posthog-js'; // +
+import { PostHogErrorBoundary, PostHogProvider } from '@posthog/react' // +
+
+// Initialize PostHog
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, { // +
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, // +
+ defaults: '2025-11-30', // +
+}); // +
+
+const root = document.getElementById("root");
+
+ReactDOM.createRoot(root).render(
+
+ {/* Pass PostHog client through PostHogProvider */}
+ // +
+
+
+ }>
+ {/* ... Your routes ... */}
+
+
+
+ // +
+ ,
+);
+```
+
+This initializes PostHog and passes it to your app through the `PostHogProvider` context.
+
+
+TypeError: Cannot read properties of undefined
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+PostHog can capture exceptions thrown in your app through an error boundary. PostHog provides a `PostHogErrorBoundary` component that you can use to capture exceptions. You can wrap your app with this component to capture exceptions.
+
+```tsx
+ReactDOM.createRoot(root).render(
+
+
+ // +
+
+
+ }>
+ {/* ... Your routes ... */}
+
+
+
+ // +
+
+ ,
+);
+```
+
+This automatically captures exceptions thrown in your React Router app using the `posthog.captureException()` method.
+
+
+
+
+
+
+
+
+
+
+
+Now that you've set up PostHog for React Router V7 in declarative mode, you can continue to set up server-side analytics. You can find our other SDKs in the [SDKs page](/docs/libraries).
+
+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:
+
+```tsx
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
+ defaults: '2025-11-30',
+ __add_tracing_headers: [ window.location.host, 'localhost' ], // +
+});
+```
+
+This adds the `X-POSTHOG-DISTINCT-ID` and `X-POSTHOG-SESSION-ID` headers to your requests, which you can later use on the server-side.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/contents/docs/libraries/react-router/react-router-v7-data-mode.mdx b/contents/docs/libraries/react-router/react-router-v7-data-mode.mdx
new file mode 100644
index 000000000000..9808e34e92dc
--- /dev/null
+++ b/contents/docs/libraries/react-router/react-router-v7-data-mode.mdx
@@ -0,0 +1,215 @@
+---
+title: React Router V7 data mode
+sidebarTitle: React Router V7 data mode
+sidebar: Docs
+showTitle: true
+github: 'https://github.com/PostHog/posthog-js'
+platformLogo: reactRouter
+features:
+ eventCapture: true
+ userIdentification: true
+ autoCapture: true
+ sessionRecording: true
+ featureFlags: true
+ groupAnalytics: true
+ surveys: true
+ llmAnalytics: false
+ errorTracking: true
+tableOfContents: [
+ {
+ url: 'install-client-side-sdks',
+ value: 'Install client-side SDKs',
+ depth: 1,
+ },
+ {
+ url: 'add-your-environment-variables',
+ value: 'Add your environment variables',
+ depth: 1,
+ },
+ {
+ url: 'add-the-posthogprovider-to-your-app',
+ value: 'Add the PostHogProvider to your app',
+ depth: 1,
+ },
+ {
+ url: 'verify-client-side-events-are-captured',
+ value: 'Verify client-side events are captured',
+ depth: 1,
+ },
+ {
+ url: 'access-posthog-methods',
+ value: 'Access PostHog methods',
+ depth: 1,
+ },
+ {
+ url: 'identify-your-user',
+ value: 'Identify your user',
+ depth: 1,
+ },
+ {
+ url: 'create-an-error-boundary',
+ value: 'Create an error boundary',
+ depth: 1,
+ },
+ {
+ url: 'tracking-element-visibility',
+ value: 'Tracking element visibility',
+ depth: 1,
+ },
+ {
+ url: 'set-up-server-side-analytics',
+ value: 'Set up server-side analytics',
+ depth: 1,
+ },
+ {
+ url: 'next-steps',
+ value: 'Next steps',
+ depth: 1,
+ },
+]
+---
+
+import { Steps, Step } from 'components/Docs/Steps'
+import InstallReactPackageManagers from "../../integrate/_snippets/install-react-package-managers.mdx"
+import InstallNodePackageManagers from "../../integrate/_snippets/install-node-package-managers.mdx"
+import UsageWarning from "./_snippets/usage-warning.mdx"
+import StepInstallClientSdks from "./_snippets/step-install-client-sdks.mdx"
+import StepEnvVariables from "./_snippets/step-env-variables.mdx"
+import StepVerifyClientEvents from "./_snippets/step-verify-client-events.mdx"
+import StepAccessPostHogMethods from "./_snippets/step-access-posthog-methods.mdx"
+import StepIdentifyUser from "./_snippets/step-identify-user.mdx"
+import StepNextSteps from "./_snippets/step-next-steps.mdx"
+import TypeErrorSection from "./_snippets/typeerror-section.mdx"
+import TrackingElementVisibility from "./_snippets/tracking-element-visibility.mdx"
+
+This guide walks you through setting up PostHog for React Router V7 in data mode. If you're using React Router in another mode, find the guide for that mode in the [React Router page](/docs/libraries/react-router). If you're using React with another framework, go to the [React integration guide](/docs/libraries/react).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+In data mode, you'll need to wrap your `RouterProvider` with the `PostHogProvider` context. This passes an initialized PostHog client to your app.
+
+```tsx file=app/index.tsx
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+import { createBrowserRouter, RouterProvider } from "react-router";
+import Root, { RootErrorBoundary } from "./app/root";
+
+import posthog from 'posthog-js'; // +
+import { PostHogProvider } from '@posthog/react' // +
+
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, { // +
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
+ defaults: '2025-11-30', // +
+}); // +
+
+const router = createBrowserRouter([...]);
+
+createRoot(document.getElementById("root")!).render(
+
+ {/* Pass PostHog client through PostHogProvider */}
+ // +
+
+ , // +
+ );
+});
+```
+
+This initializes PostHog and passes it to your app through the `PostHogProvider` context.
+
+
+TypeError: Cannot read properties of undefined
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+PostHog can capture exceptions thrown in your app through an error boundary. React Router in data mode has a built-in error boundary that you can use to capture exceptions. You can create an error boundary by exporting `RootErrorBoundary` from your `app/root.tsx` file.
+
+```tsx file=app/root.tsx
+import { usePostHog } from '@posthog/react'
+
+export function RootErrorBoundary() {
+ const error = useRouteError();
+
+ const posthog = usePostHog();
+ if (error) {
+ posthog.captureException(error);
+ }
+
+ // other error handling code...
+}
+
+```
+
+This automatically captures exceptions thrown in your React Router app using the `posthog.captureException()` method.
+
+
+
+
+
+
+
+
+
+
+
+Now that you've set up PostHog for React Router V7 in data mode, you can continue to set up server-side analytics. You can find our other SDKs in the [SDKs page](/docs/libraries).
+
+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:
+
+```tsx
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
+ defaults: '2025-11-30',
+ __add_tracing_headers: [ window.location.host, 'localhost' ], // +
+});
+```
+
+This adds the `X-POSTHOG-DISTINCT-ID` and `X-POSTHOG-SESSION-ID` headers to your requests, which you can later use on the server-side.
+
+
+
+
+
+
+
+
+
diff --git a/contents/docs/libraries/react-router/react-router-v7-declarative-mode.mdx b/contents/docs/libraries/react-router/react-router-v7-declarative-mode.mdx
new file mode 100644
index 000000000000..670d38967682
--- /dev/null
+++ b/contents/docs/libraries/react-router/react-router-v7-declarative-mode.mdx
@@ -0,0 +1,224 @@
+---
+title: React Router V7 declarative mode
+sidebarTitle: React Router V7 declarative mode
+sidebar: Docs
+showTitle: true
+github: 'https://github.com/PostHog/posthog-js'
+tableOfContents: [
+ {
+ url: 'install-client-side-sdks',
+ value: 'Install client-side SDKs',
+ depth: 1,
+ },
+ {
+ url: 'add-your-environment-variables',
+ value: 'Add your environment variables',
+ depth: 1,
+ },
+ {
+ url: 'add-the-posthogprovider-to-your-app',
+ value: 'Add the PostHogProvider to your app',
+ depth: 1,
+ },
+ {
+ url: 'verify-client-side-events-are-captured',
+ value: 'Verify client-side events are captured',
+ depth: 1,
+ },
+ {
+ url: 'access-posthog-methods',
+ value: 'Access PostHog methods',
+ depth: 1,
+ },
+ {
+ url: 'identify-your-user',
+ value: 'Identify your user',
+ depth: 1,
+ },
+ {
+ url: 'create-an-error-boundary',
+ value: 'Create an error boundary',
+ depth: 1,
+ },
+ {
+ url: 'tracking-element-visibility',
+ value: 'Tracking element visibility',
+ depth: 1,
+ },
+ {
+ url: 'set-up-server-side-analytics',
+ value: 'Set up server-side analytics',
+ depth: 1,
+ },
+ {
+ url: 'next-steps',
+ value: 'Next steps',
+ depth: 1,
+ },
+]
+platformLogo: reactRouter
+features:
+ eventCapture: true
+ userIdentification: true
+ autoCapture: true
+ sessionRecording: true
+ featureFlags: true
+ groupAnalytics: true
+ surveys: true
+ llmAnalytics: false
+ errorTracking: true
+---
+
+
+import { Steps, Step } from 'components/Docs/Steps'
+import InstallReactPackageManagers from "../../integrate/_snippets/install-react-package-managers.mdx"
+import InstallNodePackageManagers from "../../integrate/_snippets/install-node-package-managers.mdx"
+import UsageWarning from "./_snippets/usage-warning.mdx"
+import StepInstallClientSdks from "./_snippets/step-install-client-sdks.mdx"
+import StepEnvVariables from "./_snippets/step-env-variables.mdx"
+import StepVerifyClientEvents from "./_snippets/step-verify-client-events.mdx"
+import StepAccessPostHogMethods from "./_snippets/step-access-posthog-methods.mdx"
+import StepIdentifyUser from "./_snippets/step-identify-user.mdx"
+import StepNextSteps from "./_snippets/step-next-steps.mdx"
+import TypeErrorSection from "./_snippets/typeerror-section.mdx"
+import TrackingElementVisibility from "./_snippets/tracking-element-visibility.mdx"
+
+This guide walks you through setting up PostHog for React Router V7 in declarative mode. If you're using React Router in another mode, find the guide for that mode in the [React Router page](/docs/libraries/react-router). If you're using React with another framework, go to the [React integration guide](/docs/libraries/react).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+In declarative mode, you'll need to wrap your `BrowserRouter` with the `PostHogProvider` context. This passes an initialized PostHog client to your app.
+
+```tsx file=src/main.tsx
+import { StrictMode } from "react";
+import ReactDOM from "react-dom/client";
+import { BrowserRouter, Routes, Route } from "react-router";
+
+import posthog from 'posthog-js'; // +
+import { PostHogErrorBoundary, PostHogProvider } from '@posthog/react' // +
+
+// Initialize PostHog
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, { // +
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, // +
+ defaults: '2025-11-30', // +
+}); // +
+
+const root = document.getElementById("root");
+
+ReactDOM.createRoot(root).render(
+
+ {/* Pass PostHog client through PostHogProvider */}
+ // +
+
+
+ }>
+ {/* ... Your routes ... */}
+
+
+
+ // +
+ ,
+);
+```
+
+This initializes PostHog and passes it to your app through the `PostHogProvider` context.
+
+
+TypeError: Cannot read properties of undefined
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+PostHog can capture exceptions thrown in your app through an error boundary. PostHog provides a `PostHogErrorBoundary` component that you can use to capture exceptions. You can wrap your app with this component to capture exceptions.
+
+```tsx
+ReactDOM.createRoot(root).render(
+
+
+ // +
+
+
+ }>
+ {/* ... Your routes ... */}
+
+
+
+ // +
+
+ ,
+);
+```
+
+This automatically captures exceptions thrown in your React Router app using the `posthog.captureException()` method.
+
+
+
+
+
+
+
+
+
+
+
+Now that you've set up PostHog for React Router V7 in declarative mode, you can continue to set up server-side analytics. You can find our other SDKs in the [SDKs page](/docs/libraries).
+
+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:
+
+```tsx
+posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
+ defaults: '2025-11-30',
+ __add_tracing_headers: [ window.location.host, 'localhost' ], // +
+});
+```
+
+This adds the `X-POSTHOG-DISTINCT-ID` and `X-POSTHOG-SESSION-ID` headers to your requests, which you can later use on the server-side.
+
+
+
+
+
+
+
+
+
diff --git a/contents/docs/libraries/react-router/react-router-v7-framework-mode.mdx b/contents/docs/libraries/react-router/react-router-v7-framework-mode.mdx
new file mode 100644
index 000000000000..ee4275a58da7
--- /dev/null
+++ b/contents/docs/libraries/react-router/react-router-v7-framework-mode.mdx
@@ -0,0 +1,309 @@
+---
+title: React Router V7 framework mode (Remix V3)
+sidebarTitle: React Router V7 framework mode
+sidebar: Docs
+showTitle: true
+github: 'https://github.com/PostHog/posthog-js'
+tableOfContents: [
+ {
+ url: 'install-client-side-sdks',
+ value: 'Install client-side SDKs',
+ depth: 1,
+ },
+ {
+ url: 'add-your-environment-variables',
+ value: 'Add your environment variables',
+ depth: 1,
+ },
+ {
+ url: 'add-the-posthogprovider-to-your-app',
+ value: 'Add the PostHogProvider to your app',
+ depth: 1,
+ },
+ {
+ url: 'verify-client-side-events-are-captured',
+ value: 'Verify client-side events are captured',
+ depth: 1,
+ },
+ {
+ url: 'access-posthog-methods',
+ value: 'Access PostHog methods',
+ depth: 1,
+ },
+ {
+ url: 'identify-your-user',
+ value: 'Identify your user',
+ depth: 1,
+ },
+ {
+ url: 'create-an-error-boundary',
+ value: 'Create an error boundary',
+ depth: 1,
+ },
+ {
+ url: 'tracking-element-visibility',
+ value: 'Tracking element visibility',
+ depth: 1,
+ },
+ {
+ url: 'install-server-side-sdks',
+ value: 'Install server-side SDKs',
+ depth: 1,
+ },
+ {
+ url: 'create-a-server-side-middleware',
+ value: 'Create a server-side middleware',
+ depth: 1,
+ },
+ {
+ url: 'verify-server-side-events-are-captured',
+ value: 'Verify server-side events are captured',
+ depth: 1,
+ },
+ {
+ url: 'next-steps',
+ value: 'Next steps',
+ depth: 1,
+ },
+]
+platformLogo: reactRouter
+features:
+ eventCapture: true
+ userIdentification: true
+ autoCapture: true
+ sessionRecording: true
+ featureFlags: true
+ groupAnalytics: true
+ surveys: true
+ llmAnalytics: false
+ errorTracking: true
+---
+
+import { Steps, Step } from 'components/Docs/Steps'
+import InstallReactPackageManagers from "../../integrate/_snippets/install-react-package-managers.mdx"
+import InstallNodePackageManagers from "../../integrate/_snippets/install-node-package-managers.mdx"
+import UsageWarning from "./_snippets/usage-warning.mdx"
+import StepInstallClientSdks from "./_snippets/step-install-client-sdks.mdx"
+import StepEnvVariables from "./_snippets/step-env-variables.mdx"
+import StepVerifyClientEvents from "./_snippets/step-verify-client-events.mdx"
+import StepAccessPostHogMethods from "./_snippets/step-access-posthog-methods.mdx"
+import StepIdentifyUser from "./_snippets/step-identify-user.mdx"
+import StepNextSteps from "./_snippets/step-next-steps.mdx"
+import TypeErrorSection from "./_snippets/typeerror-section.mdx"
+import TrackingElementVisibility from "./_snippets/tracking-element-visibility.mdx"
+
+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](/docs/libraries/react-router). If you're using React with another framework, go to the [React integration guide](/docs/libraries/react).
+
+
+
+
+
+
+
+
+
+In framework mode, you'll also need to set `posthog-js` and `@posthog/react` as external packages in your `vite.config.ts` file to avoid SSR errors.
+
+```ts file=vite.config.ts
+// ... imports
+
+export default defineConfig({
+ plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
+ ssr: {
+ noExternal: ['posthog-js', '@posthog/react']
+ }
+});
+```
+
+
+
+
+
+
+
+
+
+
+
+In framework mode, your app enters from the `app/entry.client.tsx` file. In this file, you'll need to initialize the PostHog SDK and pass it to your app through the `PostHogProvider` context.
+
+```tsx file=app/entry.client.tsx
+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_KEY, { // +
+ api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, // +
+ defaults: '2025-11-30', // +
+ __add_tracing_headers: [ window.location.host, 'localhost' ], // +
+}); // +
+
+
+startTransition(() => {
+ hydrateRoot(
+ document,
+ {/* Pass PostHog client through 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 the `X-POSTHOG-DISTINCT-ID` and `X-POSTHOG-SESSION-ID` headers to your requests, which we'll later use on the server-side.
+
+
+TypeError: Cannot read properties of undefined
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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 `ErrorBoundary` from your `app/root.tsx` file.
+
+```tsx file=app/root.tsx
+import { usePostHog } from '@posthog/react'
+
+export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
+ const posthog = usePostHog();
+ posthog?.captureException(error);
+
+ // other error handling code...
+ return (
+
+
Something went wrong
+
{error.message}
+
+ );
+}
+```
+
+This automatically captures exceptions thrown in your React Router app using the `posthog.captureException()` method.
+
+
+
+
+
+
+
+
+
+
+
+Install the [PostHog Node SDK](/docs/libraries/node) using your package manager. This is the SDK you'll use to capture server-side events.
+
+
+
+
+
+
+
+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-ID` and `X-POSTHOG-DISTINCT-ID` headers and pass them to your request as a [context](/docs/libraries/node#contexts). 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.
+
+```ts file=app/lib/posthog-middleware.ts
+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_KEY!, {
+ 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.tsx` file by exporting it in the `Route.MiddlewareFunction[]` array.
+
+```tsx file=app/root.tsx
+import { posthogMiddleware } from './lib/posthog-middleware';
+
+export const middleware: Route.MiddlewareFunction[] = [
+ posthogMiddleware,
+ // other middlewares...
+];
+```
+
+
+
+
+
+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.
+
+```tsx file=app/routes/api.checkout.ts
+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 ...
+ });
+}
+```
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/contents/docs/libraries/react/index.mdx b/contents/docs/libraries/react/index.mdx
index 554784558652..f6e79b32722b 100644
--- a/contents/docs/libraries/react/index.mdx
+++ b/contents/docs/libraries/react/index.mdx
@@ -4,8 +4,7 @@ sidebarTitle: React
sidebar: Docs
showTitle: true
github: 'https://github.com/PostHog/posthog-js'
-icon: >-
- https://res.cloudinary.com/dmukukwp6/image/upload/posthog.com/contents/images/docs/integrate/react.svg
+platformLogo: react
features:
eventCapture: true
userIdentification: true
@@ -18,13 +17,37 @@ features:
errorTracking: true
---
-import DetailSetUpReverseProxy from "../../integrate/_snippets/details/set-up-reverse-proxy.mdx"
-import DetailGroupProductsInOneProject from "../../integrate/_snippets/details/group-products-in-one-project.mdx"
-import DetailPostHogIPs from "../../integrate/_snippets/details/posthog-ips.mdx"
+import List from 'components/List'
+import { getLogo } from 'constants/logos'
PostHog makes it easy to get data about traffic and usage of your React app. Integrating PostHog into your site enables analytics about user behavior, custom events capture, session recordings, feature flags, and more.
-This guide walks you through an example integration of PostHog using React and the [posthog-js library](/docs/integrate/client/js).
+This guide walks you through an example integration of PostHog using vanilla React and the [posthog-js library](/docs/integrate/client/js).
+
+## Using a framework?
+
+Using React with a framework like Next.js, Remix, or React Router requires additional setup. Follow their respective guides instead:
+
+
import AgentIntegrationSection from "../../components/AgentIntegrationSection.mdx"
@@ -36,11 +59,6 @@ import ReactInstall from '../../integrate/_snippets/install-react.mdx'
-
-
-
-
-
## Usage
@@ -70,13 +88,17 @@ root.render(
);
```
-### Using posthog-js functions
+### Calling PostHog methods
By default, the `posthog-js` library automatically captures pageviews, element clicks, inputs, and more. Autocapture can be tuned in with [the configuration options](/docs/product-analytics/autocapture#configuring-autocapture).
-If you want to use the library to identify users, capture events, use feature flags, or use other features, you can access the initialized `posthog-js` library using the `usePostHog` hook.
+To call PostHog methods for actions like identifying users, capturing events, using feature flags, or using other features, you can access the initialized `posthog-js` library using the `usePostHog` hook.
-**Do not directly import `posthog` apart from installation** as shown above. This will likely cause errors as the library might not be initialized yet. Initialization is handled automatically when you use the `PostHogProvider` and hook.
+
+
+ Always use the `usePostHog` hook to access the PostHog library. Directly importing `posthog` will likely cause errors as the library might not be initialized yet. Initialization is handled automatically when you use the `PostHogProvider` and hook.
+
+
All the methods of the library are available and can be used as described in the [posthog-js documentation](/docs/libraries/js).
@@ -86,6 +108,7 @@ import { useEffect } from 'react'
import { useUser, useLogin } from '../lib/user'
function App() {
+ // `usePostHog`, like other React contexts, must be called at the top level of your component
const posthog = usePostHog()
const login = useLogin()
const user = useUser()
@@ -121,7 +144,7 @@ function App() {
export default App
```
-#### TypeError: Cannot read properties of undefined
+### 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.
@@ -145,7 +168,7 @@ The `PostHogCaptureOnViewed` component enables you to automatically capture even
The component wraps your content and sends a `$element_viewed` event to PostHog when the wrapped element becomes visible in the viewport. It only fires once per component instance.
-#### Basic usage
+**Basic usage:**
```react
import { PostHogCaptureOnViewed } from '@posthog/react'
@@ -159,7 +182,7 @@ function App() {
}
```
-#### With custom properties
+**With custom properties:**
You can include additional properties with the event to provide more context:
@@ -176,7 +199,7 @@ You can include additional properties with the event to provide more context:
```
-#### Tracking multiple children
+**Tracking multiple children:**
Use `trackAllChildren` to track each child element separately. This is useful for galleries or lists where you want to know which specific items were viewed:
@@ -194,7 +217,7 @@ Use `trackAllChildren` to track each child element separately. This is useful fo
When `trackAllChildren` is enabled, each child element sends its own event with a `child_index` property indicating its position.
-#### Custom intersection observer options
+**Custom intersection observer options:**
You can customize when elements are considered "viewed" by passing options to the `IntersectionObserver`:
@@ -230,7 +253,7 @@ import BootstrappingIntro from "../../feature-flags/snippets/bootstrapping-intro
For details on how to implement bootstrapping, see our [bootstrapping guide](/docs/feature-flags/bootstrapping).
-### Experiments (A/B tests)
+## Experiments (A/B tests)
Since [experiments](/docs/experiments/manual) use feature flags, the code for running an experiment is very similar to the feature flags code:
@@ -264,3 +287,4 @@ function App() {
```
It's also possible to [run experiments without using feature flags](/docs/experiments/running-experiments-without-feature-flags).
+
diff --git a/contents/docs/libraries/remix.mdx b/contents/docs/libraries/remix.mdx
index f47f47a39081..184d29da1c72 100644
--- a/contents/docs/libraries/remix.mdx
+++ b/contents/docs/libraries/remix.mdx
@@ -10,6 +10,12 @@ import DetailPostHogIPs from "../integrate/_snippets/details/posthog-ips.mdx"
PostHog makes it easy to get data about traffic and usage of your [Remix](https://remix.run/) app. Integrating PostHog into your site enables analytics about user behavior, custom events capture, session recordings, feature flags, and more.
+
+
+Remix V3 is now React Router V7 framework mode. Please refer to the [React Router V7 framework mode](/docs/libraries/react-router/react-router-v7-framework-mode) guide instead for instructions on how to integrate PostHog.
+
+
+
This guide walks you through integrating PostHog into your Remix app using the [JavaScript Web SDK](/docs/libraries/js).
## Installation
diff --git a/src/constants/logos.ts b/src/constants/logos.ts
index 61cf50c15a3e..2cf754befb37 100644
--- a/src/constants/logos.ts
+++ b/src/constants/logos.ts
@@ -55,6 +55,7 @@ export const LOGOS = {
python: 'https://res.cloudinary.com/dmukukwp6/image/upload/posthog.com/contents/images/docs/integrate/python.svg',
railway: 'https://res.cloudinary.com/dmukukwp6/image/upload/logo_dark_f8e870867f.svg',
react: 'https://res.cloudinary.com/dmukukwp6/image/upload/posthog.com/contents/images/docs/integrate/react.svg',
+ reactRouter: 'https://res.cloudinary.com/dmukukwp6/image/upload/rr_logo_light_970950178e.svg',
redditAds: 'https://res.cloudinary.com/dmukukwp6/image/upload/reddit_logo_f6d4c5cb0b.svg',
remix: 'https://res.cloudinary.com/dmukukwp6/image/upload/remix_letter_glowing_49183adce2.svg',
revenuecat: 'https://res.cloudinary.com/dmukukwp6/image/upload/logomark_red_background_9ea591e17a.svg',
diff --git a/src/navs/index.js b/src/navs/index.js
index 0765ecb63148..21490b379efb 100644
--- a/src/navs/index.js
+++ b/src/navs/index.js
@@ -2180,14 +2180,40 @@ export const docsMenu = {
name: 'Phoenix',
url: '/docs/libraries/phoenix',
},
- {
- name: 'Remix',
- url: '/docs/libraries/remix',
+ {
+ name: 'React Router',
+ url: '/docs/libraries/react-router',
+ children: [
+ {
+ name: 'Overview',
+ url: '/docs/libraries/react-router',
+ },
+ {
+ name: 'V7 Framework mode',
+ url: '/docs/libraries/react-router/react-router-v7-framework-mode',
+ },
+ {
+ name: 'V7 Declarative mode',
+ url: '/docs/libraries/react-router/react-router-v7-declarative-mode',
+ },
+ {
+ name: 'V7 Data mode',
+ url: '/docs/libraries/react-router/react-router-v7-data-mode',
+ },
+ {
+ name: 'V6',
+ url: '/docs/libraries/react-router/react-router-v6',
+ },
+ ],
},
{
name: 'Svelte',
url: '/docs/libraries/svelte',
},
+ {
+ name: 'Remix',
+ url: '/docs/libraries/remix',
+ },
{
name: 'Vue.js',
url: '/docs/libraries/vue-js',