Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

tidemeter/tidemeter

Open more actions menu

Repository files navigation

TideMeter

Self-hosted, privacy-focused web analytics for developers and small teams

License: MIT Built with Next.js PayloadCMS Docker Hub

Website · Docs · Live Demo · Docker Hub


TideMeter Dashboard

Features

  • Privacy-focused — no cookies, no fingerprinting, GDPR-friendly by design
  • Lightweight tracker — ~1.5 KB gzipped, zero dependencies
  • Real-time dashboard — interactive charts powered by Recharts
  • Funnels & journeys — built-in conversion funnels and visitor path visualization
  • Multiple database support — PostgreSQL, ClickHouse, or SQLite for analytics storage
  • Built on PayloadCMS 3 + Next.js 16 — modern, extensible full-stack architecture
  • Docker image on Docker Hubdocker pull tidemeter/tidemeter and you're running
  • SPA support — automatic history API interception for single-page apps
  • Custom event tracking — track signups, clicks, purchases, anything
  • Team collaboration — multi-user with role-based access
  • Public dashboards — share read-only analytics views without requiring login
  • REST API — query your analytics data programmatically

Quick Start

Option A: Docker Hub Image (Fastest)

Pull the pre-built image from Docker Hub — no cloning, no build step:

# Start a PostgreSQL database (skip if you already have one)
docker run -d \
  --name tidemeter-db \
  -p 5432:5432 \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=tidemeter \
  postgres:16-alpine

# Pull and run TideMeter
docker run -d \
  -p 3700:3700 \
  -e DATABASE_URL="postgresql://postgres:postgres@host.docker.internal:5432/tidemeter" \
  -e PAYLOAD_SECRET="your-secret-key-minimum-32-characters" \
  -e NEXT_PUBLIC_APP_URL="http://localhost:3700" \
  tidemeter/tidemeter:latest

Browse all available tags on Docker Hub → tidemeter/tidemeter.

Option B: Docker Compose

Clone the repo and bring up everything (app + database) with one command:

git clone https://github.com/tidemeter/tidemeter.git
cd tidemeter
cp .env.example .env
# Edit .env — at minimum, set PAYLOAD_SECRET and SESSION_SALT_SECRET
docker compose -f docker/docker-compose.yml up -d

Visit http://localhost:3700 to create your admin account and add your first website.

Full documentation: tidemeter.com/docs

Development Setup

For contributors and anyone who wants to build from source.

Prerequisites

Install & Run

git clone https://github.com/tidemeter/tidemeter.git
cd tidemeter
pnpm install

cp .env.example .env
# Edit .env — point DATABASE_URL to your PostgreSQL instance

pnpm dev        # Start dev server with Turbopack HMR
pnpm build      # Production build
pnpm test       # Run tests
pnpm lint       # Lint

The dev server starts at http://localhost:3700.

Adding the Tracker

Add the tracking script to any website you want to monitor. The data-website-id comes from your TideMeter dashboard after adding a site.

<script
  defer
  data-website-id="YOUR_WEBSITE_ID"
  src="https://your-tidemeter-domain.com/t.js"
></script>

Script Attributes

Attribute Description Default
data-website-id (required) Website ID from your dashboard
data-host-url Override the analytics endpoint URL Script origin
data-auto-track Auto-track pageviews true
data-respect-dnt Respect the Do-Not-Track header true
data-domains Comma-separated list of allowed domains All domains

Custom Events

// Track a named event
tidemeter.track("signup", { plan: "pro" });

// Track a pageview manually (when auto-track is disabled)
tidemeter.track();

Architecture

TideMeter is a Turborepo monorepo with a clear separation between the application layer and the analytics data layer.

┌─────────────────────────────────────────────┐
│                  apps/web                   │
│        Next.js 16 + PayloadCMS 3            │
│     (dashboard, admin, API routes)          │
├──────────────┬──────────────┬───────────────┤
│ @tidemeter/  │ @tidemeter/  │ @tidemeter/   │
│   tracker    │  analytics   │      ui       │
│  (t.js)      │ (Drizzle ORM)│  (components) │
└──────────────┴──────┬───────┴───────────────┘
                      │
          ┌───────────┼───────────┐
          │           │           │
      PostgreSQL  ClickHouse   SQLite
  • Dual database design — PayloadCMS manages application data (users, sites, settings) in PostgreSQL; analytics events are stored in a separate database that can be PostgreSQL, ClickHouse, or SQLite.
  • Repository pattern — the @tidemeter/analytics package defines an AnalyticsRepository interface with swappable adapters (postgres, clickhouse), selected at runtime via the ANALYTICS_DB_TYPE env var.
  • Tracker@tidemeter/tracker compiles to a single t.js file via Rollup, served as a static asset.

