Updated 20 October 2026

Astro analytics

Privacy-first, cookieless analytics for Astro: one tag in the shared layout, a fit for static sites and for view transitions.

In short

  • One tag in the head of src/layouts/Layout.astro, with is:inline so Astro leaves it alone.
  • Works on fully static output. Nothing else is added to your bundle.
  • No cookie banner needed in cookieless mode, no IP address stored, and nothing loaded from another company.

Install on Astro#

Use your own site id and server address in the code below. On trckable Cloud the address is https://cloud.trckable.com.

Put the tag in the shared layout, inside <head>. is:inline tells Astro to keep the tag exactly as written:

---
// src/layouts/Layout.astro
---
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script
      is:inline
      defer
      data-site="tkb_a1b2c3d4"
      data-domain="example.com"
      src="https://stats.example.com/js/tkb_a1b2c3d4.js">
    </script>
  </head>
  <body>
    <slot />
  </body>
</html>

npx trckable init also recognises Astro, prints the change and writes it only with --yes.

For a server-rendered Astro site you can send events through your own domain with an endpoint:

// src/pages/api/e.ts (needs an adapter: the endpoint runs per request)
import { proxy } from 'trckable/server'

const trckable = proxy({
  host: import.meta.env.TRCKABLE_HOST,
  proxyKey: import.meta.env.TRCKABLE_PROXY_KEY,
})

export const POST = ({ request }) => trckable(request)

Open your site once, then run npx trckable doctor --host https://stats.example.com --site tkb_a1b2c3d4 --url https://example.com. It only reads, and tells you whether the tag is on the page and the server answers.

What to know about Astro#

  • Put it in the layout every page uses, not in one page, or the pages without it are not counted.
  • View transitions swap the page without a reload. The tag stays loaded once, and trckable counts the new path when the history API changes it.
  • Static output needs no adapter. The endpoint above is optional and only for sites that render on demand.
  • Island frameworks are fine. React, Vue or Svelte islands do not change anything: there is one tag per page, in the head.

Goals and revenue#

A goal needs no code: put an attribute on the element and each click is counted.

<button data-trckable-goal="signup" data-trckable-goal-plan="pro">Start trial</button>

Connect Stripe, Paddle, Lemon Squeezy, Polar or Dodo Payments with one key, and each payment is credited to the visit that earned it, so revenue shows next to traffic. See revenue attribution.

Questions#

Does the tag work with Astro's static output?
Yes. It is plain HTML in the head of every built page. The script itself is served by your trckable server, so it adds nothing to your Astro build.
Do I need a cookie banner on my Astro site?
Not for the counting itself. In cookieless mode (add data-cookieless to the tag) nothing is stored on the visitor's device and no IP address is kept. Whether your site needs a banner for other reasons is a question for your own situation; the cookie banner guide explains the rules in plain words.
Can ad blockers stop it?
A blocker can block any script, and trckable does not claim otherwise. Sending events through your own domain removes the separate analytics file a blocklist would match by name, which is the accurate setup. The same-origin proxy guide shows how.
Is it free for a Astro site?
The server is open source and free to self-host, and the tracker is MIT licensed. If you would rather not run a server, trckable Cloud runs it for you; the plans are on the pricing page.

Keep reading#

Other stacks#

Start free