Add analytics to an Astro site with View Transitions
To add analytics to an Astro site, put one script tag in your shared layout's <head>. For Simplytics that is <script async is:inline src="https://simplytics.dev/track.js" data-key="YOUR_KEY"></script>. It sets no cookies, needs no consent banner, and — the part most Astro guides skip — keeps counting page views across View Transitions route changes with no extra code.
Astro can serve pages two ways, and analytics has to survive both. A plain Astro site is multi-page: every link is a full document load, so any tag in the page runs once per page and counts each view the ordinary way. Turn on client-side routing with <ClientRouter /> and Astro starts swapping pages in place — the browser never reloads, so a tracker that only fires on page load would count the first view and miss every navigation after it. The tag below handles both cases, because it hooks the same browser API that Astro's router uses.
Where the tag goes in an Astro project
Put it once, in the <head> of the layout every page shares — usually src/layouts/Layout.astro, or a BaseHead.astro component that layout pulls in. Anywhere that renders on every route works; a shared layout is how you guarantee that.
---
// src/layouts/Layout.astro
---
<html lang="en">
<head>
<meta charset="utf-8" />
<slot name="head" />
<!-- Simplytics: cookieless, ~1.8 KB gzipped -->
<script
async
is:inline
src="https://simplytics.dev/track.js"
data-key="YOUR_KEY"
></script>
</head>
<body>
<slot />
</body>
</html>
The is:inline directive matters. By default Astro processes and bundles <script> tags — it rewrites them, and its docs tell you to add is:inline for any script that loads from outside your project, using an external analytics tag as the example. is:inline renders the tag into the HTML exactly as written, so the script loads straight from simplytics.dev with your data-key intact. Leave it off and Astro tries to treat a third-party CDN script as one of your own modules.
Replace YOUR_KEY with the site key from your dashboard — it is the same public key that ships in the snippet on every customer page, safe to commit. The script is ~1.8 KB gzipped; for how that compares to the alternatives, see how much JavaScript each analytics tool ships, where GA4's tag weighs about 140 KB.
Do View Transitions break the page-view count?
No — with Simplytics, View Transitions route changes are counted automatically, and you should not add any per-navigation code. Astro's client-side router (<ClientRouter />, imported from astro:transitions; it was named <ViewTransitions /> before Astro 5.0 renamed it) navigates using the browser History API — history.pushState and history.replaceState. The Simplytics script wraps exactly those two functions and listens for popstate, so when Astro swaps to a new path, the tracker sees it, records a page view, and sets the page you just left as the referrer (which the server folds into Direct, like a normal in-site click). Query-string-only and hash-only changes are ignored, so filter and tab state don't inflate your numbers.
Because the script initializes once and Astro does not re-run existing scripts on a swap (bundled and inline scripts execute a single time unless you add data-astro-rerun), the History-API patch stays live for the whole session. So do not reach for the common workarounds:
- Don't add an
astro:page-loadhandler that re-sends a page view. The tracker already caught thepushState; firing again onastro:page-loaddouble-counts every navigation. - Don't add
data-astro-rerunto the tag. That forces the script to re-execute on every transition, which re-initializes the tracker and, again, double-counts.
Here is what each analytics tool needs to count route changes on an Astro site running View Transitions:
| Tool | Astro route changes (View Transitions) | What you add |
|---|---|---|
| Simplytics | Automatic | Nothing beyond the tag. It patches the History API that <ClientRouter /> drives. |
| Plausible | Automatic | Nothing for History-API routers (Astro's is one); Plausible has no Astro-specific doc, its standard script handles pushState routing. |
| Fathom | Automatic with an attribute | Add data-spa="auto" to the script — its official Astro doc calls for it. |
| Google Analytics 4 | Config or manual | Enable the "Page changes based on browser history events" Enhanced-Measurement option, or send page_view on astro:page-load — never both, or you double-count. |
Simplytics, Plausible, and Fathom all end up auto-tracking History-API routing; the difference is only whether you flip a setting. GA4 is the one that makes you choose a mechanism and avoid the double-count trap. (For the general single-page-app version of this, not Astro-specific, see how to track single-page app page views without cookies.)
How to verify the first hit
Because Astro dev and production behave differently, verify against a production build, not astro dev:
- Build and serve the production output:
astro build && astro preview(or deploy). The tag only runs when it is actually in the served HTML. - Open the site and open your browser's DevTools Network tab. Filter for
track. On the first page you should see aPOSTtohttps://simplytics.dev/trackthat returns{"status":"success"}. - Click an internal link. If View Transitions are on, the URL changes without a full reload — and a new
POST /trackshould fire for the new path. That is the route-change count working. If it doesn't fire, the tag isn't in the shared<head>, oris:inlineis missing and Astro rewrote it. - Open your dashboard. The first real page view starts your 30-day free trial (no card), and the site flips to verified once a hit arrives.
No hit on step 2 usually means the tag landed in one page instead of the shared layout, or a browser extension is blocking the request.
How to exclude your own visits
Simplytics stores no cookie and no IP address — country comes from an edge header and the identifier is a same-day hash that is wiped nightly — so there is nothing to key a per-visitor "exclude me" toggle on, and the dashboard has no such setting. Two honest ways to keep your own traffic out:
Keep the tag out of development entirely. Gate it on the build mode so it never loads under
astro devor in preview:{import.meta.env.PROD && ( <script async is:inline src="https://simplytics.dev/track.js" data-key="YOUR_KEY"></script> )}import.meta.env.PRODistruein a production build andfalseinastro dev, so your local editing never sends hits.Block the request in your own browser for the live site — uBlock Origin, a Pi-hole, or a
hostsentry forsimplytics.dev. Since raw visit rows are deleted nightly and only aggregates are kept, a handful of your own views wash out quickly regardless.
Where Simplytics is not the right choice
Honest limits, because the tag isn't magic:
- Hash-based routers are not auto-tracked. If your Astro app routes with
#/pathURLs, the History-API hook never fires. Astro's own<ClientRouter />uses real paths, so this is rare on Astro, but worth knowing. - Country-level geography only. Simplytics reports countries, not cities — it never stores an IP to resolve one. If you need city-level location or long-lived per-visitor journeys, GA4 or Matomo fit better.
- Fathom hand-holds the SPA case harder. Its Astro doc spells out the
data-spa="auto"attribute; if you want a vendor walking you through every Astro edge case in their own docs, that's a fair reason to weigh it.
On the Astro question itself, Simplytics isn't uniquely magic — Plausible auto-tracks the same History-API routing. What differs is everything around it: no cookies (so no consent banner), EU data storage in Warsaw, raw rows deleted nightly with aggregates kept forever, and the price. That's the recurring theme — a lot of functionality for a lot less money: Simplytics is $1/month, billed yearly ($12/year, its 50,000 page views a month across up to 12 sites, 30-day trial, no card) against Plausible's $9/month. The full trade-offs are in Simplytics vs Plausible and vs Google Analytics, and you can see a live dashboard on the demo or start from pricing.
Astro behavior reflects Astro 5.x docs (client-side scripts, View Transitions, environment variables) and each vendor's published Astro or SPA guidance. Last verified: 2026-09-05.