PostHog SDK
Configure a reverse proxy to send posthog-js browser capture traffic to a Sazabi endpoint instead of PostHog.
All PostHog integration capabilities
About
Forward browser posthog-js capture traffic — analytics events, identify calls, and session replay snapshots — into Sazabi by routing SDK traffic through a reverse proxy you control. The proxy sends browser capture traffic (the /e/, /i/, and /s/ paths) to Sazabi instead of PostHog, and still sends PostHog's config, feature-flag, and asset traffic to PostHog. Sazabi does not forward capture traffic on to PostHog.
With this setup, PostHog stops receiving analytics events, identify calls, and session replays from this app. To keep PostHog receiving events and also send them to Sazabi, use the PostHog source instead. PostHog's Data Pipeline (a paid PostHog feature) forwards events, not session replays, to Sazabi.
This source captures only what posthog-js sends from the browser. It does
not cover server-side PostHog events — use the PostHog CDP webhook source for
those.
Session replay is controlled by your PostHog project settings, not a posthog.init option.
Prerequisites
- A
posthog-jsbrowser application. - A reverse proxy you control (for example a Next.js rewrite, Nginx, or Cloudflare Worker) that can split PostHog SDK routes by path.
- Your Sazabi intake URL (shown above).
Set up in the dashboard
Plan the reverse proxy
Configure posthog-js to use a reverse proxy path as api_host. Send capture paths (/e/, /i/, /s/) to Sazabi, and send PostHog config, flags, and assets to PostHog.
Use your Sazabi intake URL (shown above) as the upstream destination for capture-path proxy rules.
Initialize posthog-js
Point posthog-js at your reverse proxy path:
JavaScript
import posthog from "posthog-js";
posthog.init("<your phc_* project token>", {
api_host: "/ingest",
ui_host: "https://us.posthog.com",
});Next.js
"use client";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
if (typeof window !== "undefined") {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: "/ingest",
ui_host: "https://us.posthog.com",
});
}
export function Providers({ children }: { children: React.ReactNode }) {
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
}Configure rewrites
Route capture paths to Sazabi and all other PostHog paths back to PostHog. Capture traffic that reaches Sazabi does not reach PostHog. For Next.js:
On Next.js, set skipTrailingSlashRedirect: true. Otherwise Next.js sends a
308 redirect on the trailing-slash capture paths (/e/, /i/v0/e/, /s/),
which stops them from matching the Sazabi rule.
// next.config.ts
import type { NextConfig } from "next";
const config: NextConfig = {
// posthog-js posts to trailing-slash capture paths (/e/, /i/v0/e/, /s/). Without
// this, Next.js 308-redirects them to the slash-less path, which no longer matches
// the capture rule below and falls through to PostHog.
skipTrailingSlashRedirect: true,
async rewrites() {
return [
{
source: "/ingest/:path((?:e|i|s)/.*)",
destination: "https://your-intake-host/:path*",
},
{
source: "/ingest/:path*",
destination: "https://us.i.posthog.com/:path*",
},
];
},
};
export default config;Replace your-intake-host with the hostname portion of your intake URL (shown above, without https://).
Hand off the change
Commit these changes on a new branch, push it, and open a pull request. Keep the intake URL and any keys in environment variables or a secret store, and commit only configuration that references them.
Set up with the CLI
You can also register the PostHog SDK log source with the Sazabi CLI (installed and authenticated — see CLI reference).
Registering the source mints the same intake URL the dashboard shows above (the public key is embedded in its hostname):
sazabi log-sources create posthog_sdk --mode manualThe command prints the intake URL for the new source — copy the whole URL and point your sender at it using the configuration shown above. Run sazabi log-sources get <log-source-id> at any time to reprint the endpoint, or sazabi log-sources list to see every log source in the project.
Verify
Load your application and generate a browser event (for example a page view or a button click). Open the Intake page in the Sazabi dashboard and confirm records from the PostHog SDK source appear. Records typically arrive within a minute or two.
Troubleshooting
No records appear — Confirm the rewrite routes for /e/, /i/, and /s/ paths resolve to your Sazabi intake hostname. Check the browser network tab for the capture request and verify it returns a 2xx from Sazabi.
Session replay snapshots not forwarding — Session replay uses the /s/ path. Confirm your proxy rule covers /s/.* and is not blocked by a more general PostHog passthrough rule that precedes the Sazabi capture rule.
Next.js 308 redirect loop — Without skipTrailingSlashRedirect: true, Next.js redirects trailing-slash paths before the rewrite runs. The redirect destination (/e without the slash) no longer matches the capture rule and falls through to PostHog instead of Sazabi.
Events or session replays missing in PostHog — This is expected with this setup. Capture paths (/e/, /i/, /s/) go to Sazabi instead of PostHog. To keep PostHog receiving events, use the PostHog source instead.