Configuration

All configuration is done through environment variables. Copy .env.example to .env and adjust:

Variable Description Default
DATABASE_URL PostgreSQL connection string for PayloadCMS postgresql://tidemeter:tidemeter@localhost:5432/tidemeter
PAYLOAD_SECRET Secret for PayloadCMS auth (min 32 chars)
ANALYTICS_DB_TYPE Analytics storage engine: postgresql, clickhouse, sqlite postgresql
ANALYTICS_DATABASE_URL Connection string for analytics DB (PostgreSQL) Same as DATABASE_URL
CLICKHOUSE_URL ClickHouse HTTP endpoint http://localhost:8123
CLICKHOUSE_DATABASE ClickHouse database name tidemeter_analytics
ANALYTICS_SQLITE_PATH Path to SQLite file (when using SQLite) ./data/analytics.db
NEXT_PUBLIC_APP_URL Public URL of the application http://localhost:3700
SESSION_SALT_SECRET Secret for hashing visitor IDs (rotated daily)
GEOIP_DB_PATH Path to MaxMind GeoLite2-City.mmdb (optional)

See .env.example for the full annotated reference.

ClickHouse Mode

For high-traffic sites, use ClickHouse as the analytics storage engine. The override compose file adds a ClickHouse container and reconfigures the app:

docker compose -f docker/docker-compose.yml -f docker/docker-compose.ch.yml up -d

This starts PostgreSQL (for PayloadCMS) + ClickHouse (for analytics) + the TideMeter app.

Deployment

TideMeter runs anywhere Docker runs. Minimum requirements: 1 CPU core, 1 GB RAM.

For production, place TideMeter behind a reverse proxy (Nginx, Caddy, Traefik) for HTTPS. See the Deployment Guide for Nginx/Caddy examples, Railway, Fly.io, and DigitalOcean instructions.

Production Checklist

  • NODE_ENV=production
  • PAYLOAD_SECRET — strong random value (32+ characters)
  • SESSION_SALT_SECRET — strong random value
  • NEXT_PUBLIC_APP_URL — your actual domain
  • HTTPS via reverse proxy
  • Database backups scheduled

Tech Stack

Layer Technology
Framework Next.js 16
CMS PayloadCMS 3
Styling Tailwind CSS 4
Charts Recharts
State React Hooks
Analytics ORM Drizzle ORM
Build Turborepo + pnpm
Runtime Node.js 22 (Alpine)
Docker Multi-stage Dockerfile + Compose

Project Structure

tidemeter/
├── apps/
│   └── web/                 # Next.js 16 + PayloadCMS application
├── packages/
│   ├── analytics/           # Analytics data layer (Drizzle ORM, adapters)
│   │   └── src/
│   │       ├── adapters/    # postgres, clickhouse implementations
│   │       ├── schema/      # Drizzle table definitions
│   │       ├── types.ts     # Core interfaces (AnalyticsRepository, etc.)
│   │       └── factory.ts   # Adapter factory
│   ├── tracker/             # Lightweight tracking script (Rollup → t.js)
│   ├── ui/                  # Shared UI components
│   └── tsconfig/            # Shared TypeScript configs
├── docker/
│   ├── Dockerfile           # Multi-stage production build
│   ├── docker-compose.yml   # Default stack (PostgreSQL)
│   ├── docker-compose.ch.yml # ClickHouse override
│   └── clickhouse/          # ClickHouse init scripts
├── turbo.json               # Turborepo pipeline config
├── pnpm-workspace.yaml      # pnpm workspace definition
└── package.json             # Root scripts (dev, build, test, lint)

License

MIT © 2026 TideMeter

Morty Proxy This is a proxified and sanitized view of the page, visit original site.