Note: 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.
Note: If you are using the EU cloud then use
eu
instead ofus
in all domains (e.g.us.i.posthog.com
->eu.i.posthog.com
)
To use Cloudflare for reverse proxying, make sure that you're logged into your Cloudflare account, and that you've added your domain (called "website" in Cloudflare) to the account.
There are two ways to do this:
- Using Cloudflare Workers. This is a bit more setup, but can be used on all Cloudflare plans.
- Using DNS and Page Rules. This is simplest method, but requires the Cloudflare Enterprise plan.
Method one: Proxy using Cloudflare Workers
Workers are really powerful and allow up to 100,000 requests per day on the free plan (see Cloudflare pricing). Follow these steps to set up a reverse proxy worker:
1. Create a worker
From the root of the Cloudflare dashboard, go to "Workers & Pages" > "Overview" > "Create application" > "Create Worker". At this point, you can either keep the random worker name or choose your own. Click "Deploy" once done.
2. Configure the worker to act as a proxy
Click "Edit code" once the new worker has been saved following "Deploy". (And if you're already on the worker page, click "Quick edit".) You should now be seeing a code editor for the worker. Just replace all the existing content with this proxying code:
const API_HOST = "us.i.posthog.com" // Change to "eu.i.posthog.com" for the EU regionconst ASSET_HOST = "us-assets.i.posthog.com" // Change to "eu-assets.i.posthog.com" for the EU regionasync function handleRequest(request, ctx) {const url = new URL(request.url)const pathname = url.pathnameconst search = url.searchconst pathWithParams = pathname + searchif (pathname.startsWith("/static/")) {return retrieveStatic(request, pathWithParams, ctx)} else {return forwardRequest(request, pathWithParams)}}async function retrieveStatic(request, pathname, ctx) {let response = await caches.default.match(request)if (!response) {response = await fetch(`https://${ASSET_HOST}${pathname}`)ctx.waitUntil(caches.default.put(request, response.clone()))}return response}async function forwardRequest(request, pathWithSearch) {const originRequest = new Request(request)originRequest.headers.delete("cookie")return await fetch(`https://${API_HOST}${pathWithSearch}`, originRequest)}export default {async fetch(request, env, ctx) {return handleRequest(request, ctx);}};
When done, click "Save and deploy".
3. Use a custom domain for the worker
This step is optional, but highly recommended.
To use your own domain instead of the basic *.workers.dev
one, go to the worker page (by exiting the code editor, if you're still in it) and there click "settings" -> "triggers". Click "Add Custom Domain", type in a subdomain, and save with "Add Custom Domain". The subdomain can be anything, even pineapple.yourdomain.com
– just remember to avoid terms like "tracking" or "analytics", as they may be blanket-blocked.
4. Use the new host in SDKs
You can now use your worker's domain (shown under "Preview" on the worker page) as api_host
in PostHog SDKs! If you've added a custom domain in step 3, use that instead. Make sure to set the ui_host
to your actual PostHog app URL (e.g. us.posthog.com
).
Method two: Proxy using DNS and Page Rules with Cloudflare Enterprise
Proxying traffic using DNS is relatively straight-forward. However, it requires correcting the Host headers for proxied requests, which is only available on the Cloudflare Enterprise plan. If your domain is on this plan, follow these steps:
1. Add a DNS record
Select your website in the Cloudflare dashboard, go to the "DNS" page, and there click "Add record". Make sure this is a CNAME record, and choose a name for it, which will be the PostHog proxy subdomain. The subdomain can be anything, even watermelon.yourdomain.com
– just remember to avoid terms like "tracking" or "analytics", as they may be blanket-blocked. The record should point to us-proxy-direct.i.posthog.com
or eu-proxy-direct.i.posthog.com
(depending on your PostHog region), and have proxy enabled (e.g. CNAME, e, us-proxy-direct.i.posthog.com, proxied
).
2. Correct Host headers
The proxy won't work if the Host headers of requests aren't rewritten from your domain to the PostHog domain. To fix this, add a Page Rules to change the Host header to us-proxy-direct.i.posthog.com
or eu-proxy-direct.i.posthog.com
(depending on your PostHog region).
3. Use the new host in SDKs
You can now use your CNAME record's domain as api_host
in PostHog SDKs! Make sure to set the ui_host
to your actual PostHog app URL (e.g. us.posthog.com
) as well.