openanalytics README

The project's README from github.com/OpenLabs-so/openanalytics. As one markdown file: README.md.

OpenAnalytics

Open-source, privacy-first web analytics. One lightweight tracker script, no cookies, no cross-site profiles, aggregate-only reads — self-hostable on your own hardware under AGPL-3.0.

A hosted instance runs at getopen.so, operated by the authors: the same code, someone else's servers.

The Overview screen: visitors, pageviews, bounce rate, average visit and
revenue across a day, with top pages, referrers and revenue
underneath

▶ Watch the dashboard in motion, a tour of these same screens on YouTube.

What is in this repository

The product, as one pnpm monorepo:

App Role
apps/tracker The browser snippet — a few KiB, with a byte budget CI enforces
apps/collector Ingest: validates, sanitizes, rate-limits, enqueues
apps/worker Drains the queue into ClickHouse; sessions, rollups, exports, mail, deletions
apps/api Control plane: auth, sites, keys, sharing, event definitions, funnels, widgets, revenue, AI assistant, MCP
apps/query-gateway The only process allowed to read ClickHouse; verifies signed query envelopes
apps/realtime The SSE stream behind the live dashboard
apps/web The dashboard (Next.js)
apps/cli oa — site setup, stats, device-flow login
packages/* domain, postgres (+migrations), clickhouse (+migrations), redis, auth, contracts (OpenAPI), observability, integrations, migrations, testkit

Stores: Postgres (control plane), ClickHouse (events and rollups), Valkey ×2 (one durable event queue, one losable realtime cache).

What it does, in one list: page views, custom and attribute-driven events, sessions, web vitals, funnels, per-site retention, embeddable widgets, public share links, revenue analytics from your Stripe account, CSV/JSON import and export, an MCP server, and a CLI.

Who is on the site now, from a presence cache rather than a table scan. Names are generated per visitor and mean nothing outside the day they were minted.

The realtime screen: five visitors online with the page each is on, and
everyone seen in the last 24 hours below them

Where one visitor went, session by session. The identity behind a trail is a salted hash that rotates every night, so the trail is as long as a visit and never as long as a person.

One visitor's trail: two visits, one arrived direct and one from X, each
listing the pages opened inside it

Where they are, at city level and only when a site opts in. The lookup runs against a database on your own disk and never leaves the host.

A globe with visitors placed on it, one each in eastern Europe, north Africa,
the Middle East and South America

Architecture rules CI enforces, not conventions:

Self-hosting

SELF-HOSTING.md is the guide: a generator script, one docker compose up -d, automatic TLS, and an explanation of every secret and every failure mode. Requirements are a Linux host with Docker, four DNS records, about 4 GB of RAM and 25 GB of free disk.

Installing is a pull, not a build. A release publishes ten images to ghcr.io/openlabs-so/openanalytics, so a fresh host is a few minutes and needs no toolchain on it.

Point four names at the host before you start. Certificates are issued on the first boot and issuance fails without them, half an hour later and nowhere near the cause:

app.example.com   api.example.com   c.example.com   rt.example.com
git clone https://github.com/OpenLabs-so/openanalytics
cd openanalytics
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"   # newest release, not main
cd infra/selfhost
./generate-secrets.sh --domain example.com --email [email protected] --with-geoip
docker compose pull && docker compose up -d
# then open https://app.example.com and create the first account

The checkout is where the version is chosen, and it is chosen once. The generator reads the tag back out of the tree it is standing in and points .env at that release's images, printing which it picked and why; on a branch, on main, or with no git at all it writes the build defaults instead. That is not a convenience — the compose file, the env templates and the migrations ship with the images, so a release's images against another tree is a configuration nobody has tested.

Images are amd64. On arm64, or to run a branch, build the ten here instead: same compose file, one flag, about ten minutes and swap on a 4 GB box. Later, ./upgrade.sh moves between releases and takes the snapshot ./rollback.sh needs, because migrations do not go down: the way back is a restore, and a restore discards what arrived after the upgrade. It tells you that before it starts, not at rollback time when you no longer have a choice. RELEASING.md is what a version number here means.

To run it from source instead — for development, or to slot the services into infrastructure you already have — follow Running from source. The order matters and one obvious order does not work: the migration runners are compiled output, so pnpm run build comes before pnpm run migrate:postgres.

infra/selfhost/env/*.env.example documents every variable each service reads, and there is one file per service on purpose — the environment schema forbids some keys to some services, so a single shared .env cannot be correct. The AI assistant (OPENAI_API_KEY) and object storage are optional: unset, those surfaces disable themselves and everything else runs.

Run the test suite the way CI does:

pnpm run test          # unit + contract + tracker, no infrastructure needed
pnpm run verify        # everything CI checks, including boundaries and the size budget

Privacy model

No cookies, no fingerprinting, no cross-site identifiers. Visitor identity is a daily-rotating salted hash; raw IP addresses are never stored. Do Not Track and Global Privacy Control are honored at the collector, before anything is written. City-level geolocation is opt-in per site.

Geolocation is resolved locally against a database on your own disk — no lookup ever leaves the host. None is bundled (a 60 MB download, and stale within a month); infra/selfhost/geoip/fetch-dbip.sh downloads one.

IP Geolocation by DB-IP — https://db-ip.com — used under CC BY 4.0.

Contributing

Pull requests are merged here, with your name on the commit. This repository used to receive periodic exports from a private monorepo, and a merged PR was flattened by the next one; that ended in August 2026. A bot asks you to sign the CLA once — it is not an assignment, you keep your copyright — and there is no DCO sign-off on top of it.

CONTRIBUTING.md has the setup, the ground rules CI enforces, and where to start. Discussions are for questions and for ideas worth talking through first.

Security reports: SECURITY.md — please not a public issue.

License and trademark

Code: AGPL-3.0. If you run a modified OpenAnalytics as a network service, the AGPL requires you to offer your modified source to its users.

The "OpenAnalytics" name and the hosted service's domain identify the instance its authors operate and are not part of the license grant. A self-hosted instance runs the software, not the brand.

openanalytics (OpenLabs-so/openanalytics)

Searching Database…

这是什么?OpenAnalytics 是一个开源、隐私优先、无 Cookie 的网站分析平台,带有收入归因功能和内置的 MCP 服务器。你可以在 AGPL-3.0 协议下自托管它,或使用作者在 getopen.so 上运营的托管实例。
这是一个应用还是一堆服务?它是一个 pnpm monorepo,包含多个服务:tracker 脚本、collector、worker、api、query-gateway、实时 SSE 流、一个 Next.js 仪表盘,以及一个名为“oa”的 CLI,底层由 Postgres、ClickHouse 和两个 Valkey 实例支撑。
怎么把它跑起来?按照 SELF-HOSTING.md 操作:先运行生成脚本,再执行 'docker compose up -d'。发行版会向 ghcr.io 发布十个预构建镜像,所以你不需要构建工具链,TLS 证书会在首次启动时自动签发。
自托管之前我需要准备什么?一台装有 Docker 的 Linux 主机、开始前指向该主机的四条 DNS 记录、大约 4 GB 内存和 25 GB 可用磁盘空间。
预构建安装包在任何机器上都能用吗?发布的镜像只有 amd64 版本。在 arm64 上,或者想运行分支而非正式标签版本时,你得用同一个 compose 文件自己构建这十个镜像,大约需要十分钟。
我可以在哪里运行它?它设计为通过 Docker 在 Linux 主机上自托管,并配有 Next.js 网页仪表盘;作者也运营了一个托管版本,这样你就不用自己运行任何东西。
它如何避免像 Google Analytics 那样追踪访客?没有 Cookie,也没有指纹采集。访客身份是一个每晚轮换的加盐哈希,原始 IP 地址从不存储,而且 collector 在写入任何数据之前就会遵循 Do Not Track / Global Privacy Control 信号。
如果我修改它并以托管服务的形式运营会怎样?代码采用 AGPL-3.0 协议,因此以网络服务形式运营修改版时,必须向其用户提供你修改后的源代码。“OpenAnalytics”名称和 getopen.so 域名是作者的商标,不在许可授权范围之内。
MCP 服务器能做什么?它让 AI 助手和智能体可以通过 Model Context Protocol 直接查询你的分析数据,仪表盘中还有一个内置的 AI 助手界面。
收入归因功能是怎么工作的?它直接从你连接的 Stripe 账户拉取收入分析数据,让你看到哪些流量来源真正带来了付费客户。
不自己托管可以试用吗?可以——作者在 getopen.so 上运营着一个托管实例,运行的是同样的代码,部署在他们自己的服务器上。
有管理站点的命令行方式吗?内置的“oa”CLI 可以完成站点设置、查看统计和设备流登录,不需要网页仪表盘。
Size
8.7 MB
Stars
632
Age
2mo
Commits · 90 Days