Reverse proxy
Send ingestion through your domain to reduce ad-blocker loss — pattern, SDK option, and verification.
Why
Some ad blockers and corporate filters block known analytics hosts. When the browser cannot reach the default ingestion host (https://ingest.humanbehavior.co), sessions never appear. Proxying /api/ingestion/* through your first-party domain keeps the request on an allowlisted origin.
SDK configuration
The only client change is ingestionUrl — the base URL without trailing slash; the SDK appends /api/ingestion/... paths.
HumanBehaviorTracker.init(apiKey, {
ingestionUrl: "https://your-domain.com/hb",
});With that base, a typical replay flush becomes:
POST https://your-domain.com/hb/api/ingestion/events
Authorization: Bearer <apiKey>Same for heartbeat, session-end, errors, customEvent/batch, spans/batch, etc. (/init still exists upstream but the current SDK does not call it on normal startup.)
Proxy requirements
Your proxy must:
- Forward method, path (under
/api/ingestion/*), query, and body to the real ingestion host. - Forward the
Authorizationheader (Bearer API key). - Preserve or set CORS appropriately if the browser calls a different subdomain (same-site first-party paths usually avoid CORS issues).
- Allow
POST(andOPTIONSpreflight if cross-origin). - Not buffer-limit large replay chunks — events can approach 1MB per chunk (
MAX_CHUNK_SIZE_BYTESin the SDK). - Support
sendBeacon/ keepalive POSTs used on unload forsession-end, heartbeats, and span flush.
Path mapping examples
| Browser URL | Upstream |
|---|---|
https://app.example.com/hb/api/ingestion/events | https://ingest.humanbehavior.co/api/ingestion/events |
https://app.example.com/hb/api/ingestion/heartbeat | https://ingest.humanbehavior.co/api/ingestion/heartbeat |
Local development often points ingestionUrl straight at http://localhost:8000 (no proxy).
Example shapes (illustrative)
Exact nginx/Cloudflare Worker syntax varies by stack — treat the following as a pattern, not a copy-paste production config.
Next.js rewrite (same origin):
// next.config.js — illustrative
async rewrites() {
return [
{
source: "/hb/api/ingestion/:path*",
destination: "https://ingest.humanbehavior.co/api/ingestion/:path*",
},
];
}Then ingestionUrl: "" is wrong — use the site origin + prefix, e.g. https://app.example.com/hb or a relative base only if your bundler resolves it the same way the SDK expects (prefer absolute HTTPS origin + prefix).
Source maps through a proxy
npx @humanbehavior/wizard upload-sourcemaps --url https://your-domain.com/hb must reach POST …/api/ingestion/sourcemaps. Ensure CI can call the same proxy or the direct ingest host with the project API key.
Verify
- DevTools → Network: requests hit your host and return 2xx.
- No
ERR_BLOCKED_BY_CLIENTon ingestion URLs. - Data appears in Replays / Dashboard for that project.
- Heartbeat and session-end still succeed on tab close.