The PostHog React integration provides a seamless way to add analytics, feature flags, and session replay to your React applications using hooks and context providers.
Installation
Install both posthog-js and the React wrapper:
npm install posthog-js @posthog/react
yarn add posthog-js @posthog/react
pnpm add posthog-js @posthog/react
Setup
Add environment variables
Create or update your .env file with your PostHog credentials. For Vite-based apps, use the VITE_PUBLIC_ prefix: VITE_PUBLIC_POSTHOG_KEY =< ph_project_token >
VITE_PUBLIC_POSTHOG_HOST =< ph_client_api_host >
For Create React App, use the REACT_APP_ prefix: REACT_APP_POSTHOG_KEY =< ph_project_token >
REACT_APP_POSTHOG_HOST =< ph_client_api_host >
Wrap your app with PostHogProvider
Add the PostHogProvider at the root of your application (typically in main.tsx or index.tsx): Vite (main.tsx)
Create React App (index.tsx)
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { PostHogProvider } from '@posthog/react'
const options = {
api_host: import . meta . env . VITE_PUBLIC_POSTHOG_HOST ,
defaults: '2026-01-30' ,
} as const
createRoot ( document . getElementById ( 'root' )). render (
< StrictMode >
< PostHogProvider
apiKey = { import . meta . env . VITE_PUBLIC_POSTHOG_KEY }
options = { options }
>
< App />
</ PostHogProvider >
</ StrictMode >
)
The defaults option automatically configures PostHog with recommended settings. See SDK defaults for details.
Verify installation
Check your browser’s developer console for PostHog logs, or visit your Activity feed to see events.
Using the usePostHog Hook
Access the PostHog instance in any component using the usePostHog hook:
import { usePostHog } from '@posthog/react'
function MyComponent () {
const posthog = usePostHog ()
function handleClick () {
posthog . capture ( 'button_clicked' , {
button_name: 'signup' ,
page: 'homepage'
})
}
return < button onClick = { handleClick } > Sign up </ button >
}
Capturing Events
Custom Events
import { usePostHog } from '@posthog/react'
function ProductPage () {
const posthog = usePostHog ()
const handlePurchase = ( product , amount ) => {
posthog . capture ( 'purchase_completed' , {
product_id: product . id ,
product_name: product . name ,
amount: amount ,
currency: 'USD'
})
}
return (
< button onClick = { () => handlePurchase ( product , 99.99 ) } >
Buy Now
</ button >
)
}
Track Component Lifecycle
import { useEffect } from 'react'
import { usePostHog } from '@posthog/react'
function Dashboard () {
const posthog = usePostHog ()
useEffect (() => {
posthog . capture ( 'dashboard_viewed' )
}, [])
return < div > Dashboard Content </ div >
}
Identifying Users
On Login
import { usePostHog } from '@posthog/react'
function LoginForm () {
const posthog = usePostHog ()
const handleLogin = async ( email , password ) => {
const user = await login ( email , password )
posthog . identify ( user . id , {
email: user . email ,
name: user . name ,
plan: user . plan
})
}
return < form onSubmit = { handleLogin } > { /* ... */ } </ form >
}
On Logout
import { usePostHog } from '@posthog/react'
function LogoutButton () {
const posthog = usePostHog ()
const handleLogout = () => {
logout ()
posthog . reset ()
}
return < button onClick = { handleLogout } > Logout </ button >
}
Feature Flags
useFeatureFlagEnabled Hook
Check if a feature flag is enabled:
import { useFeatureFlagEnabled } from '@posthog/react'
function FeatureComponent () {
const showNewDashboard = useFeatureFlagEnabled ( 'new-dashboard' )
if ( showNewDashboard ) {
return < NewDashboard />
}
return < OldDashboard />
}
useFeatureFlagVariantKey Hook
Get the variant of a multivariate flag:
import { useFeatureFlagVariantKey } from '@posthog/react'
function ExperimentButton () {
const variant = useFeatureFlagVariantKey ( 'button-color-experiment' )
const buttonColor = {
'blue' : '#0000FF' ,
'green' : '#00FF00' ,
'red' : '#FF0000'
}[ variant ] || '#808080'
return (
< button style = { { backgroundColor: buttonColor } } >
Click me
</ button >
)
}
useFeatureFlagPayload Hook
Retrieve feature flag payload data:
import { useFeatureFlagPayload } from '@posthog/react'
function ConfigurableComponent () {
const config = useFeatureFlagPayload ( 'feature-config' )
return (
< div >
< h1 > { config ?. title || 'Default Title' } </ h1 >
< p > Max items: { config ?. maxItems || 10 } </ p >
</ div >
)
}
Manual Flag Checking
import { usePostHog } from '@posthog/react'
function FeatureGate () {
const posthog = usePostHog ()
const handleAction = () => {
if ( posthog . isFeatureEnabled ( 'premium-feature' )) {
performPremiumAction ()
} else {
showUpgradePrompt ()
}
}
return < button onClick = { handleAction } > Action </ button >
}
Accessing PostHog Outside Components
For utility functions or non-React code:
import posthog from 'posthog-js'
export function trackPurchase ( amount : number ) {
posthog . capture ( 'purchase_completed' , { amount })
}
export function checkFeature ( flagName : string ) : boolean {
return posthog . isFeatureEnabled ( flagName )
}
React Router Integration
Track route changes automatically:
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { usePostHog } from '@posthog/react'
function App () {
const location = useLocation ()
const posthog = usePostHog ()
useEffect (() => {
posthog . capture ( '$pageview' )
}, [ location , posthog ])
return < Routes > { /* your routes */ } </ Routes >
}
Group Analytics
Track events for organizations or teams:
import { usePostHog } from '@posthog/react'
function OrganizationSettings () {
const posthog = usePostHog ()
useEffect (() => {
posthog . group ( 'company' , 'company_id_123' , {
name: 'Acme Corporation' ,
plan: 'enterprise'
})
}, [])
const handleFeatureUse = () => {
posthog . capture ( 'feature_used' , {
feature_name: 'advanced_analytics'
})
}
return < div > { /* ... */ } </ div >
}
Advanced Configuration
Session Recording
Disable Autocapture
import { PostHogProvider } from '@posthog/react'
const options = {
api_host: import . meta . env . VITE_PUBLIC_POSTHOG_HOST ,
session_recording: {
recordCrossOriginIframes: true ,
maskAllInputs: false ,
maskInputOptions: {
password: true ,
email: true
}
}
}
root . render (
< PostHogProvider apiKey = { apiKey } options = { options } >
< App />
</ PostHogProvider >
)
Privacy Controls
Mask sensitive elements in session replay:
function SensitiveForm () {
return (
< form >
< input
type = "text"
placeholder = "Name"
/>
< input
type = "email"
placeholder = "Email"
className = "ph-no-capture" // This input won't be recorded
/>
< div className = "ph-mask" >
This text will be masked in recordings
</ div >
</ form >
)
}
TypeScript Support
The SDK includes full TypeScript support:
import { PostHog } from 'posthog-js'
import { usePostHog } from '@posthog/react'
interface CustomEventProperties {
button_name : string
page : string
}
function TypedComponent () {
const posthog : PostHog = usePostHog ()
const handleClick = () => {
posthog . capture < CustomEventProperties >( 'button_clicked' , {
button_name: 'signup' ,
page: 'homepage'
})
}
return < button onClick = { handleClick } > Click </ button >
}
Debugging
Enable debug mode during development:
import { PostHogProvider } from '@posthog/react'
const options = {
api_host: import . meta . env . VITE_PUBLIC_POSTHOG_HOST ,
debug: import . meta . env . DEV // Enable in development only
}
Best Practices
Provider Placement : Always place PostHogProvider as high as possible in your component tree to ensure all components have access.
Avoid Over-tracking : Don’t track every click. Focus on meaningful user actions that help you understand product usage.
Use Hooks : Prefer usePostHog and feature flag hooks over importing posthog-js directly for better React integration.
Reset on Logout : Always call posthog.reset() when users log out to prevent data leakage between accounts.
Next Steps
Next.js Integration Add PostHog to Next.js with SSR support
Feature Flags Learn advanced feature flag patterns
Session Replay Configure privacy and recording options
JavaScript SDK Full JavaScript SDK reference