Using SvelteKit server hooks as a reverse proxy

Last updated:

|Edit this page|
Warning
  1. The following self-hosted proxy isn't provided by PostHog, so we can't take responsibility for it! If unsure, we recommend using our managed reverse proxy.

  2. If you are using the EU cloud then use eu instead of us in all domains (e.g. us.i.posthog.com -> eu.i.posthog.com).

  3. Avoid using generic or common path names like /analytics, /tracking, /ingest, or /posthog for your reverse proxy. They will most likely be blocked. Instead, use a non-obvious path name or something random and unique to your application that's unlikely to appear in a filter list.

For SvelteKit, you can use server hooks to proxy requests to PostHog. We've tested this (and it works) with Cloudflare Workers.

To do this, create a file named hooks.server.ts in your src directory (or the dir you configured to contain source files). In this file, set up code to match requests to a custom route, set a new host header, change the URL to point to PostHog, and rewrite the response.

Note: This only works in SSR mode. If your site is statically generated, SvelteKit ignores hooks.server.ts.

TypeScript
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const { pathname } = event.url;
if (pathname.startsWith('/<ph_proxy_path>')) {
// Determine target hostname based on static or dynamic ingestion
const hostname = pathname.startsWith('/<ph_proxy_path>/static/')
? 'us-assets.i.posthog.com' // change us to eu for EU Cloud
: 'us.i.posthog.com'; // change us to eu for EU Cloud
// Build external URL
const url = new URL(event.request.url);
url.protocol = 'https:';
url.hostname = hostname;
url.port = '443';
url.pathname = pathname.replace('/<ph_proxy_path>/', '');
// Clone and adjust headers
const headers = new Headers(event.request.headers);
headers.set('host', hostname);
// Proxy the request to the external host
const response = await fetch(url.toString(), {
method: event.request.method,
headers,
body: event.request.body
});
return response;
}
const response = await resolve(event);
return response;
};

Once done, configure the PostHog client to send requests via your rewrite like we do in this sample:

TypeScript
// src/routes/+layout.ts
import posthog from 'posthog-js';
import { browser } from '$app/environment';
import { PUBLIC_POSTHOG_KEY as POSTHOG_KEY } from '$env/static/public';
export function initTelemetry() {
if (!browser) return;
posthog.init(POSTHOG_KEY, {
api_host: '/<ph_proxy_path>',
ui_host: 'https://us.posthog.com', // change us to eu for EU Cloud
person_profiles: 'always',
persistence: 'localStorage'
});
}
initTelemetry();

Questions? Ask Max AI.

It's easier than reading through 638 pages of documentation

Community questions

Was this page useful?

Next article

Using Vercel rewrites as a reverse proxy

Vercel supports rewrites which we can use as a reverse proxy. Create a vercel.json file and add a rewrites object from a custom route. Some frameworks, like SvelteKit and Astro , require a hungrier regex pattern like: Note: Some frameworks, like T3 app, don't support Vercel rewrites well. If neither of these options work, we recommend trying another proxy method. Once done, set the /<ph_proxy_path> route of your domain as the API host in your PostHog initialization like this: Once…

Read next article