Overview
PostHog offers multiple installation methods tailored to different platforms and frameworks. Whether you're building a React app, iOS native app, Python backend, or vanilla JavaScript website, PostHog has an SDK that fits your stack.
The installation process is straightforward: install the package, initialize with your API key, and start tracking. Most setups take less than 10 minutes.
Web Installation
JavaScript (CDN Snippet)
The fastest way to add PostHog to any website. No build tools required.
Installation:
<script>
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com'
});
</script>
Place this code:
- In
<head>for earliest load (recommended) - Before
</body>for non-blocking load
Configuration:
<script>
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com', // or https://eu.posthog.com for EU
autocapture: true,
capture_pageview: true,
capture_pageleave: true,
session_recording: {
enabled: true,
maskAllInputs: true
}
});
</script>
JavaScript (NPM/Yarn)
For modern web apps using build tools.
Installation:
npm install posthog-js
# or
yarn add posthog-js
Usage:
import posthog from 'posthog-js';
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com',
autocapture: true
});
// Track events
posthog.capture('button_clicked', {
button_name: 'signup_cta'
});
React
Installation:
npm install posthog-js
Setup (with hooks):
// src/posthog.js
import posthog from 'posthog-js';
if (typeof window !== 'undefined') {
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com',
loaded: (posthog) => {
if (process.env.NODE_ENV === 'development') posthog.debug();
}
});
}
export default posthog;
App.js:
import { PostHogProvider } from 'posthog-js/react';
import posthog from './posthog';
function App() {
return (
<PostHogProvider client={posthog}>
<YourApp />
</PostHogProvider>
);
}
Using hooks:
import { usePostHog } from 'posthog-js/react';
function MyComponent() {
const posthog = usePostHog();
const handleClick = () => {
posthog.capture('button_clicked');
};
return <button Me</button>;
}
Next.js
Installation:
npm install posthog-js
Setup (App Router - Next.js 13+):
// app/providers.js
'use client';
import posthog from 'posthog-js';
import { PostHogProvider } from 'posthog-js/react';
import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
export function PHProvider({ children }) {
useEffect(() => {
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com',
capture_pageview: false // We'll capture manually
});
}, []);
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
}
// Track pageviews
export function PostHogPageView() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
if (pathname) {
let url = window.origin + pathname;
if (searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}
posthog.capture('$pageview', { $current_url: url });
}
}, [pathname, searchParams]);
return null;
}
app/layout.js:
import { PHProvider, PostHogPageView } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<PHProvider>
<PostHogPageView />
{children}
</PHProvider>
</body>
</html>
);
}
Setup (Pages Router - Next.js 12):
// pages/_app.js
import posthog from 'posthog-js';
import { PostHogProvider } from 'posthog-js/react';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
if (typeof window !== 'undefined') {
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com',
loaded: (posthog) => {
if (process.env.NODE_ENV === 'development') posthog.debug();
}
});
}
export default function App({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
const handleRouteChange = () => posthog.capture('$pageview');
router.events.on('routeChangeComplete', handleRouteChange);
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, []);
return (
<PostHogProvider client={posthog}>
<Component {...pageProps} />
</PostHogProvider>
);
}
Vue.js
Installation:
npm install posthog-js
Setup (Vue 3):
// main.js
import { createApp } from 'vue';
import posthog from 'posthog-js';
import App from './App.vue';
const app = createApp(App);
app.config.globalProperties.$posthog = posthog.init(
'YOUR_PROJECT_API_KEY',
{
api_host: 'https://app.posthog.com'
}
);
app.mount('#app');
Usage in components:
<script>
export default {
methods: {
trackEvent() {
this.$posthog.capture('button_clicked');
}
}
}
</script>
Setup (Vue 2):
// main.js
import Vue from 'vue';
import posthog from 'posthog-js';
Vue.prototype.$posthog = posthog.init(
'YOUR_PROJECT_API_KEY',
{
api_host: 'https://app.posthog.com'
}
);
Angular
Installation:
npm install posthog-js
app.module.ts:
import { APP_INITIALIZER, NgModule } from '@angular/core';
import posthog from 'posthog-js';
export function initPostHog() {
return () => {
posthog.init('YOUR_PROJECT_API_KEY', {
api_host: 'https://app.posthog.com'
});
};
}
@NgModule({
providers: [
{
provide: APP_INITIALIZER,
useFactory: initPostHog,
multi: true
}
]
})
export class AppModule {}
Usage in components:
import posthog from 'posthog-js';
export class MyComponent {
trackEvent() {
posthog.capture('button_clicked');
}
}
Mobile Installation
iOS (Swift)
Installation (CocoaPods):
# Podfile
pod 'PostHog', '~> 3.0'
pod install
Setup:
// AppDelegate.swift
import PostHog
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = PostHogConfig(apiKey: "YOUR_PROJECT_API_KEY")
config.host = "https://app.posthog.com"
config.captureApplicationLifecycleEvents = true
config.captureScreenViews = true
PostHogSDK.shared.setup(config)
return true
}
Track events:
PostHogSDK.shared.capture("button_clicked", properties: [
"button_name": "signup_cta"
])
Identify users:
PostHogSDK.shared.identify("user_123", properties: [
"email": "user@example.com",
"name": "Jane Doe"
])
iOS (Swift Package Manager)
Installation:
- In Xcode: File → Add Packages
- Enter:
https://github.com/PostHog/posthog-ios - Select version and add
Setup: Same as CocoaPods
Android (Kotlin)
Installation (Gradle):
// build.gradle (app level)
dependencies {
implementation 'com.posthog:posthog-android:3.+'
}
Setup:
// Application.kt or MainActivity.kt
import com.posthog.PostHog
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
PostHog.setup(
context = this,
apiKey = "YOUR_PROJECT_API_KEY",
host = "https://app.posthog.com"
).also {
it.captureApplicationLifecycleEvents()
it.captureScreenViews()
}
}
}
AndroidManifest.xml:
<application
android:name=".MainApplication"
...>
</application>
Track events:
PostHog.capture("button_clicked", properties = mapOf(
"button_name" to "signup_cta"
))
Identify users:
PostHog.identify("user_123", properties = mapOf(
"email" to "user@example.com",
"name" to "Jane Doe"
))
React Native
Installation:
npm install posthog-react-native
# or
yarn add posthog-react-native
For iOS:
cd ios && pod install
Setup:
// App.js
import PostHog from 'posthog-react-native';
const posthog = new PostHog(
'YOUR_PROJECT_API_KEY',
{
host: 'https://app.posthog.com'
}
);
export default function App() {
// Track events
const handlePress = () => {
posthog.capture('button_clicked', {
button_name: 'signup_cta'
});
};
return <Button title="Click Me" />;
}
Flutter
Installation:
# pubspec.yaml
dependencies:
posthog_flutter: ^3.0.0
flutter pub get
Setup:
// main.dart
import 'package:posthog_flutter/posthog_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Posthog().setup(
apiKey: 'YOUR_PROJECT_API_KEY',
host: 'https://app.posthog.com',
captureApplicationLifecycleEvents: true,
);
runApp(MyApp());
}
Track events:
Posthog().capture(
eventName: 'button_clicked',
properties: {
'button_name': 'signup_cta'
}
);
Server-Side Installation
Node.js
Installation:
npm install posthog-node
Usage:
const { PostHog } = require('posthog-node');
const posthog = new PostHog(
'YOUR_PROJECT_API_KEY',
{ host: 'https://app.posthog.com' }
);
// Track event
posthog.capture({
distinctId: 'user_123',
event: 'subscription_created',
properties: {
plan: 'Pro',
price: 29.99
}
});
// Identify user
posthog.identify({
distinctId: 'user_123',
properties: {
email: 'user@example.com',
plan: 'Pro'
}
});
// Shutdown on exit (flushes events)
await posthog.shutdown();
Python
Installation:
pip install posthog
Usage:
from posthog import Posthog
posthog = Posthog(
'YOUR_PROJECT_API_KEY',
host='https://app.posthog.com'
)
# Track event
posthog.capture(
distinct_id='user_123',
event='subscription_created',
properties={
'plan': 'Pro',
'price': 29.99
}
)
# Identify user
posthog.identify(
distinct_id='user_123',
properties={
'email': 'user@example.com',
'plan': 'Pro'
}
)
# Shutdown (flushes events)
posthog.shutdown()
Ruby
Installation:
gem install posthog-ruby
Usage:
require 'posthog-ruby'
posthog = PostHog::Client.new({
api_key: 'YOUR_PROJECT_API_KEY',
host: 'https://app.posthog.com'
})
# Track event
posthog.capture({
distinct_id: 'user_123',
event: 'subscription_created',
properties: {
plan: 'Pro',
price: 29.99
}
})
# Identify user
posthog.identify({
distinct_id: 'user_123',
properties: {
email: 'user@example.com',
plan: 'Pro'
}
})
PHP
Installation:
composer require posthog/posthog-php
Usage:
<?php
require 'vendor/autoload.php';
use PostHog\PostHog;
PostHog::init(
'YOUR_PROJECT_API_KEY',
['host' => 'https://app.posthog.com']
);
// Track event
PostHog::capture([
'distinctId' => 'user_123',
'event' => 'subscription_created',
'properties' => [
'plan' => 'Pro',
'price' => 29.99
]
]);
// Identify user
PostHog::identify([
'distinctId' => 'user_123',
'properties' => [
'email' => 'user@example.com',
'plan' => 'Pro'
]
]);
// Flush events
PostHog::flush();
Go
Installation:
go get github.com/posthog/posthog-go
Usage:
package main
import (
"github.com/posthog/posthog-go"
)
func main() {
client, _ := posthog.NewWithConfig(
"YOUR_PROJECT_API_KEY",
posthog.Config{
Endpoint: "https://app.posthog.com",
},
)
defer client.Close()
// Track event
client.Enqueue(posthog.Capture{
DistinctId: "user_123",
Event: "subscription_created",
Properties: posthog.NewProperties().
Set("plan", "Pro").
Set("price", 29.99),
})
// Identify user
client.Enqueue(posthog.Identify{
DistinctId: "user_123",
Properties: posthog.NewProperties().
Set("email", "user@example.com").
Set("plan", "Pro"),
})
}
Java
Installation (Maven):
<dependency>
<groupId>com.posthog.java</groupId>
<artifactId>posthog</artifactId>
<version>3.0.0</version>
</dependency>
Usage:
import com.posthog.java.PostHog;
public class MyApp {
public static void main(String[] args) {
PostHog posthog = new PostHog.Builder("YOUR_PROJECT_API_KEY")
.host("https://app.posthog.com")
.build();
// Track event
posthog.capture("user_123", "subscription_created",
Map.of(
"plan", "Pro",
"price", 29.99
)
);
// Identify user
posthog.identify("user_123",
Map.of(
"email", "user@example.com",
"plan", "Pro"
)
);
posthog.shutdown();
}
}
Reverse Proxy Setup (Bypass Ad Blockers)
Ad blockers often block PostHog. Use a reverse proxy to route requests through your own domain.
Nginx
location /posthog/ {
proxy_pass https://app.posthog.com/;
proxy_set_header Host app.posthog.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Update SDK:
posthog.init('YOUR_API_KEY', {
api_host: 'https://yourdomain.com/posthog',
ui_host: 'https://app.posthog.com'
});
Cloudflare Workers
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
if (url.pathname.startsWith('/posthog/')) {
const posthogUrl = 'https://app.posthog.com' + url.pathname.replace('/posthog', '');
return fetch(posthogUrl, request);
}
return fetch(request);
}
Verification
After installation, verify PostHog is working:
1. Check browser console:
posthog.debug = true; // Enable debug mode
You should see:
[PostHog] Event captured: $pageview
[PostHog] Sending batch of 1 events
2. Check network tab:
- Filter for
posthogor your domain - Look for POST requests to
/e/or/batch/ - Response should be
{"status": 1}
3. Check PostHog dashboard:
- Go to Activity
- Events should appear within 30 seconds
- Check for
$pageviewor your first custom event
4. Test user identification:
posthog.identify('test_user_123');
console.log(posthog.get_distinct_id()); // Should show 'test_user_123'
Need help? Check the troubleshooting guide or visit PostHog documentation.