Instrument your frontend
Instrument a browser app with @sazabi/browser to capture errors, console output, network activity, and interaction events — or forward from a Sentry or PostHog SDK you already run.
You can send browser-side telemetry — errors, console output, network activity, and interaction events — to the same Sazabi intake your backend uses. For most apps, use the Sazabi browser SDK (@sazabi/browser): it captures a semantic event stream and injects W3C trace context into outgoing requests so browser events correlate with your backend logs. By the end of this guide you will have the SDK initialized and confirmed events arriving. Setup takes a few minutes plus a deploy.
Ways to instrument the frontend
- The Sazabi browser SDK (recommended). First-party capture with backend correlation — the richest browser data, at the cost of adding one SDK to your app. The rest of this guide sets it up. Do not use it when you do not control the frontend build.
- The Sentry SDK. Already instrumenting the browser with Sentry? Point the Sentry SDK's DSN at your project's intake URL so Sentry envelopes arrive as records — you keep Sentry's event shape rather than the browser SDK's semantic stream. See Sentry SDK source.
- The PostHog SDK. Already running
posthog-js? Repoint its API host at your project's intake URL so its analytics and session events arrive as records. See PostHog SDK source.
You can also run the browser SDK alongside an existing provider — everything lands in the same searchable set of log records.
What the browser SDK captures
- Errors and console — uncaught errors and unhandled rejections, plus
console.errorandconsole.warnoutput mirrored as log events. - Network —
fetchandXHRrequests, with a request-id response header attached as a join key against platform logs when present. - Interaction events — clicks (including rage and dead clicks) and per-field input engagement episodes. The SDK records element selectors and a developer-facing element name, never values or keystrokes.
- Navigation — SPA route changes and full page loads.
- Session identity — a cross-tab session id and per-tab window id, plus a client-asserted distinct id you set with
identify().
Set up the SDK
Install the package and call init() once, as early as possible in your app's startup, before the code you want to observe runs.
bun add @sazabi/browserimport { init } from "@sazabi/browser";
init({
intakeUrl: import.meta.env.VITE_SAZABI_INTAKE_URL,
serviceName: "web-app",
});Like every other log source, the SDK is configured with your intake URL alone — copy it from the Sazabi Browser SDK source under Settings > Log streams (create the source there if your project has none, or with sazabi log-sources create sazabi_browser_sdk --mode connectionless). The URL embeds a write-only public key, which is why it is safe to ship in a browser bundle.
init() takes two required options — intakeUrl and serviceName — plus optional ones such as serviceVersion, environment, consent, network, console, and input, and exposes identify() / reset() for user identity. For every option, method signature, and the exact call semantics, see the Browser SDK reference — this guide does not repeat them.
Correlate with backend logs
By default the SDK injects a W3C traceparent header into same-origin requests, and stamps the record trace id on the resulting network event. When your backend also sends logs to Sazabi with the same trace context, the agent can line up a browser action with the backend work it triggered.
Cross-origin injection is opt-in because the target must allowlist the header in CORS. Add matching URL patterns to init()'s network.allowlist option when you want it (for example network: { allowlist: ["https://api.example.com"] }); see Browser SDK reference for the full network option.
Verify
Confirm real browser events reach your project.
- Deploy or run the app with
init()active, then open it in a browser. - Trigger an event the SDK captures — for example, click a button, then force a
console.error("sazabi browser sdk test")from your app or the devtools console. - Filter to
service.nameequal to theserviceNameyou configured (web-appin the examples above). In the dashboard, open your logs and filter; an agent can runsazabi logs query --service web-app --last 1hinstead. - You should see records with
web.event_typevalues such asclick,error,navigation, ornetwork, and your testlogrecord. Events batch and flush about every five seconds (and on page hide), so allow up to roughly a minute after the interaction.
If nothing appears, check that you pasted the complete intake URL from the source's setup screen and that the browser's network tab shows requests to your intake host returning 2xx.
Troubleshooting
- No events at all. Confirm
init()runs in the browser (not only during SSR), that all three required options are set, and that noconsentgate is holding capture dormant. - Requests rejected. Confirm
intakeUrlis the complete intake URL copied from the source's setup screen — a partial or hand-built URL is rejected. - Backend correlation missing. Ensure your backend forwards logs with the incoming trace context, and add cross-origin API hosts to
network.allowlist.