Antlytics logoAntlytics
← Blog
5

Analytics for SvelteKit: A Quick Setup Guide

How to add privacy-friendly analytics to a SvelteKit project. SvelteKit's routing needs a specific approach.

Analytics for SvelteKit: A Quick Setup Guide

SvelteKit is a server-side rendering framework built on Svelte. Adding analytics requires handling both initial page loads and client-side navigation events — the standard script tag gets the former, but SvelteKit's routing system handles navigation differently.

SvelteKit basics: how routing works

SvelteKit uses file-based routing. When a visitor navigates between pages, SvelteKit intercepts the navigation and updates the DOM without triggering a full page load. This is the same SPA pattern that requires special handling in Next.js.

The upshot: you cannot just drop a script into <head> and have it fire on every navigation. You need to hook into SvelteKit's navigation events.

Option 1: Script tag with navigation hook (recommended)

SvelteKit provides a $app/navigation module with lifecycle events. You can use the afterNavigate callback to fire an analytics pageview on each client-side navigation.

In your +layout.svelte (the root layout file):

<script>
  import { afterNavigate } from '$app/navigation';
  import { onMount } from 'svelte';

  const TRACKING_ID = 'YOUR_TRACKING_ID';
  const INGEST_URL = 'https://www.antlytics.com/api/ingest/pageview';
  const SESSION_KEY = 'ant_sid';

  function getSessionId() {
    try {
      let sid = sessionStorage.getItem(SESSION_KEY);
      if (sid) return sid;
      sid = crypto.randomUUID();
      sessionStorage.setItem(SESSION_KEY, sid);
      return sid;
    } catch {
      return crypto.randomUUID();
    }
  }

  function sendPageview() {
    fetch(INGEST_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      keepalive: true,
      body: JSON.stringify({
        tracking_id: TRACKING_ID,
        pathname: location.pathname,
        referrer: document.referrer || undefined,
        session_id: getSessionId()
      })
    }).catch(() => {});
  }

  onMount(() => {
    sendPageview();
  });

  afterNavigate(() => {
    sendPageview();
  });
</script>

<slot />

Replace YOUR_TRACKING_ID with your actual UUID from Settings → Tracking Snippet in your Antlytics dashboard.

Why both onMount and afterNavigate?

Using only afterNavigate misses the initial load. Using only onMount misses subsequent navigations.

Option 2: Script tag in app.html

SvelteKit has an app.html file in src/ that is the HTML shell for every page. You can add the standard Antlytics snippet there:

<!-- src/app.html -->
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    %sveltekit.head%
    <script>
    (function(){
      var t="YOUR_TRACKING_ID",
          u="https://www.antlytics.com/api/ingest/pageview",
          k="ant_sid";
      function sid(){
        try{var s=sessionStorage.getItem(k);if(s)return s;
        s=crypto.randomUUID();sessionStorage.setItem(k,s);return s;}
        catch(e){return crypto.randomUUID();}
      }
      function send(){
        fetch(u,{method:"POST",headers:{"Content-Type":"application/json"},
        keepalive:true,body:JSON.stringify({tracking_id:t,
        pathname:location.pathname,referrer:document.referrer||undefined,
        session_id:sid()})}).catch(function(){});
      }
      send();
      window.addEventListener("popstate",send);
    })();
    </script>
  </head>
  <body data-sveltekit-preload-data="hover">
    <div style="display: contents">%sveltekit.body%</div>
  </body>
</html>

Limitation: The popstate event fires on browser back/forward navigation but does not fire on SvelteKit's programmatic navigation (e.g., goto(), link clicks handled by the router). Use Option 1 for complete coverage.

Verifying it works

  1. Start your SvelteKit dev server (npm run dev or pnpm dev).
  2. Open the browser dev tools → Network tab.
  3. Navigate between pages.
  4. Look for POST requests to api/ingest/pageview on each navigation.
  5. Check your Antlytics dashboard for new pageviews.

SvelteKit 2 specifics

If you are on SvelteKit 2 (current stable), the afterNavigate API is unchanged from SvelteKit 1. The +layout.svelte approach works the same way.

VERIFY_IN_REPO: If Antlytics ships a dedicated SvelteKit integration or npm package in the future, check the implementation guides for updated instructions.

FAQ

Does this work with SSR enabled? Yes. The onMount and afterNavigate callbacks only run in the browser. The analytics code does not execute during server-side rendering.

Does this work with SvelteKit's prerender option? Yes. Prerendered pages are static HTML served to the browser, where the client-side script executes normally. Analytics fires on initial load and subsequent navigations as expected.

Can I use the first-party proxy with SvelteKit? SvelteKit has server-side route handlers (+server.js files). You can implement a forwarding handler in src/routes/api/antlytics/+server.js that proxies requests to https://www.antlytics.com/api/ingest/pageview. Update your INGEST_URL in the tracking code to point to your proxy route.

What about Svelte without SvelteKit? Plain Svelte (without SvelteKit) has no built-in routing. If you're using Svelte with a client-side router, hook into that router's navigation events. If pages are full page loads, the popstate approach in app.html is sufficient.


Related: Privacy analytics: Scripts vs SDKs vs Proxies vs APIs · SPA analytics · Antlytics implementation guides