Integration React Vite
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 systematic, four-phase workflow for developers to integrate PostHog analytics into React applications using Vite. It emphasizes best practices such as using environment variables for keys, maintaining minimal code changes, and ensuring proper event tracking across both client and server boundaries. The skill includes specific guidelines for React development, such as avoiding useEffect for event-driven logic and correctly identifying users during authentication flows.
What it does
- Guides the creation of an event tracking plan via a JSON configuration file.
- Provides a step-by-step process for implementing event capture code.
- Ensures consistent user identification across client and server sessions.
- Includes instructions for adding error tracking to critical application flows.
- Enforces React-specific best practices for state management and event handling.
- Requires the use of environment variables for secure configuration.
When to use it
- When you need to add PostHog analytics to a React project using Vite.
- When you want to ensure your analytics implementation follows established best practices.
- When you need to correlate client-side and server-side user events.
- When you are setting up error tracking for critical user journeys.
Advantages
- Structured, repeatable process reduces implementation errors.
- Promotes clean code by requiring minimal, targeted changes.
- Ensures secure handling of API keys via environment variables.
- Facilitates accurate user correlation between frontend and backend.
Usage examples
- “Integrate PostHog into my React Vite project.”
- The agent will initiate the four-phase workflow, starting with an analysis of your project to create a .posthog-events.json plan.
- “How should I track user logins in my React app?”
- The agent will guide you to use the identify() function during login events, ensuring the distinct ID is passed correctly to maintain session correlation.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/posthog/integration-react-vite/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip integration-react-vite.zip -d .agents/skills
Documentation by PostHog
PostHog integration for React (Vite)
This skill helps you add PostHog analytics to React (Vite) 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/react.md- React - 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 AutoGineer966 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md2.8 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.md18.5 KiB
references/react.md
React - Docs
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 vanilla React and the posthog-js library.
Using a framework?
Using React with a framework like Next.js, Remix, or React Router requires additional setup. Follow their respective guides instead:
Beta: integration via LLM
Install PostHog for React in seconds with our wizard by running this prompt with LLM coding agents like Cursor and Bolt, or by running it in your terminal.
npx @posthog/wizard@latest
Or, to integrate manually, continue with the rest of this guide.
Installation
For React-based frameworks, we recommend the Next.js integration guide and Next.js integration guide instead.
Install
posthog-jsand@posthog/reactusing your package manager:
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/reactAdd 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, includeVITE_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.comIntegrate PostHog at the root of your app (such as
main.jsxfor Vite apps androot.tsxfor React Router V7).
React
PostHog AI
// src/main.jsx
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'
posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, {
api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
defaults: '2026-01-30',
});
createRoot(document.getElementById('root')).render(
<StrictMode>
<PostHogProvider client={posthog}>
<App />
</PostHogProvider>
</StrictMode>,
)Don't directly import PostHog
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.
Identifying users
Identifying users is required. Call
posthog.identify('your-user-id')after login to link events to a known user. This is what connects frontend event captures, session replays, LLM traces, and error tracking to the same person — and lets backend events link back too.See our guide on identifying users for how to set this up.
Usage
PostHog provider
The React context provider makes it easy to access the posthog-js library in your app.
The provider takes an initialized and configured client instance like this:
React
PostHog AI
// src/index.js
import posthog from 'posthog-js';
import { PostHogProvider} from '@posthog/react'
posthog.init(process.env.REACT_APP_PUBLIC_POSTHOG_TOKEN, {
api_host: process.env.REACT_APP_PUBLIC_POSTHOG_HOST,
defaults: '2026-01-30',
});
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<PostHogProvider client={posthog}>
<App />
</PostHogProvider>
</React.StrictMode>
);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.
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.
Don't directly import PostHog
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.
React
PostHog AI
import { usePostHog } from '@posthog/react'
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()
useEffect(() => {
if (user) {
// Identify sends an event, so you may want to limit how often you call it
posthog?.identify(user.id, {
email: user.email,
})
posthog?.group('company', user.company_id)
}
}, [posthog, user.id, user.email, user.company_id])
const loginClicked = () => {
posthog?.capture('clicked_log_in')
login()
}
return (
<div className="App">
{/* Fire a custom event when the button is clicked */}
<button onClick={() => posthog?.capture('button_clicked')}>Click me</button>
{/* This button click event is autocaptured by default */}
<button data-attr="autocapture-button">Autocapture buttons</button>
{/* This button click event is not autocaptured */}
<button className="ph-no-capture">Ignore certain elements</button>
<button onClick={loginClicked}>Login</button>
</div>
)
}
export default AppTypeError: 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.
Tracking element visibility
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
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 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
PostHog AI
<PostHogCaptureOnViewed
name="product-gallery"
properties={{ gallery_type: 'featured' }}
trackAllChildren
>
<ProductCard id="1" />
<ProductCard id="2" />
<ProductCard id="3" />
</PostHogCaptureOnViewed>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
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.
Feature flags
PostHog's feature flags enable you to safely deploy and roll back new features as well as target specific users and groups with them.
There are two ways to implement feature flags in React:
Using hooks.
Using the
<PostHogFeature>component.
Method 1: Using hooks
PostHog provides several hooks to make it easy to use feature flags in your React app.
| Hook | Description |
|---|---|
| useFeatureFlagEnabled | Returns a boolean indicating whether the feature flag is enabled. This sends a $feature_flag_called event. |
| useFeatureFlagVariantKey | Returns the variant key of the feature flag. This sends a $feature_flag_called event. |
| useActiveFeatureFlags | Returns an array of active feature flags. This does not send a $feature_flag_called event. |
| useFeatureFlagPayload | Returns the payload of the feature flag. This does not send a $feature_flag_called event. Always use this with useFeatureFlagEnabled or useFeatureFlagVariantKey. |
Example 1: Using a boolean feature flag
React
PostHog AI
import { useFeatureFlagEnabled } from '@posthog/react'
function App() {
const showWelcomeMessage = useFeatureFlagEnabled('flag-key')
const payload = useFeatureFlagPayload('flag-key')
return (
<div className="App">
{
showWelcomeMessage ? (
<div>
<h1>Welcome!</h1>
<p>Thanks for trying out our feature flags.</p>
</div>
) : (
<div>
<h2>No welcome message</h2>
<p>Because the feature flag evaluated to false.</p>
</div>
)
}
</div>
);
}
export default App;Example 2: Using a multivariate feature flag
React
PostHog AI
import { useFeatureFlagVariantKey } from '@posthog/react'
function App() {
const variantKey = useFeatureFlagVariantKey('show-welcome-message')
let welcomeMessage = ''
if (variantKey === 'variant-a') {
welcomeMessage = 'Welcome to the Alpha!'
} else if (variantKey === 'variant-b') {
welcomeMessage = 'Welcome to the Beta!'
}
return (
<div className="App">
{
welcomeMessage ? (
<div>
<h1>{welcomeMessage}</h1>
<p>Thanks for trying out our feature flags.</p>
</div>
) : (
<div>
<h2>No welcome message</h2>
<p>Because the feature flag evaluated to false.</p>
</div>
)
}
</div>
);
}
export default App;Example 3: Using a flag payload
Payload hook
The useFeatureFlagPayload hook does not send a $feature_flag_called event, which is required for the experiment to be tracked. To ensure the exposure event is sent, you should always use the useFeatureFlagPayload hook with either the useFeatureFlagEnabled or useFeatureFlagVariantKey hook.
React
PostHog AI
import { useFeatureFlagPayload } from '@posthog/react'
function App() {
const variant = useFeatureFlagEnabled('show-welcome-message')
const payload = useFeatureFlagPayload('show-welcome-message')
return (
<>
{
variant ? (
<div className="welcome-message">
<h2>{payload?.welcomeTitle}</h2>
<p>{payload?.welcomeMessage}</p>
</div>
) : <div>
<h2>No custom welcome message</h2>
<p>Because the feature flag evaluated to false.</p>
</div>
}
</>
)
}Method 2: Using the PostHogFeature component
The PostHogFeature component simplifies code by handling feature flag related logic.
It also automatically captures metrics, like how many times a user interacts with this feature.
Note: You still need the
PostHogProviderat the top level for this to work.
Here is an example:
React
PostHog AI
import { PostHogFeature } from '@posthog/react'
function App() {
return (
<PostHogFeature flag='show-welcome-message' match={true}>
<div>
<h1>Hello</h1>
<p>Thanks for trying out our feature flags.</p>
</div>
</PostHogFeature>
)
}The
matchon the component can be eithertrue, or the variant key, to match on a specific variant.If you also want to show a default message, you can pass these in the
fallbackattribute.
If you wish to customise logic around when the component is considered visible, you can pass in visibilityObserverOptions to the feature. These take the same options as the IntersectionObserver API. By default, we use a threshold of 0.1.
Payloads
If your flag has a payload, you can pass a function to children whose first argument is the payload. For example:
React
PostHog AI
import { PostHogFeature } from '@posthog/react'
function App() {
return (
<PostHogFeature flag='show-welcome-message' match={true}>
{(payload) => {
return (
<div>
<h1>{payload.welcomeMessage}</h1>
<p>Thanks for trying out our feature flags.</p>
</div>
)
}}
</PostHogFeature>
)
}Request timeout
You can configure the feature_flag_request_timeout_ms parameter when initializing your PostHog client to set a flag request timeout. This helps prevent your code from being blocked in the case when PostHog's servers are too slow to respond. By default, this is set at 3 seconds.
JavaScript
PostHog AI
posthog.init('<ph_project_token>', {
api_host: 'https://us.i.posthog.com',
defaults: '2026-01-30'
feature_flag_request_timeout_ms: 3000 // Time in milliseconds. Default is 3000 (3 seconds).
}
)Error handling
When using the PostHog SDK, it's important to handle potential errors that may occur during feature flag operations. Here's an example of how to wrap PostHog SDK methods in an error handler:
JavaScript
PostHog AI
function handleFeatureFlag(client, flagKey, distinctId) {
try {
const isEnabled = client.isFeatureEnabled(flagKey, distinctId);
console.log(`Feature flag '${flagKey}' for user '${distinctId}' is ${isEnabled ? 'enabled' : 'disabled'}`);
return isEnabled;
} catch (error) {
console.error(`Error fetching feature flag '${flagKey}': ${error.message}`);
// Optionally, you can return a default value or throw the error
// return false; // Default to disabled
throw error;
}
}
// Usage example
try {
const flagEnabled = handleFeatureFlag(client, 'new-feature', 'user-123');
if (flagEnabled) {
// Implement new feature logic
} else {
// Implement old feature logic
}
} catch (error) {
// Handle the error at a higher level
console.error('Feature flag check failed, using default behavior');
// Implement fallback logic
}Bootstrapping flags
Since there is a delay between initializing PostHog and fetching feature flags, feature flags are not always available immediately. This makes them unusable if you want to do something like redirecting a user to a different page based on a feature flag.
To have your feature flags available immediately, you can initialize PostHog with precomputed values until it has had a chance to fetch them. This is called bootstrapping. After the SDK fetches feature flags from PostHog, it will use those flag values instead of bootstrapped ones.
For details on how to implement bootstrapping, see our bootstrapping guide.
Experiments (A/B tests)
Since experiments use feature flags, the code for running an experiment is very similar to the feature flags code:
React
PostHog AI
// You can either use the `useFeatureFlagVariantKey` hook,
// or you can use the feature flags component - /docs/libraries/react#feature-flags-react-component
// Method one: using the useFeatureFlagVariantKey hook
import { useFeatureFlagVariantKey } from '@posthog/react'
function App() {
const variant = useFeatureFlagVariantKey('experiment-feature-flag-key')
if (variant == 'variant-name') {
// do something
}
}
// Method two: using the feature flags component
import { PostHogFeature } from '@posthog/react'
function App() {
return (
<PostHogFeature flag='experiment-feature-flag-key' match={'variant-name'}>
<!-- the component to show -->
</PostHogFeature>
)
}
// You can also test your code by overriding the feature flag:
// e.g., posthog.featureFlags.overrideFeatureFlags({ flags: {'experiment-feature-flag-key': 'test'}})It's also possible to run experiments without using feature flags.
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-vite · 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-vite.zip