Install or Embed PostHog Tag or SDK | OpsBlu Docs

Install or Embed PostHog Tag or SDK

Step-by-step installation guide for PostHog across web, mobile, and server platforms

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:

  1. In Xcode: File → Add Packages
  2. Enter: https://github.com/PostHog/posthog-ios
  3. 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 posthog or 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 $pageview or 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.