Developer pages

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:

  1. Forward method, path (under /api/ingestion/*), query, and body to the real ingestion host.
  2. Forward the Authorization header (Bearer API key).
  3. Preserve or set CORS appropriately if the browser calls a different subdomain (same-site first-party paths usually avoid CORS issues).
  4. Allow POST (and OPTIONS preflight if cross-origin).
  5. Not buffer-limit large replay chunks — events can approach 1MB per chunk (MAX_CHUNK_SIZE_BYTES in the SDK).
  6. Support sendBeacon / keepalive POSTs used on unload for session-end, heartbeats, and span flush.

Path mapping examples

Browser URLUpstream
https://app.example.com/hb/api/ingestion/eventshttps://ingest.humanbehavior.co/api/ingestion/events
https://app.example.com/hb/api/ingestion/heartbeathttps://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

  1. DevTools → Network: requests hit your host and return 2xx.
  2. No ERR_BLOCKED_BY_CLIENT on ingestion URLs.
  3. Data appears in Replays / Dashboard for that project.
  4. Heartbeat and session-end still succeed on tab close.