Website: sight-hog.vercel.app
Documentation: sight-hog.vercel.app/docs
SightHog is a drop-in browser SDK that records rrweb session replay, rage-clicks, web vitals, and network logs — then ships them to your own Kafka, Postgres, and ClickHouse. Open source, self-hosted, no per-seat fees.
For setup guides, architecture docs, API reference, and privacy details, see sight-hog.vercel.app/docs.
Browser (SDK on demo store)
|
v
Ingest API (Go) :8080
|
v
Kafka (sighthog-raw-events)
|
+-- metadata worker --> PostgreSQL (sessions, users)
+-- metrics worker --> ClickHouse (events, interactions, telemetry)
+-- blob worker --> SeaweedFS (gzipped rrweb replays per session)
|
v
Dashboard (Next.js) :3000
- The SDK batches rrweb events, interactions, and telemetry and POSTs to
/v1/events. It sends a persistentvisitorId(localStorage),sessionId(sessionStorage),referrer, and optionaluserId. - The ingest API validates payloads, resolves country (optional GeoLite2), parses browser/OS from User-Agent, masks sensitive fields, and publishes to Kafka.
- Workers consume the same topic in parallel:
- Metadata upserts one Postgres row per
sessionId(updatesupdated_aton later batches). - Metrics writes ClickHouse rows for analytics charts and frustration detection.
- Blob merges rrweb events per session and uploads
{sessionId}.json.gzto object storage.
- Metadata upserts one Postgres row per
- The dashboard reads Postgres for the session list, ClickHouse for charts, and SeaweedFS for replay files.
The demo store is a separate Next.js app on port 3001. It uses client-side routing across multiple pages while keeping one sessionId in sessionStorage, so you should see a single session row after browsing Home, Catalog, Product, Cart, and Checkout.
- Docker Desktop (recommended for full stack)
- Node.js 20+ (optional, for local app development)
- Go 1.22+ (optional, for ingest API development)
Full install steps and SDK usage are in the docs. To run the stack locally:
cp .env.example .env
docker compose up --build| URL | Service |
|---|---|
| http://localhost:3000 | Dashboard (sessions and replay) |
| http://localhost:3000/analytics | Web analytics (visitors, geo, browsers) |
| http://localhost:3001 | Demo store (Next.js, multi-page) |
| http://localhost:8080 | Ingest API |
| http://localhost:9333 | SeaweedFS admin |
- Open http://localhost:3001 and click through several pages (use the nav: Home, Catalog, Product, Cart, Checkout).
- On Home, try rapid clicks on the red “Broken checkout button” to generate rage-click events.
- Wait about 30 seconds for workers to flush replay blobs.
- Open http://localhost:3000, click Refresh on the session list, then Watch on your session.
- Open Analytics in the nav (or http://localhost:3000/analytics) to see pageviews, unique visitors, world map, and browser/OS breakdowns.
- Use Clear all sessions on the dashboard to wipe Postgres, ClickHouse, and stored replays before another test run.
Country codes are resolved at ingest from the client IP using MaxMind GeoLite2:
- Create a free MaxMind account and download
GeoLite2-Country.mmdb. - Place it at
infra/geoip/GeoLite2-Country.mmdb(this path is gitignored). - Restart the ingest API container. Without the file,
countryis stored asUnknown(orLOCALfor private IPs).
Existing Docker volumes need schema migrations:
docker compose exec clickhouse clickhouse-client --user default --password password --multiquery < infra/clickhouse/migrate_analytics.sql
docker compose exec postgres psql -U sighthog_user -d sighthog_metadata -f - < infra/postgres/migrate_analytics.sql(Adjust paths if running from the host; pipe the SQL files into the containers.)
| Path | Role |
|---|---|
packages/sdk |
Browser SDK (rrweb, telemetry, funnel events, frustration detection) |
apps/demo |
Next.js demo store for generating traffic |
apps/dashboard |
Next.js control center and replay player |
services/ingest-api |
Go HTTP API and Kafka producer |
services/workers |
Kafka consumers (Postgres, ClickHouse, SeaweedFS) |
infra/ |
Init scripts for Kafka, Postgres, ClickHouse, SeaweedFS |
Kafka and databases via Docker:
docker compose up kafka kafka-init postgres clickhouse seaweedfs seaweed-initIngest API:
cd services/ingest-api
go run ./cmd/serverWorkers:
cd services/workers
go run ./cmd/processorSDK:
cd packages/sdk
npm install && npm run buildDemo store:
cd apps/demo
npm install
npm run devDashboard:
cd apps/dashboard
npm install
npm run devSet NEXT_PUBLIC_SDK_ENDPOINT=http://localhost:8080/v1/events for the demo app.
Copy .env.example to .env before docker compose up. Important variables:
DATABASE_URL— Postgres for session metadataCLICKHOUSE_HTTP_URL— analytics queries from the dashboardSEAWEEDFS_ENDPOINT/SEAWEEDFS_BUCKET— replay object storageCORS_ALLOWED_ORIGINS— must include demo and dashboard originsNEXT_PUBLIC_DEMO_URL— link from dashboard to the demo storeGEOLITE2_DB_PATH— path to GeoLite2-Country.mmdb inside the ingest container (default/geo/GeoLite2-Country.mmdb)
Postgres sessions:
docker compose exec postgres psql -U sighthog_user -d sighthog_metadata -c "SELECT id, initial_url, updated_at FROM sessions ORDER BY updated_at DESC LIMIT 10;"ClickHouse event counts:
docker compose exec clickhouse clickhouse-client --user default --password password --query "SELECT event_name, count() FROM sighthog.events GROUP BY event_name;"Apache 2.0. See LICENSE.
