From 99d3713bc25096288a09c686476d71c0e52a7e0b Mon Sep 17 00:00:00 2001 From: "posthog-eu[bot]" <226701856+posthog-eu[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 13:42:41 +0000 Subject: [PATCH] feat: add PostHog analytics integration Integrate PostHog analytics via the setup wizard. Initialises PostHog through a reusable src/components/posthog.astro inline snippet included in BaseLayout, capturing pageviews and session replays on every page, plus custom events at key interaction points (newsletter signup, activity/story views, CTA clicks). Generated-By: PostHog Code Task-Id: 369d2cea-ed2a-4d9c-bc40-ed1132a3b4e7 --- package.json | 1 + pnpm-lock.yaml | 74 ++++++++++++++++++++++++++ pnpm-workspace.yaml | 1 + src/components/posthog.astro | 10 ++++ src/components/react/Hero.tsx | 35 ++++++++++-- src/components/react/Navbar.tsx | 26 +++++++-- src/components/react/NewsletterCTA.tsx | 17 ++++-- src/layouts/BaseLayout.astro | 3 ++ src/pages/activities/[slug].astro | 32 +++++++++++ src/pages/index.astro | 11 ++++ src/pages/stories/[slug].astro | 11 ++++ 11 files changed, 210 insertions(+), 11 deletions(-) create mode 100644 src/components/posthog.astro diff --git a/package.json b/package.json index 0a0b6fe..12bd3ec 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "motion": "^12.42.2", + "posthog-js": "^1.399.5", "react": "^18.3.1", "react-dom": "^18.3.1", "relume-icons": "^1.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9aef726..bb1db58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: motion: specifier: ^12.42.2 version: 12.42.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + posthog-js: + specifier: ^1.399.5 + version: 1.399.5 react: specifier: ^18.3.1 version: 18.3.1 @@ -712,6 +715,12 @@ packages: '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@posthog/core@1.40.2': + resolution: {integrity: sha512-H12j7O9iHGvpK9t2ko8W4pvfbV1pBDxrsWC1LA6yp2RhzwvC4T3sWhu+AekDQJSRSrJEWlB0t/Ueq9QhPSq7FQ==} + + '@posthog/types@1.393.0': + resolution: {integrity: sha512-vzWeEJZ7ERQhFRoQYaP5jzN1JvIu46UJyHXsuv+dTGW2r3sMgREOhNxXLZjmFHwZ8/FOHQoyqqQmXTCXZSfMSg==} + '@radix-ui/react-compose-refs@1.1.3': resolution: {integrity: sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==} peerDependencies: @@ -956,6 +965,9 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -1132,6 +1144,9 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + core-js@3.49.0: + resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} + crossws@0.3.5: resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} @@ -1218,6 +1233,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.12: + resolution: {integrity: sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -1302,6 +1320,9 @@ packages: picomatch: optional: true + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1851,6 +1872,17 @@ packages: resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.399.5: + resolution: {integrity: sha512-5z7piKHxzZeDhdZ/XtivVHKIFr+09mDPcN3kIIkBS1zHmUTzDhQAR0T3R6NZTLog/8wzhY2jlu16anve1fdMAA==} + + preact@10.29.7: + resolution: {integrity: sha512-DCHYrK/B10yUD3ZjLfhZ3WIE/9Vf9VFUODcRE2dRomTYDpJk6z6L9wecSfhfE6M9ZTHUdyQkoC46arIDhEV84Q==} + peerDependencies: + preact-render-to-string: '>=5' + peerDependenciesMeta: + preact-render-to-string: + optional: true + prettier-plugin-astro@0.14.1: resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==} engines: {node: ^14.15.0 || >=16.0.0} @@ -1871,6 +1903,9 @@ packages: property-information@7.2.0: resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -2306,6 +2341,9 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-vitals@5.3.0: + resolution: {integrity: sha512-q6LWsLatGYZp5VGBIOvbTj6JBV2nOmC8KvWztXBmwJcfFAzhwKwbOxhUH306XY3CcaZDUlSmSuNPBsCn0bFu+g==} + which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -2877,6 +2915,12 @@ snapshots: '@oslojs/encoding@1.1.0': {} + '@posthog/core@1.40.2': + dependencies: + '@posthog/types': 1.393.0 + + '@posthog/types@1.393.0': {} + '@radix-ui/react-compose-refs@1.1.3(@types/react@18.3.31)(react@18.3.1)': dependencies: react: 18.3.1 @@ -3083,6 +3127,9 @@ snapshots: dependencies: '@types/node': 24.13.3 + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@3.0.3': {} '@ungap/structured-clone@1.3.3': {} @@ -3330,6 +3377,8 @@ snapshots: cookie@1.1.1: {} + core-js@3.49.0: {} + crossws@0.3.5: dependencies: uncrypto: 0.1.3 @@ -3407,6 +3456,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.12: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -3531,6 +3584,8 @@ snapshots: optionalDependencies: picomatch: 4.0.5 + fflate@0.4.8: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -4246,6 +4301,21 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.399.5: + dependencies: + '@posthog/core': 1.40.2 + '@posthog/types': 1.393.0 + core-js: 3.49.0 + dompurify: 3.4.12 + fflate: 0.4.8 + preact: 10.29.7 + query-selector-shadow-dom: 1.0.1 + web-vitals: 5.3.0 + transitivePeerDependencies: + - preact-render-to-string + + preact@10.29.7: {} + prettier-plugin-astro@0.14.1: dependencies: '@astrojs/compiler': 2.13.1 @@ -4263,6 +4333,8 @@ snapshots: property-information@7.2.0: {} + query-selector-shadow-dom@1.0.1: {} + queue-microtask@1.2.3: {} radix3@1.1.2: {} @@ -4762,6 +4834,8 @@ snapshots: web-namespaces@2.0.1: {} + web-vitals@5.3.0: {} + which-pm-runs@1.1.0: {} widest-line@5.0.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d2d21a9..0fe89c7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,5 @@ allowBuilds: + core-js: false esbuild: true sharp: true onlyBuiltDependencies: diff --git a/src/components/posthog.astro b/src/components/posthog.astro new file mode 100644 index 0000000..0cdb79c --- /dev/null +++ b/src/components/posthog.astro @@ -0,0 +1,10 @@ +--- +// PostHog analytics snippet — is:inline prevents Astro/TS from processing window.posthog +--- + diff --git a/src/components/react/Hero.tsx b/src/components/react/Hero.tsx index 92d3000..01e4548 100644 --- a/src/components/react/Hero.tsx +++ b/src/components/react/Hero.tsx @@ -49,25 +49,52 @@ export function Hero({ tagline, mission, cta, secondaryCta, image }: Props) { > {tagline} - + {mission} {cta && ( )} {secondaryCta && ( )} > = { - logo: { src: "/logo/okbe-withname.svg", alt: "Open Knowledge Belgium", url: "/" }, + logo: { + src: "/logo/okbe-withname.svg", + alt: "Open Knowledge Belgium", + url: "/", + }, navLinks: [ { title: "About", url: "/about" }, { title: "Activities", url: "/activities" }, @@ -50,7 +54,11 @@ export function Navbar(props: Props) { } >
- + {logo.alt} @@ -75,7 +83,12 @@ export function Navbar(props: Props) {
@@ -122,7 +135,12 @@ export function Navbar(props: Props) { ))} diff --git a/src/components/react/NewsletterCTA.tsx b/src/components/react/NewsletterCTA.tsx index 2f97c41..09e4dea 100644 --- a/src/components/react/NewsletterCTA.tsx +++ b/src/components/react/NewsletterCTA.tsx @@ -26,6 +26,7 @@ export function NewsletterCTA({ const [done, setDone] = useState(false); const onSubmit = (e: React.FormEvent) => { + window.posthog?.capture("newsletter_subscribed"); if (action) return; // let the real endpoint handle it e.preventDefault(); if (!email) return; @@ -52,7 +53,11 @@ export function NewsletterCTA({

{heading}

- {subheading &&

{subheading}

} + {subheading && ( +

+ {subheading} +

+ )}
setEmail(e.target.value)} className="border-white/20 bg-white/95" /> -
{done ? ( -

Thanks! Check your email client to confirm.

+

+ Thanks! Check your email client to confirm. +

) : (

No spam — just occasional updates on open knowledge in Belgium. diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index c7d8768..b7126bb 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -1,5 +1,6 @@ --- import "@/styles/global.css"; +import PostHog from "@/components/posthog.astro"; interface Props { title?: string; @@ -43,6 +44,8 @@ const canonical = new URL(Astro.url.pathname, Astro.site).toString(); + +

+ + diff --git a/src/pages/index.astro b/src/pages/index.astro index 9f42f0f..1fb64a6 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -161,3 +161,14 @@ const values = [ contactEmail={site.email} /> + + diff --git a/src/pages/stories/[slug].astro b/src/pages/stories/[slug].astro index 11b89a6..a1edfd9 100644 --- a/src/pages/stories/[slug].astro +++ b/src/pages/stories/[slug].astro @@ -56,3 +56,14 @@ const d = story.data; + +