Self-hosted app telemetry and website analytics. One binary. No cloud. No cookies.
Crowbar collects two kinds of data: app telemetry and website analytics. App telemetry tracks events with type, phase, operation, and result fields. It detects failures and slow operations so you know when something breaks before your users tell you. Website analytics tracks page views, unique visitors, engagement time, scroll depth, browser/device/OS/language/country breakdowns, referrers, and UTM campaigns.
It's a single Go binary backed by PostgreSQL. That's the whole stack. No Redis, no Kafka, no message queue, no fourteen microservices.
Privacy is the default, not a feature flag. No cookies. Visitor identity is a daily-rotating hash — same person gets a different hash tomorrow. IP addresses are resolved to a country via GeoIP and then thrown away. Nothing is stored that could identify a person.
git clone https://github.com/staack/crowbar.git
cd crowbar
docker compose up -d
open http://localhost:8080The dashboard is at / with basic auth. Default creds are in the docker-compose file. Change them.
All configuration is through environment variables.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
(required) | PostgreSQL connection string |
LISTEN_ADDR |
:8080 |
Address and port to bind |
DASH_USER |
admin |
Dashboard basic auth username |
DASH_PASS |
(required) | Dashboard basic auth password |
PROJECT_NAME |
crowbar |
Project name shown in dashboard and emails |
ALLOWED_ORIGINS |
* |
Comma-separated allowed CORS origins |
NOTIFY_ON |
(empty) | Event types that trigger email alerts (comma-separated) |
SMTP2GO_API_KEY |
(empty) | SMTP2Go API key for email notifications |
SMTP2GO_FROM |
(empty) | Sender address for notifications |
SMTP2GO_TO |
(empty) | Recipient address for notifications |
ADMIN_TOKEN_HASH |
(empty) | SHA-256 hash of the admin API token |
GEOIP_DB_PATH |
(empty) | Path to MaxMind GeoLite2 Country database |
MAX_REQUEST_BYTES |
1048576 |
Maximum request body size in bytes |
RATE_LIMIT_RPS |
10 |
Requests per second per IP |
RATE_LIMIT_BURST |
20 |
Burst allowance for rate limiting |
LOG_LEVEL |
info |
Log level: debug, info, warn, error |
LOG_FORMAT |
json |
Log format: json or text |
Paste before </body> on pages you want to track. Replace YOUR_DOMAIN with your crowbar host. The full snippet is in docs/tracking-snippet.html — copy it from there.
It collects page path, title, referrer, screen size, viewport, timezone, device pixel ratio, touch support, connection type, UTM params, scroll depth, and time on page. No cookies. Uses sessionStorage for page-count-per-visit (clears when the tab closes). Fires a beacon on page hide for engagement data.
Register an installation, then send events:
# Register — save the token.
curl -s -X POST https://YOUR_DOMAIN/api/v1/installations/register | jq .
# Send an event.
curl -X POST https://YOUR_DOMAIN/api/v1/ingest \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"events": [{
"event_type": "deploy",
"phase": "database",
"operation": "migrate",
"result": "success",
"duration_ms": 1230,
"app_version": "1.0.0"
}]
}'See docs/client-examples/ for Python, Node.js, and Go.
See docs/reverse-proxy/ for Caddy, Nginx, HAProxy, Apache, and Traefik configs.
MIT. See LICENSE.