Ready to dive into self-hosted web analytics?

Well, with Swetrix you will get something more, you will understand the story behind your customers.

In this post, you’ll be setting up Swetrix, a privacy-focused, cookie-less, open source analytics platform.

Discover how to deploy the Nest.js backend, Remix frontend, and configure MySQL & Clickhouse.

Master selfhosting best practices for ultimate data ownership and start collecting your website’s actionable insights.

Project Overview: Swetrix

Swetrix is an open source, privacy-centric web analytics suite offering features like real-time visitor tracking, session recordings, pageflow analysis, and customizable dashboards.

Built with a Nest.js backend alongside MySQL and Clickhouse databases, and a Remix-based frontend, Swetrix delivers enterprise-grade analytics without compromising data ownership.

Swetrix Login

Why Swetrix Matters for Self-Hosting Enthusiasts

  • ⚙️ Streamlined setup with Docker & Compose
  • 🔒 Full data privacy & cookie-less tracking (forget about the cookie banner)
  • 🚀 Scalable architecture using MySQL & Clickhouse
  • Also can measure your page performance!
  • 🌐 Extensible modules: authentication, integrations, and custom metrics
The Swetrix Analytics Source Code

And you get interesting features, like funnels or even an open source captcha widget.

Swetrix CAPTCHA is a fully open source, cookieless and privacy-friendly CAPTCHA service. It is designed to be used on websites and web applications to prevent bots from performing automated actions.

The CAPTCHA challenge is presented to the user in the form of sequence of letters and numbers. T

Swetrix Tech Overview

Swetrix comprises a modular Nest.js monorepo in TypeScript and a Remix + React frontend styled with Tailwind CSS.

The backend leverages TypeORM for MySQL ORM, a Clickhouse client for analytics, Redis for caching, and integrates Sentry for observability.

On the front, React Router-based routes serve dynamic dashboards with D3.js, Billboard.js, and Nivo for visualizations.

Linters and static analysis tools (ESLint, TypeScript, ts-prune) enforce code quality.

Module Descriptions

  • backend/apps/cloud: Core API server handling authentication, analytics endpoints, integrations, and mailing.
  • backend/apps/community: Community Edition variant with simplified feature set.
  • backend/migrations: Database migration scripts for MySQL and Clickhouse.
  • web/app: Remix routes, components, and styles for the UI dashboard.
  • web/public: Static assets, including images and manifest files.
  • blog-posts: Markdown-driven content for the Swetrix blog.

Key Concepts and Algorithms

Swetrix employs sessionization algorithms to group user events into coherent sessions.

Custom funnel analysis is implemented by aggregating event streams in Clickhouse.

UA parsing leverages uaparser libraries for browser/device insights.

Data transformers normalize raw event payloads, and sampling strategies ensure cost-effective Clickhouse queries.

About Swetrix Dependencies ⏬
  • Nest.js (TypeScript API framework)
  • TypeORM & mysql2 (MySQL ORM)
  • @clickhouse/client (Clickhouse connector)
  • Remix & React Router (Frontend framework)
  • Tailwind CSS (Utility-first styling)
  • D3.js, Billboard.js, Nivo (Data visualization)
  • Redis, dotenv, bcrypt, passport (Auth & caching)
  • ESLint, Prettier, TypeScript (Static code analysis)

Deployment: Self-hosting Swetrix

Swetrix provides official self-hosting docs, but you can simply deploy locally with Docker Compose

Deploy with Docker Compose

We can use a docker-compose as the only configuration required to SelfHost Swetrix.

