From 91bba81a4b5e91017a5573e4cb96132bd031d313 Mon Sep 17 00:00:00 2001 From: Michael Sydney Moore Date: Fri, 11 Sep 2026 15:57:42 +0100 Subject: [PATCH] Let PostHog see that ingestion is proxied When `api_host` is a custom origin, posthog-js tags every event with `$lib_custom_api_host`, and that property is how the installation health check recognises a reverse proxy. The sanitizer's allowlist dropped it, so the check stayed red even though `/e30` was carrying all the traffic correctly. The value is the site's own public origin, so there is nothing sensitive in letting it through. --- src/analytics.js | 3 +++ test/analytics.test.mjs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/analytics.js b/src/analytics.js index f4da148..6663c9d 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -27,6 +27,9 @@ export function sanitizePosthogEvent(event) { '$lib','$lib_version','$browser','$browser_version','$os','$os_version','$device_type', '$screen_height','$screen_width','$viewport_height','$viewport_width','$timezone', '$host','$pathname','$title','$is_identified','$process_person_profile','page_path','page_title', + // How PostHog recognises that ingestion is proxied. It holds our own + // public origin, and without it the reverse proxy check never passes. + '$lib_custom_api_host', 'concept','placement','destination',...campaignKeys, ...webVitalsMetrics.map(name => `$web_vitals_${name}_value`)]); const properties = Object.fromEntries(Object.entries(event.properties || {}).filter(([key,value]) => keep.has(key) && ['string','number','boolean'].includes(typeof value))); diff --git a/test/analytics.test.mjs b/test/analytics.test.mjs index 49dbd0d..192e368 100644 --- a/test/analytics.test.mjs +++ b/test/analytics.test.mjs @@ -77,6 +77,8 @@ test('PostHog loads and ingests through the same origin so blockers cannot drop const options = h.win.posthog._i[0][1]; assert.equal(options.api_host,'https://www.javascriptin30words.com/e30'); assert.equal(options.ui_host,'https://eu.posthog.com','Links into PostHog still point at the real app'); + assert.ok(sanitizePosthogEvent({event:'$pageview',properties:{$lib_custom_api_host:'https://www.javascriptin30words.com/e30'}}).properties.$lib_custom_api_host, + 'PostHog detects the proxy from this property, so it has to survive sanitizing'); const loader = h.scripts.map(element=>element.src).find(src=>src.includes('/e30/')); assert.equal(loader,'https://www.javascriptin30words.com/e30/static/array.js'); assert.ok(!h.scripts.some(element=>element.src.includes('posthog.com')),'No request reveals the vendor hostname');