Ingestion API
Public ingestion endpoints from the ingestion-server — auth, paths, and SDK usage notes.
Base URL
| Context | Typical base |
|---|---|
| Production | https://ingest.humanbehavior.co |
| Local stack | http://localhost:8000 (or your compose port) |
| Reverse proxy | Your first-party prefix (see Reverse proxy) |
The SDK sets ingestionUrl to this base and appends the paths below.
Authentication
Most ingestion POSTs from the browser SDK (ordinary fetch) send:
Authorization: Bearer <project_api_key>
Content-Type: application/jsonsendBeacon cannot set headers, so some unload / presence paths (notably heartbeat, session-end, and beacon event batches) put apiKey in the JSON body instead. The server accepts either form.
Keys come from Settings → Environments. Invalid keys fail auth at the server; rotate invalidates old keys immediately.
Public endpoints (ingestion-server)
Registered in ingestion-server/src/index.ts:
| Method | Path | Purpose | Primary SDK caller |
|---|---|---|---|
| POST | /api/ingestion/init | Optional / deprecated bootstrap (session + end user). Normal SDK startup does not call this — ids are local and users are created on first event | testConnection() / legacy only |
| POST | /api/ingestion/events | Replay / rrweb chunks (+ event stream) | Event flush / chunking |
| POST | /api/ingestion/user | Identify / user upsert | identifyUser |
| POST | /api/ingestion/user/auth | Auth-field-aware user upsert | Low-level api.sendUserAuth (no public tracker.auth() helper in current tracker API) |
| POST | /api/ingestion/customEvent | Single analytics event | Fallback / non-batch |
| POST | /api/ingestion/customEvent/batch | Batched analytics events | customEvent batcher |
| POST | /api/ingestion/groupidentify | Group identify (PostHog-style groups) | Present on server; browser tracker usage not verified as a first-class public method in this pass |
| POST | /api/ingestion/ip-info | GeoIP helper input | SDK geo pipeline when used |
| POST | /api/ingestion/logs | Console log ingest | Console tracking |
| POST | /api/ingestion/network | Network error ingest | Network tracking |
| POST | /api/ingestion/spans/batch | Trace spans | Tracing module |
| POST | /api/ingestion/errors | Error reports → Issues | Error capture |
| POST | /api/ingestion/sourcemaps | Source map upload | npx @humanbehavior/wizard upload-sourcemaps |
| POST | /api/ingestion/heartbeat | Live presence ping | ~30s heartbeat |
| POST | /api/ingestion/session-end | Unload presence clear | pagehide / unload |
| GET | /health | Comprehensive health | Ops / load balancers |
| GET | /health/simple | Lightweight health | Load balancers |
| GET | / | Simple health | Root probe |
Not public SDK surface
| Path | Note |
|---|---|
POST /api/internal/scan-findings | Secret-guarded static-analysis ingest — not for browser SDKs |
Practical constraints (from SDK)
| Topic | Detail |
|---|---|
| Chunk size | Replay payloads split around 1MB encoded JSON |
| Batching | Custom events: 100ms / 50-event batch; replay flush ~3s (or 150ms when live viewer active) |
| Offline | Failed batches can persist to localStorage and drain later / on online |
| Unload | Beacon / keepalive used when fetch is unavailable or sticky-beacon mode engages |
| Monthly limit | 429 / monthlyLimitReached causes the SDK to stop sending quietly |
Building a custom client
- Copy a successful browser request from DevTools as your template (headers + JSON shape).
- Always send a stable
sessionIdandendUserIdconsistent with your session model. - Prefer the JS SDK in browsers — retry, redaction, and live-flush behavior are non-trivial to reimplement.
- Do not treat frontend
/api/projects/...routes as a public ingest API; those require dashboard session auth.