How to SelfHost Swetrix ⏬
services:
  # This is Swetrix user interface application, it's used to display the analytics data, render charts, etc.
  swetrix: #https://docs.swetrix.com/selfhosting/how-to
    image: swetrix/swetrix-fe:v3.3.1 #https://github.com/swetrix/selfhosting
    restart: always
    depends_on:
      - swetrix-api
    ports:
      - '80:3000'
    environment:
      - API_URL=${API_URL}
    healthcheck:
      test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/ping || exit 1"]
      interval: 30s
      start_period: 15s

  # This is Swetrix API, it's purpose is to collect incoming analytical events and serve the data to the UI
  swetrix-api:
    image: swetrix/swetrix-api:v3.3.1
    restart: always
    container_name: swetrix-api
    ports:
      - '8080:5005'
    environment:
      # Configurable with .env file
      - JWT_ACCESS_TOKEN_SECRET=${JWT_ACCESS_TOKEN_SECRET}
      - JWT_REFRESH_TOKEN_SECRET=${JWT_REFRESH_TOKEN_SECRET}
      - EMAIL=${EMAIL}
      - PASSWORD=${PASSWORD}
      - API_KEY=${API_KEY}
      - IP_GEOLOCATION_DB_PATH=${IP_GEOLOCATION_DB_PATH}
      - DEBUG_MODE=${DEBUG_MODE}
      - CLOUDFLARE_PROXY_ENABLED=${CLOUDFLARE_PROXY_ENABLED}

      # Redis and Clickhouse are required for the API to work
      - REDIS_HOST=redis
      - CLICKHOUSE_HOST=http://clickhouse
    links:
      - 'redis'
      - 'clickhouse'
    depends_on:
      redis:
        condition: service_healthy
      clickhouse:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5005/ping || exit 1"]
      interval: 30s
      start_period: 15s

  redis:
    image: redis:7.2-alpine
    restart: always
    environment:
      - REDIS_PORT=6379
      - REDIS_USER=default
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      interval: 30s
      start_period: 1m

  clickhouse:
    image: clickhouse/clickhouse-server:24.10-alpine
    container_name: clickhouse
    environment:
      - CLICKHOUSE_DATABASE=analytics
      - CLICKHOUSE_USER=default
      - CLICKHOUSE_PORT=8123
      - CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "wget --no-verbose --tries=1 -O - http://127.0.0.1:8123/ping || exit 1"]
      interval: 30s
      start_period: 1m
    restart: always
    cap_add:
      - SYS_NICE
    volumes:
      - swetrix-events-data:/var/lib/clickhouse
      # Disable logging
      - ./clickhouse/reduce-logs.xml:/etc/clickhouse-server/config.d/reduce-logs.xml:ro
      - ./clickhouse/disable-user-logging.xml:/etc/clickhouse-server/users.d/disable-user-logging.xml:ro

      # Reduce RAM usage
      - ./clickhouse/preserve-ram-config.xml:/etc/clickhouse-server/config.d/preserve-ram-config.xml:ro
      - ./clickhouse/preserve-ram-user.xml:/etc/clickhouse-server/users.d/preserve-ram-user.xml:ro
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
volumes:
  swetrix-events-data:
    driver: local

swetrix-api - the main API server running on port 8080 by default swetrix-fe - the frontend server running on port 80 by default Redis server for caching Clickhouse server for analytics and transactional data

After starting the container you can access the dashboard at http://{host}:80.

You will require to setup a .env with your desired user/pass among other variables.

That can also be done with the configure.sh script, but these are the ones you need:

# Swetrix Frontend configuration
API_URL=localhost

# Swetrix API configuration
JWT_ACCESS_TOKEN_SECRET=createonetoken
JWT_REFRESH_TOKEN_SECRET=somejwttoken
[email protected]
PASSWORD=somecoolpassword
CLOUDFLARE_PROXY_ENABLED=false
DEBUG_MODE=false
API_KEY=
IP_GEOLOCATION_DB_PATH=


# Keep these empty unless you manually set passwords for your databases
REDIS_PASSWORD=
CLICKHOUSE_PASSWORD=

In this compose for Swetrix, we have few services that will be started together:

sudo docker compose up -d
  • db: MySQL storage for core data.
  • clickhouse: High-performance analytics database.
  • redis: Cache and rate-limiting store.
  • backend: Nest.js API server.
  • frontend: Remix-based UI server.

Once running, you can navigate to the frontend port and login into your dashboard as per your .env configured admin and pass:

Swetrix Dashboard

Configuration

Adjust .env or Compose environment variables to suit your domain, secrets, and resource constraints.

Ensure JWT_SECRET keys are secure and set OIDC_ENABLED or external integration flags as needed.

The JS code you will need to embed it into your site, looks like:

<script src="https://swetrix.org/swetrix.js" defer></script>
<script>
  document.addEventListener('DOMContentLoaded', function() {
    swetrix.init('23IczH6bvFrR', {
      apiURL: 'http://localhost:8080/log',
    })
    swetrix.trackViews()
  })
</script>

<noscript>
  <img
    src="http://localhost:8080/log/noscript?pid=23IczH6bvFrR"
    alt=""
    referrerpolicy="no-referrer-when-downgrade"
  />
</noscript>

Swetrix JS Snippet


Conclusion

In this guide, we explored how to self-host Swetrix, covering project architecture, modules, dependencies, and a Docker-based deployment.

With Swetrix, you gain full data control, privacy, and extensible analytics: not just visitor counts, but.

As you could expect, Swetrix related services are not the most lightweight with ~500mb RAM usage

docker stats $(docker-compose -f compose.yaml ps -q)

Swetrix Logs

Latest Releases

v3.3.1: Patch release with minor bug fixes and performance tweaks. v3.3.0: Introduced custom event analytics and enhanced session visualization. v3.2.x: Improved UI components, i18n support, and dashboard optimizations.

Alternative self-hosted platforms to Swetrix could be: Umami, Tianji