Documentation

Everything you need to know

Two minutes to your first event. The rest of this page covers things you do after the product already works.

Install on WordPress

For WordPress sites we recommend our plugin. It connects the site to your Spårlös account with one click, injects the snippet automatically on every public page, and handles 404 detection and proxy mode (to avoid adblockers).

  1. Search for Spårlös under WordPress → Plugins → Add New and click Install (or download the ZIP file directly).
  2. Activate the plugin.
  3. Go to Settings → Spårlös and click Connect to Spårlös.
  4. Confirm in the new tab. Done.

Install on any site (code snippet)

The base snippet is one line. You paste it into the site's <head> and every pageview starts counting right away. If you can't find how to edit the <head> in your framework, we have concrete examples below this section.

Paste into your site's <head>
<script defer
  data-site="DIN_SITE_ID"
  src="https://sparlos.se/script.js">
</script>

Always use defer. The script is under 1.5 KB gzipped and never blocks page load. Load a page once after installing, and the first event shows up in the dashboard within 30 seconds.

You find DIN_SITE_ID in the dashboard once you have created a site: Create site.

Per framework: where the code goes

The exact file and where to paste the code in popular frameworks. Replace DIN_SITE_ID with the site ID from the dashboard.

Next.js (App Router)

Put the <script> directly in the root layout.tsx so it covers every page. In a dev environment the tracker is self-filtering (it bails on localhost).

Paste into your site's <head>
// src/app/layout.tsx (Next.js App Router)
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="sv">
      <head>
        <script
          defer
          data-site="DIN_SITE_ID"
          src="https://sparlos.se/script.js"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}

Next.js (Pages Router)

Use the central _document.tsx to put the script in <Head>. It then loads on every page without client overhead.

Paste into your site's <head>
// pages/_document.tsx (Next.js Pages Router)
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="sv">
      <Head>
        <script
          defer
          data-site="DIN_SITE_ID"
          src="https://sparlos.se/script.js"
        />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

React (Vite / Create React App / any React template)

Edit index.html in the project root. The script can sit in the <head> before React's main.tsx. The Spårlös script hooks intohistory.pushState so React Router navigations are captured automatically.

Paste into your site's <head>
<!-- index.html (Vite / Create React App / any React template) -->
<!doctype html>
<html lang="sv">
  <head>
    <meta charset="UTF-8" />
    <title>My site</title>
    <script
      defer
      data-site="DIN_SITE_ID"
      src="https://sparlos.se/script.js"
    ></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Vue 3 (Vite)

Same as React: edit index.html in the project root. Vue Router uses history.pushState which the tracker hooks automatically.

Paste into your site's <head>
<!-- index.html (Vue 3 + Vite or another Vue template) -->
<!doctype html>
<html lang="sv">
  <head>
    <meta charset="UTF-8" />
    <title>My site</title>
    <script
      defer
      data-site="DIN_SITE_ID"
      src="https://sparlos.se/script.js"
    ></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

Nuxt 3

Add the script in nuxt.config.ts under app.head.script. It is then injected on every page without you needing to touch any layout components.

Paste into your site's <head>
// nuxt.config.ts (Nuxt 3)
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          defer: true,
          'data-site': 'DIN_SITE_ID',
          src: 'https://sparlos.se/script.js',
        },
      ],
    },
  },
});

SvelteKit

Add the script in src/app.html, SvelteKit's root template that wraps every route.

Paste into your site's <head>
<!-- src/app.html (SvelteKit) -->
<!doctype html>
<html lang="sv">
  <head>
    %sveltekit.head%
    <script
      defer
      data-site="DIN_SITE_ID"
      src="https://sparlos.se/script.js"
    ></script>
  </head>
  <body>
    <div>%sveltekit.body%</div>
  </body>
</html>

Astro

Add it to your shared BaseLayout.astro (or src/layouts/Layout.astro depending on the template).is:inline makes sure Astro does not process the script with Vite.

Paste into your site's <head>
---
// src/layouts/BaseLayout.astro
---
<!doctype html>
<html lang="sv">
  <head>
    <meta charset="UTF-8" />
    <title>{Astro.props.title}</title>
    <script
      is:inline
      defer
      data-site="DIN_SITE_ID"
      src="https://sparlos.se/script.js"
    ></script>
  </head>
  <body><slot /></body>
</html>

Static HTML / Hugo / Eleventy / Jekyll / 11ty

Paste the script into your template (usually layouts/_default/baseof.html in Hugo, _includes/head.html in Jekyll/Eleventy). Or just in your index.html if the site is hand-rolled.

