Skip to content

A self-hostable, privacy-first web analytics service in a single Go binary.

License

Notifications You must be signed in to change notification settings

PascaleBeier/hitkeep

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

165 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HitKeep

Web Analytics in a single binary.

License: MIT Go Version Docker Image Documentation

HitKeep is a self-hostable, privacy-first web analytics platform designed for radical simplicity without sacrificing performance.

Unlike other solutions that require you to manage a complex stack (PostgreSQL, Redis, ClickHouse, Nginx), HitKeep runs as a single, self-contained executable. It embeds a high-performance OLAP database (DuckDB) and a distributed message queue (NSQ) directly into the binary.

dashboard

HitKeep Cloud is coming!

Prefer a managed solution and funding Open Source? Join the Early Access Waitlist for fully managed, data-sovereign and privacy-first analytics in the EU or US.

Join the Waitlist →

Documentation

Visit hitkeep.com for the complete documentation, including:


Features

  • Single Binary Runtime: No external database, queue, or cache to provision.
  • Embedded DuckDB + NSQ: Columnar analytics storage with in-process burst buffering.
  • Privacy-First Tracking: Cookie-less by default, bot filtering, DNT support, optional sendBeacon disable.
  • Analytics Coverage: Traffic overview, raw hits, events, goals, funnels, and UTM attribution fields.
  • Security & Auth: JWT sessions, remember-me tokens, password reset, TOTP MFA, and WebAuthn passkeys.
  • RBAC & Team Management: Instance roles and per-site roles with delegated permissions.
  • API Clients: Create scoped API tokens for automation and integrations.
  • Share Links: Read-only dashboard sharing for stakeholders.
  • Data Lifecycle: Per-site retention, scheduled archival to Parquet, and on-demand user/site takeout exports.
  • Ops Endpoints: Health/readiness probes and versioned OpenAPI endpoint.
  • Cluster Support: Optional leader/follower topology via memberlist gossip.

Quick Start

Binary

Head over to Releases and download the binary for your system, for example:

$ wget https://github.com/PascaleBeier/hitkeep/releases/latest/download/hitkeep-linux-arm64
$ chmod +x hitkeep-linux-arm64

Running

Security Tip: Avoid passing secrets (like JWT_SECRET) via flags in production, as they appear in process lists. Use the HITKEEP_JWT_SECRET environment variable instead.

# Set secret via ENV, config via flags
$ export HITKEEP_JWT_SECRET="your-secure-random-string"
$ ./hitkeep-linux-arm64 -public-url="https://analytics.example.org"
# to use your public ip
$ ./hitkeep-linux-arm64 -public-url="http://1.2.3.4:8080"

Docker

Also see examples.

  1. Create a compose.yml file:
services:
  hitkeep:
    image: ghcr.io/pascalebeier/hitkeep:latest
    container_name: hitkeep
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - hitkeep_data:/var/lib/hitkeep/data
    environment:
      # Securely pass secrets via ENV
      - HITKEEP_JWT_SECRET=replace-this-with-a-long-random-string
    command:
      # IMPORTANT: Set this to your actual public domain in production
      - "-public-url=http://localhost:8080"

volumes:
  hitkeep_data: {}
  1. Run it:

    docker compose up -d
  2. Open http://localhost:8080 to create your admin account.

Tracking Snippet

Once your instance is running and you have created a website in the dashboard, add this script to the <head> of your website:

<script async src="https://your-hitkeep-instance.com/hk.js"></script>

Do-Not-Track

To ignore DNT:

<script
  async
  src="https://your-hitkeep-instance.com/hk.js"
  data-collect-dnt="true"
></script>

fetch over sendBeacon

To use fetch over navigator.sendBeacon:

<script
  async
  src="https://your-hitkeep-instance.com/hk.js"
  data-collect-dnt="true"
  data-disable-beacon="true"
></script>

Custom events

Emit custom events from your app:

<script>
  window.hk = window.hk || {};
  window.hk.event?.("signup", { plan: "pro", source: "landing-page" });
</script>

Configuration

HitKeep is configured via command-line flags or environment variables. Flags take precedence.

Most Relevant Production Settings

Flag Environment Variable Why it matters most in production
-public-url HITKEEP_PUBLIC_URL Used for JWT issuer/audience and CORS behavior.
-jwt-secret HITKEEP_JWT_SECRET Signs auth tokens; must be stable and secret across restarts.
-db HITKEEP_DB_PATH Controls where hitkeep.db is stored/persisted.
-archive-path HITKEEP_ARCHIVE_PATH Stores takeout and retention archives.
-trusted-proxies HITKEEP_TRUSTED_PROXIES Controls whether forwarded headers are trusted for real IP and GeoIP.
-retention-days HITKEEP_DATA_RETENTION_DAYS Default retention policy for new sites.

Notes on Recent/Important Defaults

  • -trusted-proxies now defaults to * (trust-all CIDRs). Set this explicitly in production to your reverse proxy/load balancer CIDRs.
  • -jwt-secret is auto-generated if omitted. That is fine for local dev but will invalidate sessions on restart unless you persist a fixed secret.

General Settings

