Best analytics for static sites on Astro
How to add analytics to an Astro static site, and which privacy-first tools fit a mostly-HTML site best.
How to add analytics to an Astro static site, and which privacy-first tools fit a mostly-HTML site best.
Astro is built for content sites: it ships HTML by default and only hydrates the interactive islands you ask for. That makes it a wonderful match for lightweight, privacy-first analytics, because the whole point of both is to add almost nothing to the page. A static Astro site can carry analytics that weighs a few kilobytes and never touches the main thread.
The install is a single tag in your base layout. This guide covers how to add it, how to handle Astro's client-side navigation if you use view transitions, and what to look for when choosing a tool for a static site.
Every Astro project has a layout that wraps pages. In the default starter that is src/layouts/Layout.astro. Put the analytics tag in the head with the defer attribute so it never blocks rendering.
---
// src/layouts/Layout.astro
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{Astro.props.title}</title>
<script
defer
src="https://cdn.lumenlytic.com/analytics.js"
data-website-id="YOUR_TRACKING_ID"
></script>
</head>
<body>
<slot />
</body>
</html>Because it is in the base layout, every page that uses the layout is tracked. Static pages render the tag once at build time, so there is no server work and no extra JavaScript bundle from your framework.
Plain Astro is multi-page: each link is a full navigation, so every click loads a new document and fires a new pageview automatically. If you use Astro's view transitions, navigation becomes client-side, and a tracking script that only counts the initial load would miss subsequent pages. Choose a tool whose script listens for the History API, or call its pageview function after each transition. This is the same trap as the Next.js App Router, and the same fix applies.
Plausible and Lumenlytic both install with a single tag and are cookie-free. Plausible's script is smaller; Lumenlytic's captures Core Web Vitals alongside traffic and has a fairly generous free tier. Umami is a good fit if you want to self-host. Cloudflare Web Analytics is worth considering if your site is already behind Cloudflare and you only need the basics. All of them will work with Astro; the differences are price, retention and feature depth.
For a blog or documentation site, the practical winner is usually whichever tool gives you honest traffic numbers with the least added weight and the least ongoing cost. A static site is already fast; the goal is to keep it that way while still knowing which pages people read and where they come from.
Astro ships zero JavaScript by default and only hydrates the interactive islands you opt into, which is why it pairs so well with a tiny analytics script. The one place to be careful is view transitions. When you enable them, navigation becomes client-side and the document does not reload, so a script that only counts the initial load will miss every page after the first. Pick a tool whose script subscribes to the History API, or call its pageview function after each transition. Test by navigating between two pages and confirming a second pageview appears in real time; if it does not, the script needs a manual nudge.
A static site is often deployed to a CDN, and the analytics script should be cached the same way. Loading it from the vendor's CDN with the defer attribute is fine and requires no build step. If you prefer to self-host it, put the file in public/ so Astro copies it unchanged, and serve it with a long cache lifetime. The tracking identifier still tells the service which site is reporting, so self-hosting does not change the data flow. Keep the tag in the base layout so it appears once per document, and avoid bundling it through the framework, which would add JavaScript for no benefit.
Content sites usually care about more than raw pageviews. Outbound clicks, file downloads and scroll depth tell you whether people actually engage with a post, and a well-designed script can track them automatically or with a single call. If you write long guides, pageleave timing shows which ones hold attention. If you link to products or sources, outbound tracking shows which are useful. Keep the event names few and stable, and avoid over-instrumenting early; a handful of meaningful signals beats a wall of numbers nobody reads. Start with pageviews and referrers, add one or two events you will actually act on, and expand only when a question demands it. One more consideration is caching. A static Astro site is usually served from a CDN, and the analytics tag is part of the HTML, so make sure your cache rules do not serve stale HTML with an old tracking identifier after a change. Set a short cache lifetime on HTML and a long one on assets, and purge the cache after deploys that touch the layout. If you self-host the script, do the same for it. These details do not affect the numbers much day to day, but they prevent the confusing case where a change seems not to have taken effect because an edge node is still serving yesterday's page. Check the response headers after a deploy if something looks stale; a quick curl will tell you whether the HTML is cached longer than you intended. Getting the cache right keeps both the page and the numbers honest, and it is a five-minute check that saves a confusing afternoon of doubt. Make it part of your release checklist so it happens every time rather than only when something breaks. It is a small habit that keeps a fast site fast and a measurement trustworthy.