Paste into your site's <head>
<!-- index.html (static HTML, Hugo, Eleventy, Jekyll) -->
<!doctype html>
<html lang="sv">
  <head>
    <meta charset="UTF-8" />
    <title>My site</title>
    <script
      defer
      data-site="DIN_SITE_ID"
      src="https://sparlos.se/script.js"
    ></script>
  </head>
  <body>...</body>
</html>

Google Tag Manager

Create a new Custom HTML tag. Paste the base snippet above. Trigger: All Pages. Publish. The Spårlös script loads on the page via GTM and hooks into pushState just as well as a direct include, but you lose 30 to 40 ms compared to including it directly in the <head>.

Other platforms

The snippet above works on any platform that lets you edit the <head>. Here are the exact menu paths for the most common ones:

Shopify
Admin → Sales channels → Online Store → Themes → Edit code → theme.liquid (under )
Webflow
Site settings → Custom code → Head code
Squarespace
Settings → Advanced → Code Injection → Header
Wix
Settings → Custom code → Add custom code → Head
Ghost
Settings → Code injection → Site Header
Framer
Site settings → General → Custom code → Start of

How the big players install

Every privacy analytics service uses the same pattern: a small JS snippet in the <head> that posts to an ingest endpoint. The difference is what the snippet does and how much data it sends.

ToolSnippet size (gzip)CookiesWP plugin
Spårlös< 1.5 KBNoneYes, one-click connect
Plausible~1.3 KBNoneYes
Fathom~2 KBNoneYes
Umami~2.5 KBNoneCommunity
Google Analytics 4~50 KBSeveral (consent required)Yes (Site Kit)
Matomo~22 KBConfigurableYes

Sources: each tool's official docs and npm packages. Measured over the first-party CDN, not proxied. The GA4 figure is gtag.js plus tag manager overhead in a normal configuration.

Track 404 errors

The tracker snippet auto-detects 404 pages via page title and URL patterns (English and Swedish). That covers about 80 percent of all themes. For the rest: add a meta tag on your 404 page to mark the pageview as a 404 event explicitly.

Paste into your site's <head>
<meta name="sparlos-event" content="404" />

The WordPress plugin emits this tag automatically on every 404 page. You do not need to do anything.

Result: in the dashboard you get a separate Top 404 URLs report that shows which broken links drive the most traffic. Perfect for finding 301 redirects to add.

SPA navigation

Spårlös automatically detects navigations via history.pushState, history.replaceState and hashchange. This covers React Router, Next.js App Router, SvelteKit, Vue Router and every other modern SPA framework, including older HashRouter-based apps (/#/cart). You do not need to do anything extra.

Manual pageview hook

Some SPA patterns do not change the URL between views. Typical examples: a cart as a slide-out drawer, login as a modal, tab navigation driven by React state. Because the URL does not change, the tracker does not know that a "page change" happened.

For these cases the tracker exposes window.sparlos.pageview(). Call it manually when your virtual view opens:

Paste into your site's <head>
// Example: cart slide-out
function openCart() {
  setCartOpen(true);
  window.sparlos?.pageview();
}

// Example: login modal
function openLoginModal() {
  setLoginOpen(true);
  // change the URL too so subsequent dedupes work
  window.history.pushState({}, '', '/login');
  // the pushState hook catches it automatically; no extra call needed.
}

The Spårlös script dedupes identical URLs in a row, so it is safe to call sparlos.pageview() even if you are unsure whether the URL has already changed.

DNT and GPC are respected

Our tracker respects the Do Not Track header (DNT) and Global Privacy Control (GPC) by default. Visitors with these flags enabled are never counted in your statistics. You do not need to change anything.

Exclude pages from tracking

As a per-site setting you can block URL patterns from being tracked. Common examples: /admin/*, /preview/*, /api/*. Pageviews that match the blocklist are sent to our ingest API but dropped before they are stored.

Configure it under Dashboard → Site → Settings → Blocklist.

Get your data (GDPR Art. 15)

You own your data and have the right to a copy at any time (GDPR Article 15, right of access, and Article 20, data portability). A self-service export via API is in development and unlocks as soon as per-user scoping is done.

In the meantime: go to Profile and click Request my data. We compile your pageviews, site settings and account data, and email it back to your registered address within 30 days (statutory response time). Completely free, all plans.

Stop sending data to the US. Start today.

Get the same insights as from Google Analytics. No banner, no cookies, no legal headache.

Documentation | Spårlös