Skip to content

Analytics for Static Sites Without Trackers — Privacy-First Guide

DodaTech Updated 2026-06-22 7 min read

In this tutorial, you'll learn about Analytics for Static Sites Without Trackers. We cover key concepts, practical examples, and best practices.

Privacy-first analytics for static sites tracks page views, referrers, and user engagement without cookies, fingerprinting, or GDPR consent banners — using server-side logs, lightweight JavaScript beacons, or edge-based measurement instead of traditional tracking scripts.

What You'll Learn

Why It Matters

Google Analytics requires cookie consent banners across the EU, slows page load with a heavy script, and shares visitor data with third-party ad networks. Privacy-first alternatives like Cloudflare Web Analytics and GoatCounter collect essential metrics with zero cookies, no personal data collection, and minimal performance impact — keeping your site fast and legally compliant.

Real-World Use

A documentation site uses Cloudflare Web Analytics to track top pages and referrers without any client-side JavaScript. A developer blog uses GoatCounter for lightweight visit counting with a privacy dashboard. A SaaS landing page uses Plausible for marketing analytics with a clean, real-time dashboard that respects ad blockers.

Analytics Architecture Comparison

flowchart TD
  subgraph Traditional[Google Analytics]
    A1[User Browser] --> B1[gtag.js Script]
    B1 --> C1[Google Servers]
    C1 --> D1[Tracking Cookies]
    D1 --> E1[Ad Personalization]
  end

  subgraph Privacy[Privacy-First]
    A2[User Browser] --> B2[Edge/Server Log]
    B2 --> C2[No Cookies]
    B2 --> D2[Anonymous Data]
    D2 --> E2[Simple Dashboard]
  end

  style Traditional fill:#f44,color:#fff
  style Privacy fill:#090,color:#fff

Analytics Platform Comparison

Feature Google Analytics Cloudflare Web Analytics GoatCounter Plausible Umami (Self-hosted)
Cookies Yes (multiple) None None None None
GDPR compliant No (needs consent) Yes Yes Yes Yes
Page load impact ~45KB + requests ~2KB ~3KB ~1KB ~3KB
Blocked by ad blockers Yes No No Sometimes No
Bounce rate Yes Yes Yes Yes Yes
Custom events Yes No Limited Yes Yes
Real-time Yes No Yes Yes Yes
Self-hostable No No Yes No Yes
Cost Free Free (with CF) Free (public) / Paid Paid Free (self-hosted)

Cloudflare Web Analytics

Cloudflare Web Analytics measures page views and visits without any client-side JavaScript by using edge log data from Cloudflare's network.

Setup

Enable Web Analytics in the Cloudflare dashboard under Analytics > Web Analytics and add your domain. No code changes are needed if your site is proxied through Cloudflare.

Manual JavaScript Beacon (Optional)

<!-- Cloudflare Web Analytics beacon (deferred, non-blocking) -->
<script
  defer
  src="https://static.cloudflareinsights.com/beacon.min.js"
  data-cf-beacon='{"token": "your-token"}'>
</script>

Expected behavior: When a visitor loads the page, the beacon sends an anonymous request to Cloudflare's analytics endpoint. The data appears in the Cloudflare dashboard within minutes, showing page views, top pages, referrers, and device types.

GoatCounter Integration

GoatCounter is a lightweight, privacy-first analytics service that can be self-hosted or used via the public hosted version.

JavaScript Snippet

<!-- GoatCounter analytics -->
<script
  data-goatcounter="https://your-code.goatcounter.com/count"
  async
  src="https://gc.zgo.at/count.js">
</script>

Expected behavior: GoatCounter records a page view with the URL, referrer, screen size, and country (from IP address, not stored). No cookies are set, and the data is not shared with third parties. The dashboard shows visit totals, daily breakdowns, and top pages.

Hugo Partial for Conditional Loading

{{/* layouts/partials/analytics.html */}}
{{ if not .Site.IsServer }}
  {{ if eq .Site.Params.analytics "goatcounter" }}
    <script
      data-goatcounter="https://{{ .Site.Params.goatcounterCode }}.goatcounter.com/count"
      async
      src="https://gc.zgo.at/count.js">
    </script>
  {{ else if eq .Site.Params.analytics "cloudflare" }}
    <script
      defer
      src="https://static.cloudflareinsights.com/beacon.min.js"
      data-cf-beacon='{"token": "{{ .Site.Params.cloudflareAnalyticsToken }}"}'>
    </script>
  {{ end }}
{{ end }}

Plausible Analytics Integration

Plausible is a paid, hosted analytics service with a focus on simplicity and privacy.

