In your src/components folder, create a posthog.astro file:
cd ./src/components
# or 'cd ./src && mkdir components && cd ./components' if your components folder doesnt exist
touch posthog.astro
In this file, add your Web snippet which you can find in your project settings. Be sure to include the is:inline directive to prevent Astro from processing it, or you will get Typescript and build errors that property 'posthog' does not exist on type 'Window & typeof globalThis'.
---
// src/components/posthog.astro
---
<script is:inline>
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('<ph_project_api_key>', {
api_host:'https://us.i.posthog.com',
defaults: '2025-11-30'
})
</script>
Using with Astro's view transitions (ClientRouter)
If you've opted in to Astro's <ClientRouter> component for client-side navigation, you'll need to add an initialization guard to prevent PostHog from running multiple times during page transitions.
Update your posthog.astro file to wrap the snippet with a check:
---
// src/components/posthog.astro
---
<script is:inline>
if (!window.__posthog_initialized) {
window.__posthog_initialized = true;
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('<ph_project_api_key>', {
api_host: 'https://us.i.posthog.com',
defaults: '2025-11-30',
capture_pageview: 'history_change'
})
}
</script>
Without this guard, ClientRouter's soft navigation can re-execute the inline script during page transitions, causing a stack overflow error. The capture_pageview: 'history_change' option ensures pageviews are tracked automatically as users navigate.
The next step is to a create a Layout where we will use posthog.astro. Create a new file PostHogLayout.astro in your src/layouts folder:
cd .. && cd .. # move back to your base directory if you're still in src/components/posthog.astro
cd ./src/layouts
# or 'cd ./src && mkdir layouts && cd ./layouts' if your layouts folder doesn't exist yet
touch PostHogLayout.astro
Add the following code to PostHogLayout.astro:
---
import PostHog from '../components/posthog.astro'
---
<head>
<PostHog />
</head>
Lastly, update index.astro to wrap your existing app components with the new Layout:
---
import PostHogLayout from '../layouts/PostHogLayout.astro';
---
<PostHogLayout>
<!-- your existing app components -->
</PostHogLayout>
After installing PostHog and ensuring autocapture is enabled, head to your web analytics dashboard to see your data. And then check out our getting started guide.
PostHog tip: Web analytics works with anonymous events. This means if you are primarily using PostHog for web analytics, it can be significantly cheaper for you.