Flag Environment Variable Default Description
-public-url HITKEEP_PUBLIC_URL http://localhost:8080 Public URL for JWT issuer/audience and CORS. Set this to your real public domain.
-jwt-secret HITKEEP_JWT_SECRET (random) Secret key for signing auth tokens. Use a fixed strong value in production.
-http HITKEEP_HTTP_ADDR :8080 Address to bind the HTTP server to.
-healthcheck - false Run one-shot healthcheck mode and exit (useful for container probes).
-db HITKEEP_DB_PATH hitkeep.db Path to the DuckDB database file.
-log-level HITKEEP_LOG_LEVEL info Logging verbosity (debug, info, warn, error).

Data Management

Flag Environment Variable Default Description
-archive-path HITKEEP_ARCHIVE_PATH archive Directory for exports, rollups, and archival artifacts.
-retention-days HITKEEP_DATA_RETENTION_DAYS 365 Default data retention window (days) for newly created sites.

Mailer (SMTP)

Flag Environment Variable Default Description
-mail-driver HITKEEP_MAIL_DRIVER smtp Mail driver to use (smtp or log).
-mail-host HITKEEP_MAIL_HOST SMTP Server Hostname (e.g., smtp.postmarkapp.com).
-mail-port HITKEEP_MAIL_PORT 587 SMTP Server Port.
-mail-username HITKEEP_MAIL_USERNAME SMTP Username.
-mail-password HITKEEP_MAIL_PASSWORD SMTP Password.
-mail-encryption HITKEEP_MAIL_ENCRYPTION tls Encryption mode: tls (STARTTLS), ssl (Implicit), or none.
-mail-insecure-skip-verify HITKEEP_MAIL_INSECURE_SKIP_VERIFY false Skip TLS certificate validation (useful for self-signed certs).
-mail-from-address HITKEEP_MAIL_FROM_ADDRESS hitkeep@localhost The email address messages are sent from.
-mail-from-name HITKEEP_MAIL_FROM_NAME HitKeep The name displayed to the recipient.

Rate Limiting

Flag Environment Variable Default Description
-ingest-rate HITKEEP_INGEST_RATE_LIMIT 20.0 Rate limit for /ingest (req/sec/ip).
-ingest-burst HITKEEP_INGEST_BURST 40 Burst size for /ingest.
-api-rate HITKEEP_API_RATE_LIMIT 10.0 Rate limit for general API endpoints (req/sec/ip).
-api-burst HITKEEP_API_BURST 20 Burst size for general API.
-auth-rate HITKEEP_AUTH_RATE_LIMIT 2.0 Rate limit for login/signup (req/sec/ip).
-auth-burst HITKEEP_AUTH_BURST 5 Burst size for login/signup.

Trusted Proxies

Use this when HitKeep is behind a reverse proxy or load balancer and you want to trust forwarded headers. This affects both rate limiting and GeoIP resolution.

Flag Environment Variable Default Description
-trusted-proxies HITKEEP_TRUSTED_PROXIES "*" Comma-separated trusted proxy CIDRs or * (trust all). Used for client IP and GeoIP resolution.

Behavior:

  • * trusts forwarding headers from any direct peer.
  • CIDR list trusts forwarding headers only when the direct connection IP is in the trusted list.
  • Empty disables trusted proxy behavior and uses the direct remote address.

Clustering & Internals

Flag Environment Variable Default Description
-name HITKEEP_NODE_NAME hostname-timestamp Unique name for this node in the cluster.
-bind HITKEEP_BIND_ADDR 0.0.0.0:7946 Bind address for cluster gossip (Memberlist).
-join HITKEEP_JOIN_ADDR "" Address of a peer node to join.
-nsq-tcp-address HITKEEP_NSQ_TCP_ADDRESS 127.0.0.1:4150 Address of the internal embedded NSQ TCP.
-nsq-http-address HITKEEP_NSQ_HTTP_ADDRESS 127.0.0.1:4151 Address of the internal embedded NSQ HTTP.

FAQ

How much data storage will I need?

As of now, without any parqueting, you can expect to store 1 Million Raw Hits per ~120MB.

Architecture

HitKeep bridges the gap between simple log analyzers (like GoAccess) and enterprise analytics (like Umami/Plausible).

  1. Ingestion: Requests hit the Go HTTP server.
  2. Buffering: Events are published to an embedded NSQ topic (hits) in memory. This decouples the API from the database write speed.
  3. Storage: An internal consumer creates micro-batches and writes them to DuckDB, a columnar database that lives in a single file but offers OLAP performance comparable to ClickHouse.
  4. Clustering: Nodes communicate via Gossip protocol. The Leader node handles database writes, while Follower nodes proxy ingestion traffic to the leader.

Development

Prerequisites

  • Go 1.26+
  • Node.js 24+
  • Make

Build from source

# Clone the repo
git clone https://github.com/pascalebeier/hitkeep.git
cd hitkeep

# Build frontend and backend
make build

# Run the binary
./hitkeep

Changelog

We use SemVer and Conventional Commits.

See CHANGELOG.md.

License

Distributed under the MIT License. See LICENSE for more information.

About

A self-hostable, privacy-first web analytics service in a single Go binary.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors 2

  •  
  •