Add one script tag
Paste 2.5 KB of JavaScript into your layout. Works with every framework, including single-page apps.
<script defer
data-website-id="acme"
src="/js/kestrel.js">
</script>
Connect every payment to the visit that caused it. Run the whole stack on your own server.
Works with the stack you already run
How it works
No data team, no tagging plan, no 40-tab dashboard. Three steps, one afternoon.
Paste 2.5 KB of JavaScript into your layout. Works with every framework, including single-page apps.
<script defer
data-website-id="acme"
src="/js/kestrel.js">
</script>
Add a webhook or send a small JSON payload. Dodo Payments is native; Stripe and others work through the API.
Open the dashboard and find the channels, pages and posts that create customers, not just clicks.
The part other tools skip
Kestrel stitches every payment back to the visit that caused it. Not a vanity dashboard: an attribution engine that answers the only question that matters.
Features
All the reports you need to make decisions, none of the consent-manager-required, script-bloated, dashboard-slow baggage.
Visitors, revenue, conversion, revenue per visitor, bounce rate and session time with period-over-period changes.
ChatGPT, Claude, Perplexity and Copilot get their own channel, so you can see what the answer engines send you.
See who is on the site right now, the page they landed on and what they are doing. Addictive in a useful way.
Click any visitor for a full timeline: visits, pages, goals, identified email and payments. See the exact path from first touch to checkout.
Button clicks, custom events and multi-step funnels. No extra product, no per-goal pricing.
Publish a read-only link for a client or investor. No account to create, revoke it any time.
One SQLite file. Back up the entire product with one command. No Postgres, no managed database bill.
cp data/kestrel.db backup.db
The honest comparison
Self-hosting removes the bill. Kestrel removes the reasons you still needed a second tool.
| Google Analytics 4 | Umami | Plausible | ||
|---|---|---|---|---|
| Tracker size (gzipped) | ~2.5 KB | ~45–90 KB | ~2 KB | ~1 KB |
| Self-hosted, no cloud | Yes, 1 container | No | Yes | Yes (CE) |
| Database you own | SQLite file | Google’s | Postgres / MySQL | Postgres / ClickHouse |
| Revenue attribution | Built in | Complex setup | No | No |
| AI assistant channel | Dedicated | Mixed into referral | Mixed into referral | Mixed into referral |
| Goals & funnels | Included | Included, heavy | Goals only | Goals only |
| Visitor journey profiles | Full timeline | Limited | No | No |
| GDPR-friendly (first-party) | Yes | Consent mode | Yes | Yes |
| Cost | $0 forever | Free / $50k+ | Free / $20+ | Free / €9+ |
Approximate values, checked October 2026. “Self-hosted” means you run it on your own server. Kestrel uses first-party cookies to recognise returning visitors, with no cross-site identifiers, no data sold, no third party.
Deploy
Node 22.13+ or Docker. No build service, no database admin, no monthly bill. The first boot creates the database and runs every migration automatically.
git clone https://github.com/rahulxdevv/kestrel.git
cd kestrel
docker build -t kestrel .
docker run -d --name kestrel -p 3000:3000 \
-v kestrel-data:/data \
-e ADMIN_PASSWORD='a-strong-password' \
-e SESSION_SECRET="$(openssl rand -hex 32)" \
kestrel
Open http://localhost:3000/app. Everything lives in the volume at /data.
services:
kestrel:
build: .
restart: unless-stopped
ports: ["3000:3000"]
environment:
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
SESSION_SECRET: ${SESSION_SECRET}
volumes:
- kestrel-data:/data
volumes:
kestrel-data:
Build type: Dockerfile. Add a persistent volume at /data and point your domain at port 3000.
# render.yaml is included in the repo
services:
- type: web
name: kestrel
runtime: docker
plan: starter
healthCheckPath: /api/health
disk:
name: kestrel-data
mountPath: /data
sizeGB: 1
Render needs a persistent disk for the SQLite file; without it the database resets on every deploy.
# Any VPS with Node 22.13+
npm ci && npm run build
ADMIN_PASSWORD='…' SESSION_SECRET='…' npm start
# Cloudflare Workers (optional)
npx wrangler d1 create kestrel
npm run deploy:cloudflare
Put Caddy or Nginx in front for HTTPS. Both runtimes share the same code and schema.
Then add one script tag
Works with Next.js, Astro, WordPress, Shopify, Webflow, plain HTML and single-page apps.
<script defer data-website-id="YOUR_SITE_ID"
src="https://analytics.yoursite.com/js/kestrel.js"></script>
FAQ
Yes. MIT licensed, self-hosted, no seat limits, no event limits, no feature gates. You pay for your own server if you don’t already have one.
Kestrel only uses first-party cookies on your own domain to recognise a returning visitor and keep a session together. There are no third-party cookies and no cross-site tracking. Whether you need a banner depends on your jurisdiction and legal advice, but the data is far smaller, and it never leaves your server.
Not today. Kestrel is deliberately SQLite-first: one file, zero operations, fast on a $4 VPS and easy to back up. A managed Postgres adapter is on the roadmap.
Put Cloudflare in front of your domain (free), or use a proxy that adds geo headers (Caddy with the geo module, Traefik + GeoIP, Vercel). Without geo headers Kestrel simply leaves the country empty; nothing breaks.
Yes, through the generic payments API: post a small JSON payload from your webhook with the visitor id, amount and email. Dodo Payments has a native, signature-verified webhook.
Yes. The repo still ships a Worker entry, D1 migrations and wrangler config. Run npm run deploy:cloudflare and you get the same dashboard on Workers, free.
On SQLite with WAL mode, a small VPS handles millions of events per month comfortably. The dashboard uses pre-aggregated SQL queries with indexes and the tracker batches engaged-time pings, so there is no scanning of raw events on page load.
Copy data/kestrel.db (plus the WAL files while stopped, or use sqlite3 .backup) and mount it on the new host. The schema migrates itself on boot.
Open source · MIT · Self-hosted
Deploy Kestrel once. Own the dashboard, the database and the story your traffic tells.
No account. No trial. No monthly bill.