Skip to main content

How to Self-Host Plausible Analytics: Privacy-First Google Analytics 2026

·OSSAlt Team
plausibleanalyticsgoogle-analyticsprivacygdprself-hostingdocker2026

TL;DR

Plausible Analytics (AGPL 3.0, ~21K GitHub stars, Elixir + ClickHouse) is a lightweight, privacy-first web analytics tool. The tracking script is under 1KB (vs 45KB for Google Analytics 4), has no cookies, is GDPR-compliant without a consent banner, and collects only what you need — page views, referrers, goals, and device info. Self-hosted Plausible gives you the full product free. Plausible Cloud starts at $9/month for 10K pageviews.

Key Takeaways

  • Plausible: AGPL 3.0, ~21K stars, Elixir + ClickHouse — privacy-first, no cookies
  • 1KB script: Loads 45x faster than Google Analytics 4 (45KB)
  • GDPR without consent: No personal data stored, no cookies — no banner needed in most jurisdictions
  • ClickHouse: Time-series analytics database that scales to billions of events
  • Goals and events: Track conversions, button clicks, form submissions
  • Shared dashboards: Public or password-protected stats pages

Plausible vs Google Analytics vs Umami

FeaturePlausibleGoogle Analytics 4Umami
LicenseAGPL 3.0ProprietaryMIT
Script size~1KB~45KB~22KB
CookiesNoneYesNone
GDPR consent neededUsually noYesUsually no
Data ownershipYoursGoogleYours
RealtimeYesYesYes
Goals/EventsYesYesYes
FunnelsYesYesNo
User journeyNoYesNo
DatabaseClickHouseGoogle infraPostgreSQL
RAM (idle)~500MB~200MB

Part 1: Docker Setup

Plausible requires ClickHouse for analytics storage. The official repo provides a full Docker Compose setup:

# Download official config:
git clone https://github.com/plausible/community-edition plausible
cd plausible

The community edition includes docker-compose.yml and plausible-conf.env:

# docker-compose.yml (simplified view)
services:
  mail:
    image: bytemark/smtp:latest
    restart: always

  plausible_db:
    image: postgres:16-alpine
    restart: always
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=postgres

  plausible_events_db:
    image: clickhouse/clickhouse-server:24-alpine
    restart: always
    volumes:
      - event-data:/var/lib/clickhouse
      - event-logs:/var/log/clickhouse-server
      - ./clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro
      - ./clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro

  plausible:
    image: ghcr.io/plausible/community-edition:v2
    restart: always
    command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
    depends_on:
      - plausible_db
      - plausible_events_db
      - mail
    ports:
      - "8000:8000"
    env_file:
      - plausible-conf.env
# plausible-conf.env
BASE_URL=https://plausible.yourdomain.com
SECRET_KEY_BASE=<64-char-secret>   # openssl rand -base64 48
TOTP_VAULT_KEY=<32-byte-base64>    # openssl rand -base64 32
# Generate keys:
openssl rand -base64 48    # SECRET_KEY_BASE
openssl rand -base64 32    # TOTP_VAULT_KEY

docker compose up -d

Part 2: HTTPS with Caddy

plausible.yourdomain.com {
    reverse_proxy localhost:8000
}

Visit https://plausible.yourdomain.com → register your account.


Part 3: Add Your First Website

  1. + Add website in the dashboard
  2. Enter domain: yourdomain.com
  3. Get your snippet:
<script defer data-domain="yourdomain.com" src="https://plausible.yourdomain.com/js/script.js"></script>

Add to your site's <head>. That's it.


Proxy Plausible through your own domain to bypass ad blockers:

Next.js

// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/js/script.js',
        destination: 'https://plausible.yourdomain.com/js/script.js',
      },
      {
        source: '/api/event',
        destination: 'https://plausible.yourdomain.com/api/event',
      },
    ]
  },
}
<script defer data-domain="yourdomain.com" 
  data-api="/api/event"
  src="/js/script.js">
</script>

Caddy Proxy

yourdomain.com {
    # Proxy Plausible script through your domain:
    handle /js/script.js {
        reverse_proxy plausible.yourdomain.com
    }
    handle /api/event {
        reverse_proxy plausible.yourdomain.com
    }
    # ... rest of your site
}

Update the script tag:

<script defer data-domain="yourdomain.com"
  data-api="https://yourdomain.com/api/event"
  src="https://yourdomain.com/js/script.js">
</script>

Part 5: Goals and Events

Track custom events like button clicks, signups, or form submissions:

Script variant for custom events

<script defer data-domain="yourdomain.com" 
  src="https://plausible.yourdomain.com/js/script.tagged-events.js">
</script>

Auto-tracked CSS class events

<!-- Button click automatically tracked as "Signup" goal: -->
<button class="plausible-event-name=Signup">
  Sign Up Free
</button>

<!-- With properties: -->
<button class="plausible-event-name=Purchase plausible-event-plan=pro">
  Upgrade to Pro
</button>

JavaScript API

// Track any event programmatically:
plausible('Signup', { props: { plan: 'pro', method: 'email' } })

// Track after form submit:
document.getElementById('signup-form').addEventListener('submit', function() {
  plausible('Form Submit')
})

Create Goals in Dashboard

  1. Site Settings → Goals → Add Goal
  2. Type: Pageview (e.g., /thank-you) or Custom Event (e.g., Signup)
  3. Goal appears in dashboard with conversion rate

Part 6: Funnels

Track multi-step conversion funnels:

  1. Site Settings → Funnels → Create Funnel
  2. Add steps:
    • Step 1: Pageview → /pricing
    • Step 2: Pageview → /signup
    • Step 3: Custom event → Signup
  3. See where users drop off in the funnel visualization

Part 7: Shared Dashboards

Make your stats public or share with password:

  1. Site Settings → Visibility → Make dashboard public
  2. Or: Shared links → Create link with optional password

Share URL: https://plausible.yourdomain.com/yourdomain.com


Part 8: API Access

# Get site stats:
curl "https://plausible.yourdomain.com/api/v1/stats/aggregate?site_id=yourdomain.com&period=30d&metrics=visitors,pageviews,bounce_rate" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Real-time visitors:
curl "https://plausible.yourdomain.com/api/v1/stats/realtime/visitors?site_id=yourdomain.com" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Breakdown by page:
curl "https://plausible.yourdomain.com/api/v1/stats/breakdown?site_id=yourdomain.com&period=30d&property=event:page" \
  -H "Authorization: Bearer YOUR_API_KEY"

Multi-Site Setup

One Plausible instance can host analytics for multiple sites:

  1. + Add website → enter each domain
  2. Each gets its own dashboard and tracking snippet
  3. One admin account manages all sites

Maintenance

# Update Plausible:
docker compose pull
docker compose up -d

# Backup:
# PostgreSQL (config data):
docker exec plausible_plausible_db_1 pg_dump -U postgres plausible > plausible-db-$(date +%Y%m%d).sql

# ClickHouse (events data):
tar -czf clickhouse-backup-$(date +%Y%m%d).tar.gz \
  $(docker volume inspect plausible_event-data --format '{{.Mountpoint}}')

# Logs:
docker compose logs -f plausible

See all open source analytics tools at OSSAlt.com/alternatives/google-analytics.

Comments