Static site generators · 3 min setup
How to add analytics to a Hugo site
extend_head.html — wrapped in {{ if hugo.IsProduction }} so hugo server never sends data. Put the site id in your site config so the theme files stay untouched.Updated
Hugo merges your project's layouts folder over the theme's, so you never edit the theme itself: create a file with the same name in your own layouts folder and Hugo uses yours. Hugo 0.146 renamed the partials folder to layouts/_partials/; on older versions and many themes it's layouts/partials/. Use whichever your Hugo version and theme use.
Hugo at a glance
- Where the tag goes
- A head partial or the theme's head hook (e.g.
extend_head.html) - Production only
{{ if hugo.IsProduction }}(false underhugo server)- Config
params.visitrack.siteIdinhugo.toml- Goals
- A small shortcode adding
data-vt-goal - Hosting
- Any static host — Netlify, Cloudflare Pages, GitHub Pages, Vercel
How to install VisitTrack on Hugo
Step 1: Copy your site id into hugo.toml
Copy the id from VisitTrack's install step and add it to your site config. Keeping it in config means the partial works across environments and themes.
hugo.toml[params.visitrack] siteId = "SITE_ID"Step 2: Create the partial
hugo.IsProductionis true forhugobuilds (the production environment) and false forhugo server. Hugo escapes the attribute value for you.layouts/_partials/visitrack.html{{ if hugo.IsProduction }} {{ with site.Params.visitrack.siteId }} <script defer data-site="{{ . }}" src="https://visitrack.app/tracker.js"></script> {{ end }} {{ end }}Step 3: Include it in the head
If your theme has a head hook, put the include there — PaperMod reads
extend_head.html, and many themes have a similar hook (check your theme's docs). Otherwise copy the theme'shead.html(or the<head>part ofbaseof.html) into your ownlayoutsfolder and add the line before</head>.layouts/_partials/extend_head.html (PaperMod){{ partial "visitrack.html" . }}Step 4: Build and deploy
Run
hugo(or let your host build it), deploy, and open the live site.
How to check VisitTrack is working on Hugo
- Search the generated
public/index.htmlfortracker.jsafter a production build — it should be there; underhugo serverit shouldn't. - Open the deployed site and read two posts; the VisitTrack live view shows you and the Pages tab lists both paths.
- Your theme's
404.htmlusually has "404" or "not found" in its title, so broken links show up aspage_not_foundevents automatically.
Does VisitTrack track Hugo page navigation?
Hugo output is plain static HTML, so every page is a full page load and one pageview. Taxonomy pages (/tags/go/), section lists and paginated lists (/posts/page/2/) each have their own path.
If your theme uses a client-side page-transition library that changes the URL with the History API, those navigations are counted too — no theme changes needed.
How to track custom events and goals in Hugo
Markdown links can't carry custom attributes in Hugo, so add a shortcode that renders a link with data-vt-goal and use it in your content. (Shortcodes live in layouts/_shortcodes/ on Hugo 0.146+, layouts/shortcodes/ before.)
<!-- layouts/_shortcodes/goal.html -->
<a href="{{ .Get "href" }}" data-vt-goal="{{ .Get "name" }}">{{ .Inner }}</a>
<!-- in any post -->
{{< goal href="https://app.example.com/signup" name="blog_signup_click" >}}Try it free{{< /goal >}}To measure how many readers finish a post, add <div data-vt-scroll="post_finished"></div> near the end of your single.html template. It fires once per page when that element is half visible. Then make either event a goal in Settings → Goals.
Script options you might need on Hugo
All optional — add them to the same tag. Full reference: script configuration.
| Attribute | What it does |
|---|---|
data-cookieless | Store nothing in the browser; the server derives a daily-rotating id. See cookieless mode. |
data-exclude="/app/*" | Never track these paths (comma-separated, * wildcard). Checked on every navigation. |
data-allow-local | Track on localhost and *.local — for testing an install only. |
data-debug | Log every event the script sends, and why it skipped one, to the console. |
data-auto="false" | Turn off automatic events (downloads, contact clicks, form submits, rage clicks, JS errors, 404s). |
Hugo troubleshooting
The tag isn't in the built HTML
Either the partial isn't included from the head your theme actually renders, or the build ran in a non-production environment (hugo --environment staging). Check hugo.IsProduction and the include path.
Your override is ignored
The file must mirror the theme's path and name exactly, in your project's layouts folder, using the same partials folder name (_partials vs partials) your Hugo version resolves.
Deploy previews count as traffic
Netlify and Cloudflare previews build in production mode too. Save your real domain under Settings → General → Allowed hostnames in VisitTrack.
site.Params.visitrack.siteId is empty
Config keys are case-insensitive in Hugo but the nesting matters: it must be under [params.visitrack].
Hugo analytics FAQ
Where do I put an analytics script in Hugo?
In the head of your base template — ideally through a partial included from your theme's head hook (like PaperMod's extend_head.html), so you don't modify the theme. Wrap it in hugo.IsProduction to skip local development.
Does hugo server send analytics data?
Not with the partial above: hugo.IsProduction is false under hugo server. VisitTrack's script also ignores localhost by default.
Does VisitTrack work with Hugo themes like PaperMod or Blowfish?
Yes. It's one tag in the page head, independent of the theme. Use the theme's head-extension partial if it has one, or override its head template in your own layouts folder.
Can I track outbound links on a Hugo blog?
Yes, automatically. Every click on a link to another domain is recorded and shows up in the Outbound tab, with no shortcode needed.
Is VisitTrack a privacy-friendly alternative to Google Analytics for Hugo?
Yes. In cookieless mode it stores nothing in the browser, so a static blog can skip the consent banner. See VisitTrack vs Google Analytics.
Keep going
- Jekyll analyticsAdd VisitTrack to Jekyll (and GitHub Pages) through _includes/head.html or Minima's custom-head.html, production-only via jekyll.environment.
- Astro analyticsAdd VisitTrack to Astro with one is:inline tag in your shared layout — works for static, SSR and ClientRouter (view transitions) sites.
- Netlify analyticsAdd VisitTrack on Netlify with Snippet injection (no code) or in your framework, keep deploy previews out, and set CSP in _headers.
- Cloudflare Pages analyticsAdd VisitTrack on Cloudflare Pages in your HTML or with an HTMLRewriter middleware, exclude it from Rocket Loader, and track AI crawlers at the edge.
- Install the tracking scriptThe reference tag, CSP notes and how to check it's working.
- Custom events and signupsvisitrack(), data-vt-goal, scroll events and server-side signups.
- Use casesHow SaaS teams, indie hackers, stores and agencies use VisitTrack.
- VisitTrack vs Google AnalyticsCookie-free analytics with revenue attribution, compared honestly.
Add VisitTrack to your Hugo site
Cookie-free analytics with revenue attribution, live visitors, funnels and session replays. One script tag, every feature on every plan. 14 days free, no card required.
Not on Hugo? See all 29 integration guides.