# Browser Ingest

Send events from browsers and single-page apps. Browser code is public, so it never holds your secret key: your backend mints a **short-lived session token** (1 hour) and the browser SDK sends events with it.

**The flow**

1. Your backend calls [Server Ingest API → Mint browser session token](/server-ingest-api) with the secret DSN key (the JS and PHP SDKs ship ready-made mint helpers; any other backend calls the endpoint directly).
2. Your page calls `initBrowser({ sessionUrl })` pointing at your own mint endpoint (never `projectKey`); see [Install an SDK → JavaScript & TypeScript](/install-an-sdk).
3. The SDK captures errors, batches events and posts them with `x-bugwatch-session`, re-fetching the token before expiry and on a 401 automatically.

**Origin allow-list:** the project's allowed origins (Dashboard → project → Settings) are enforced on every browser event; a mismatched `Origin` gets `403 origin_not_allowed`. An empty list allows any origin; lock it down before production.

The browser wire contract accepts the same event shape as [Server Ingest API](/server-ingest-api) (including `breadcrumbs[]`, `contexts{}` and `causes[]`), authenticated with `x-bugwatch-session` instead of the key; the SDK produces it for you. Browser `sessionUrl` mode captures errors and logs only; span creation needs a server-side `projectKey` (the JS `wrapFetch` still injects `traceparent` in the browser so your backend joins the page's trace).

**POST /api/v1/bugwatch/ingest/browser**: Browser ingest - error event (session token) (fetch id `endpoint:6ae152d083f212a997c813a0`)
