History

Add PostHog analytics to marketing site

Mirrors the cloud app's setup: client init in Layout.astro behind PUBLIC_POSTHOG_KEY, plus an Astro middleware that reverse-proxies /api/${PUBLIC_ANALYTICS_PATH} to us.i.posthog.com and us-assets.i.posthog.com so events flow past adblockers.

Rhys Sullivan committed 6 months ago

Commit 40353be1 parent 63cdca34 files · +50 −0Browse files

Unified · Split

4 files
  1. apps/marketing/package.json +1 −0
  2. apps/marketing/src/layouts/Layout.astro +16 −0
  3. apps/marketing/src/middleware.ts +32 −0
  4. bun.lock +1 −0
apps/marketing/package.json+1−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
22 "@tailwindcss/vite": "^4.2.2",22 "@tailwindcss/vite": "^4.2.2",
23 "astro": "^6.1.3",23 "astro": "^6.1.3",
24 "effect": "catalog:",24 "effect": "catalog:",
25 "posthog-js": "^1.372.5",
25 "tailwindcss": "^4.2.2"26 "tailwindcss": "^4.2.2"
26 },27 },
27 "devDependencies": {28 "devDependencies": {
apps/marketing/src/layouts/Layout.astro+16−0
@@ -32,6 +32,22 @@ const { · 31 unmodified lines
32 <body class="bg-surface text-ink antialiased selection:bg-teal/20 selection:text-teal">32 <body class="bg-surface text-ink antialiased selection:bg-teal/20 selection:text-teal">
33 <slot />33 <slot />
34 34
35 <script>
36 import posthog from 'posthog-js'
37
38 const key = import.meta.env.PUBLIC_POSTHOG_KEY
39 if (key) {
40 const analyticsPath = (import.meta.env.PUBLIC_ANALYTICS_PATH ?? 'a').replace(/^\/+|\/+$/g, '')
41 posthog.init(key, {
42 api_host:
43 import.meta.env.PUBLIC_POSTHOG_HOST ?? `${window.location.origin}/api/${analyticsPath}`,
44 ui_host: 'https://us.posthog.com',
45 defaults: '2025-05-24',
46 person_profiles: 'identified_only',
47 })
48 }
49 </script>
50
35 <script>51 <script>
36 // Scroll-triggered reveals52 // Scroll-triggered reveals
37 const observer = new IntersectionObserver(53 const observer = new IntersectionObserver(
apps/marketing/src/middleware.ts+32−0
@@ -0,0 +1,32 @@
1import { defineMiddleware } from "astro:middleware";
2
3// PostHog reverse proxy — the browser SDK targets a build-randomized
4// first-party path and we forward to PostHog's ingest + asset hosts. Keeps
5// events flowing past adblockers that match *.posthog.com. See
6// https://posthog.com/docs/advanced/proxy/cloudflare
7
8const POSTHOG_INGEST_HOST = "us.i.posthog.com";
9const POSTHOG_ASSETS_HOST = "us-assets.i.posthog.com";
10const POSTHOG_PROXY_PATH = `/api/${(import.meta.env.PUBLIC_ANALYTICS_PATH ?? "a").replace(
11 /^\/+|\/+$/g,
12 "",
13)}`;
14
15export const onRequest = defineMiddleware(async (context, next) => {
16 const { pathname } = new URL(context.request.url);
17 if (pathname !== POSTHOG_PROXY_PATH && !pathname.startsWith(`${POSTHOG_PROXY_PATH}/`)) {
18 return next();
19 }
20
21 const url = new URL(context.request.url);
22 url.hostname = pathname.startsWith(`${POSTHOG_PROXY_PATH}/static/`)
23 ? POSTHOG_ASSETS_HOST
24 : POSTHOG_INGEST_HOST;
25 url.protocol = "https:";
26 url.port = "";
27 url.pathname = pathname.slice(POSTHOG_PROXY_PATH.length) || "/";
28
29 const upstream = new Request(url, context.request);
30 upstream.headers.delete("cookie");
31 return fetch(upstream);
32});
bun.lock+1−0
@@ -185,6 +185,7 @@ · 184 unmodified lines
185 "@tailwindcss/vite": "^4.2.2",185 "@tailwindcss/vite": "^4.2.2",
186 "astro": "^6.1.3",186 "astro": "^6.1.3",
187 "effect": "catalog:",187 "effect": "catalog:",
188 "posthog-js": "^1.372.5",
188 "tailwindcss": "^4.2.2",189 "tailwindcss": "^4.2.2",
189 },190 },
190 "devDependencies": {191 "devDependencies": {