Privacy-first analytics
for every site you build.
Self-host Zenith once. Track unlimited client sites with a tiny cookieless script, run on-demand SEO audits, and give each client a dashboard that lives on their own domain.
$ npm install zenith-analyticsVisitors
12,847
+18%
Pageviews
48.1K
+12%
Sessions
15.3K
+9%
Traffic
last 30 days
Top pages
Referrers
Zenith in action
One console. Every site you build.
Deploy Zenith once on your own server. Every client site reports into it, and any of them can serve its owner a dashboard on their own domain — password-gated, same-origin, reading through your site rather than ours.
1
KB, cookieless · Tracking script
∞
Sites per deploy
0
Consent banners
320
Tests, end to end
Everything you need
One deploy. Every site. Zero cookies.
The things the product exists to do — analytics, domain-native dashboards, SEO auditing, and privacy — with nothing you have to bolt on.
Multi-site console
Deploy once and every site you manage reports into one place. Overview, events, SEO and setup — for each client, behind one login.
Visitors
12,847
Pageviews
48.1K
Bounce
38%
Cookieless tracking
A daily-rotating visitor hash — no cookies, no fingerprinting, no persistent identifier. GDPR-clean, so no consent banner.
sha256(ip + ua + saltᴰᵃʸ)
a3f9c1e0…7b42
Domain-native dashboards
Your client reads their analytics at theirsite.com/analytics-dashboard — password-gated, same-origin, native to their brand.
SEO audits
On-demand, headless-Chromium audits: titles, meta, links, structured data, and Core Web Vitals from the real render.
Monthly email reports
Each client is emailed last month's numbers automatically on the 1st. No cron to run — the scheduler is built in.
Visitors
+18%
Views
+12%
Audits
4
Self-hosted, open-core
Two Go services, DuckDB for events, SQLite for app data. One command brings the whole thing up, and your data never leaves your box.
$ docker compose up -dHonestly, how it compares
Zenith isn’t the right answer for everyone.
Here is where it actually sits — including the two rows where it loses. If you need funnels and session replay, or you want nothing to deploy, one of the others is the better tool and this table should tell you so.
| Capability | Google Analytics | Plausible / Fathom | Umami (self-hosted) | Zenith |
|---|---|---|---|---|
| Cookie banner needed | Yes | No | No | No |
| Cost per extra site | Free | Per site or pageview | Free | Free |
| You own the data | No | No | Yes | Yes |
| Client reads it on their domain | No | No | No | Yes |
| SEO audits built in | No | No | No | Yes |
| Monthly client emails | No | Some plans | No | Yes |
| Setup effort | Paste a tag | Paste a tag | Deploy a server | Deploy a server |
| Funnels, cohorts, replay | Extensive | Growing | Basic | Basic |
Choose something else if
you want zero infrastructure — Plausible and Fathom cloud are excellent — or you need deep product analytics: funnels, cohorts, session replay, attribution modelling. Zenith deliberately doesn’t do those.
Choose Zenith if
you look after several sites for other people, you’re tired of consent banners and per-site pricing, and you’d rather hand a client a page on their own domain than another login.
How it works
Three steps. About fifteen minutes.
This is the whole setup — not an excerpt. One deploy on your server, one package in your client’s app, and a dashboard they open on their own domain.
Deploy once
Clone the repo, fill in three environment variables, and bring it up. That server is now the only Zenith you will ever need to run — every client site reports into it.
git clone https://github.com/MUKE-coder/zenith.git
cd zenith/deploy
docker compose --env-file ../.env up -d --buildInstall the package
In your client's Next.js app, install and scaffold. zenith init detects the router and writes the config plus the dashboard route; after that the tracker is one component in the root layout.
npm install zenith-analytics
npx zenith init # config/zenith.ts + the dashboard route
npx zenith hash # the client's dashboard passwordimport { Analytics } from "zenith-analytics/next";
import { ZENITH_PUBLIC } from "@/config/zenith";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
{/* Only the public half: the site key and the service URL. */}
<Analytics config={ZENITH_PUBLIC} />
</body>
</html>
);
}Hand off the dashboard
Your client opens theirsite.com/analytics-dashboard, enters their password, and reads their own analytics — same-origin, on their own domain, with no third-party subdomain in sight.
Analytics
Enter the password to continue
Under the hood
Two Go services and two embedded databases.
Events land on /api/collect and go straight into DuckDB, which is built for exactly this kind of counting. App data — your sites, keys and users — lives in SQLite, which doubles as the queue the SEO worker pulls audits off. No message broker, no managed database, nothing to bolt on.

Muke Johnbaptist
Creator of Zenith — JB
A word from the creator
I build websites for clients, and the analytics part was always the ugly bit. Every site meant another third-party account, another cookie banner nobody wanted, and a dashboard on somebody else’s subdomain that my client had to be walked through every single time.
So Zenith is the thing I wanted instead: deploy it once, and it covers every site you build. The tracker is cookieless, so there is no banner to argue about. The dashboard lives on your client’s own domain, so it just looks like part of their site. And because you host it, the numbers stay yours — not rented back to you.
It is open-core and it runs on one box. If that is the kind of thing you have been looking for, I would genuinely like to hear how it goes.
Own your clients’ analytics.
No third-party subdomain, no cookie banner, no per-site setup. Deploy once and every site you build reports into it.