just the currents, never the identities
TypeScript 99.7%
Other 0.3%
2 1 2

Clone this repository

https://tangled.org/tijs.org/driftline-analytics
git@tangled.org:tijs.org/driftline-analytics

For self-hosted knots, clone URLs may differ based on your setup.

README.md

Driftline Analytics#

Anonymous analytics service for ATProto app views, hosted on Valtown.

Features#

  • Anonymous by design: users are identified by pseudonymous IDs derived from DIDs
  • Per-app-view isolation: same user gets different IDs across different app views
  • Simple event model: accounts, views, and actions
  • JSON stats API

API Endpoints#

Base URL: https://driftline.val.run

Health Check#

GET /

Collect Events#

POST /collect
Headers: X-API-Key: <your-api-key>
Content-Type: application/json

Body (single event):
{
  "v": 1,
  "appView": "kipclip.com",
  "env": "prod",
  "ts": "2025-01-15T10:30:00.000Z",
  "uid": "a1b2c3d4e5f6",
  "type": "action",
  "name": "checkin_created",
  "screen": "CheckinScreen",
  "props": { "placeType": "cafe" }
}

Body (batch):
{
  "events": [...]
}

Event types:

  • account - Track account creation (once per user)
  • view - Track screen impressions
  • action - Track user actions

Get Stats#

All stats endpoints require the X-API-Key header.

GET /stats/:appView?env=prod
GET /stats/:appView/accounts?env=prod
GET /stats/:appView/users?env=prod
GET /stats/:appView/events?env=prod

Client#

See @tijs/driftline-client for the TypeScript client library.

Anonymity#

User IDs are derived using SHA-256:

uid = sha256(salt + did).slice(0, 12)
  • Each app view uses its own salt
  • Same DID produces different UIDs across app views
  • Server never sees the original DID

Admin#

Create API keys (requires ADMIN_SECRET env var):

POST /admin/api-keys
Headers: X-Admin-Secret: <admin-secret>
Body: { "appView": "your-app.com" }

Development#

deno task fmt      # Format code
deno task lint     # Lint code
deno task check    # Type check
deno task deploy   # Format, lint, check, and push to Valtown