Analytics
Analytics is one config block in src/config/site.ts. Set the provider, paste your ID, save. The theme injects the right snippet into <head> at build time — nothing to install, nothing to import.
The shape
Section titled “The shape”analytics: { provider: null as "google" | "plausible" | "umami" | null, // googleId: "G-XXXXXXXXXX", // plausibleDomain: "example.com", // umamiWebsiteId: "your-id", // umamiScriptUrl: "https://analytics.example.com/script.js",}Set provider to one of the four values, then fill in the matching ID below.
Provider setup
Section titled “Provider setup”Google Analytics 4
Section titled “Google Analytics 4”- Create a GA4 property at analytics.google.com.
- Copy the measurement ID — it starts with
G-. - Set:
analytics: { provider: "google", googleId: "G-ABC123DEF4",}What gets injected:
<script async src="https://www.googletagmanager.com/gtag/js?id=G-ABC123DEF4"></script><script> window.dataLayer = window.dataLayer || []; function gtag(){ dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'G-ABC123DEF4');</script>Plausible
Section titled “Plausible”Privacy-friendly, cookie-free, lightweight (~1 KB).
- Add your site at plausible.io (or your self-hosted instance).
- Set:
analytics: { provider: "plausible", plausibleDomain: "yourdomain.com",}What gets injected:
<script defer data-domain="yourdomain.com" src="https://plausible.io/js/script.js"></script>Open-source, privacy-friendly, self-hostable.
- Get your website ID and script URL from your Umami dashboard.
- Set:
analytics: { provider: "umami", umamiWebsiteId: "abc-123-def-456", umamiScriptUrl: "https://cloud.umami.is/script.js", // or your self-hosted: "https://analytics.yourdomain.com/script.js"}umamiScriptUrl is optional — if you skip it, it defaults to https://cloud.umami.is/script.js.
What gets injected:
<script defer src="https://cloud.umami.is/script.js" data-website-id="abc-123-def-456"></script>No analytics
Section titled “No analytics”analytics: { provider: null }Nothing gets injected. Useful during development.
How it works
Section titled “How it works”Open src/layouts/Layout.astro and search for getAnalyticsScript. It’s a function that reads siteConfig.analytics, returns the right HTML string, and the layout injects it inside <head> via <Fragment set:html={...}>. No client-side branching, no waterfall — pure SSG.
function getAnalyticsScript() { const { provider } = siteConfig.analytics; if (!provider) return ""; const a = siteConfig.analytics;
if (provider === "google" && a.googleId) { /* … */ } if (provider === "plausible" && a.plausibleDomain) { /* … */ } if (provider === "umami" && a.umamiWebsiteId) { /* … */ } return "";}Adding a custom provider
Section titled “Adding a custom provider”If you want Fathom, Mixpanel, PostHog, or something else, edit the same function in Layout.astro:
if (provider === "fathom" && a.fathomSiteId) { return `<script src="https://cdn.usefathom.com/script.js" data-site="${a.fathomSiteId}" defer></script>`;}…and add "fathom" to the provider union type:
analytics: { provider: "fathom" as "google" | "plausible" | "umami" | "fathom" | null, fathomSiteId: "ABCDEFGH",}Custom head scripts
Section titled “Custom head scripts”For one-off pixels, verification tags, or anything else that goes in <head>, use siteConfig.headScripts — a raw HTML string injected after analytics:
headScripts: ` <script defer src="https://customer.io/pixel.js" data-site="123"></script> <meta name="google-site-verification" content="abc123" />`,What’s next
Section titled “What’s next”- Contact form — wire your contact form to Formspree, FormSubmit, or Netlify.
- Newsletter — wire the newsletter form to Mailchimp, ConvertKit, or Buttondown.
- Deploy → Custom domain — point a real domain at the build so analytics tracks the right host.