<!-- Plausible analytics -->
<script
  defer
  data-domain="yourdomain.com"
  src="https://plausible.io/js/script.js">
</script>

Custom Events with Plausible

<button onclick="plausible('Download', {props: {file: 'ebook.pdf'}})">
  Download eBook
</button>

Expected behavior: Plausible records the click as a custom event with the file property. The dashboard shows downloads alongside page views, giving you conversion tracking without cookies.

Self-Hosted Umami

Umami is an open-source analytics platform you deploy on your own infrastructure.

# docker-compose.yml — Umami deployment
version: '3'
services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:password@db:5432/umami
      APP_SECRET: your-secret-key
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: password
    volumes:
      - umami-data:/var/lib/postgresql/data

volumes:
  umami-data:

Umami Tracking Script

<script
  defer
  src="https://your-umami-instance.com/script.js"
  data-website-id="your-site-id">
</script>

Server-Side Log Analytics with Cloudflare

For zero JavaScript, use Cloudflare's edge log analytics:

# wrangler.toml — Enable edge analytics
name = "my-site"
type = "webpack"

[env.production]
  workers_dev = false
  routes = ["example.com/*"]

[analytics]
  enabled = true

Expected behavior: Cloudflare logs every HTTP request at the edge and aggregates the data into analytics dashboards. No JavaScript runs on the client, no cookies are set, and the data includes only what Cloudflare sees: request path, status code, user agent, country, and timing.

Common Errors

1. Analytics Script Blocking Page Load

Synchronous analytics scripts block page rendering. Always add async or defer attributes to analytics scripts. For critical analytics, use Cloudflare Web Analytics which operates at the edge without client scripts.

2. Double-Counting Page Views

If you add analytics to a Hugo partial that renders on both the default template and a custom template, the same page may fire the analytics script twice. Ensure the analytics partial is included only once in baseof.html.

3. Analytics Running in Development Mode

Analytics scripts should not fire during local development. Check if not .Site.IsServer in Hugo templates, or check location.hostname === 'localhost' in JavaScript before initializing analytics.

4. GDPR Compliance with Third-Party Hosting

Even privacy-first tools hosted by third parties (e.g., Plausible Cloud) may require a data processing agreement (DPA) under GDPR. Check each provider's DPA availability and configure data retention periods.

5. Ad Blockers Blocking Self-Hosted Analytics

Some ad blockers use pattern matching to block known analytics endpoints. Host your analytics on a subdomain (e.g., analytics.example.com) and use a reverse proxy to serve the script from your main domain if needed.

Practice Questions

1. What makes Cloudflare Web Analytics different from Google Analytics?

Cloudflare Web Analytics does not use cookies, does not require client-side JavaScript (when used at the edge), and does not collect personal data. It works at the CDN level by analyzing HTTP request logs.

2. Which analytics platforms can be self-hosted?

GoatCounter and Umami can be self-hosted. GoatCounter uses SQLite, while Umami requires PostgreSQL. Both are open source and provide full data ownership.

3. Why should analytics scripts use async or defer attributes?

These attributes prevent the analytics script from blocking page rendering. async loads the script in parallel and executes as soon as it downloads. defer loads in parallel but executes after the HTML is fully parsed.

4. How do you prevent analytics from firing during local development?

In Hugo, wrap the analytics partial with {{ if not .Site.IsServer }}. In client-side JavaScript, check if (location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') before initializing.

5. Challenge: Set up Cloudflare Web Analytics for a Hugo site deployed on Cloudflare Pages. Verify that page views appear in the dashboard. Then add GoatCounter as a secondary analytics tool and compare the numbers from both tools for the same traffic period. Document any discrepancies.

Mini Project: Privacy-First Analytics Dashboard

Build a complete analytics setup for a static site:

  1. Enable Cloudflare Web Analytics for edge-level measurement
  2. Add GoatCounter as a lightweight JavaScript-based tracker
  3. Create a Hugo partial that:
    • Conditionally loads analytics only in production
    • Supports multiple analytics providers via site config
    • Includes a doNotTrack check that respects browser DNT headers
  4. Build a privacy policy page that documents exactly what data is collected
  5. Compare the analytics data from both sources over one week

Configuration in hugo.toml:

[params]
  analytics = "goatcounter"
  goatcounterCode = "dodatech"
  cloudflareAnalyticsToken = "your-token"

Verify by publishing the site and checking:

  • Cloudflare Web Analytics dashboard shows page views
  • GoatCounter dashboard shows matching data
  • No cookies are set (verify with browser dev tools)
  • The analytics script does not load on localhost

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro