PostHog makes it easy to get data about traffic and usage of your Remix 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 integrating PostHog into your Remix app using the JavaScript Web SDK.
Installation
Install posthog-js
using your package manager:
yarn add posthog-js# ornpm install --save posthog-js
First, you'll need to pass both your project API key and instance address from your project settings to your client through Remix. We recommend placing the project API key on window.ENV
like Remix recommends in this guide.
import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData } from "@remix-run/react";import type { LinksFunction } from "@remix-run/node";import { json } from "@remix-run/node";//... other imports, links, etc.export const loader = () => {return json({ENV: {POSTHOG_API_KEY: process.env.POSTHOG_API_KEY,},});};export default function App() {const { ENV } = useLoaderData<typeof loader>();return (<html lang="en"><head><Meta /><Links /></head><body><Outlet /><ScrollRestoration /><scriptdangerouslySetInnerHTML={{__html: `window.ENV = ${JSON.stringify(ENV)}`,}}/><Scripts /></body></html>);}
Next, create a new PostHog context in app/contexts/posthog-context.tsx
. This is necessary because of a missing export statement in posthog-js
's package.json
.
import posthog from "posthog-js";import React, { createContext, useContext, useRef } from "react";type PosthogType = typeof posthog | undefined;const PosthogContext = createContext<PosthogType>(undefined);interface PosthogProviderProps {children: React.ReactNode;}export function PosthogProvider({ children }: PosthogProviderProps) {const posthogInstanceRef = useRef<PosthogType>(undefined);// https://react.dev/reference/react/useRef#avoiding-recreating-the-ref-contents// Note that in StrictMode, this will run twice.function getPosthogInstance() {if (posthogInstanceRef.current) return posthogInstanceRef.current;if (!window.ENV.POSTHOG_API_KEY) return undefined;posthogInstanceRef.current = posthog.init(window.ENV.POSTHOG_API_KEY, {api_host: 'https://us.i.posthog.com',person_profiles: 'identified_only'});return posthogInstanceRef.current;}return (<PosthogContext.Provider value={getPosthogInstance()}>{children}</PosthogContext.Provider>);}export const usePosthog = () => useContext(PosthogContext);
Lastly, we need to add this context to your React tree. Go to app/entry.client.tsx
and add the following:
import { RemixBrowser } from "@remix-run/react";import { startTransition, StrictMode, useEffect } from "react";import { hydrateRoot } from "react-dom/client";import { PosthogProvider } from "./contexts/posthog-context";startTransition(() => {hydrateRoot(document,<StrictMode><PosthogProvider><RemixBrowser /></PosthogProvider></StrictMode>,);});
Identifying Users
To identify users call posthog?.identify()
when you have a distinct ID.
import { usePosthog } from "./contexts/posthog-context";function SomeAuthedComponent() {const posthog = usePosthog();useEffect(() => {posthog?.identify(user.distinctId);}, [posthog, user.distinctId]);// ...}
Setting up Pageviews
Because Remix is a single-page app that uses client-side routing, we need to track pageviews whenever the page location changes. In app/root.tsx
:
export default function App() {const location = useLocation();const posthog = usePosthog();useEffect(() => {posthog?.capture('$pageview');}, [posthog, location]);return (<html lang="en">//... rest of code
Next steps
For any technical questions for how to integrate specific PostHog features into Remix (such as analytics, feature flags, A/B testing, surveys, etc.), have a look at our JavaScript Web SDK docs.
Alternatively, the following tutorials can help you get started: