koda-sdk-browser
v0.1.1
Published
Koda browser SDK: programmatic KodaClient.report() and an opt-in Shadow-DOM drop-in widget for user-triggered bug reports.
Downloads
37
Readme
koda-sdk-browser
Browser SDK for Koda — a self-hosted, user-triggered bug report platform. Ships a programmatic API plus an opt-in Shadow-DOM drop-in widget. Lazy-loads the screenshot library and widget chunk, so a page that initializes but never reports pays only the core bundle.
Install
bun add koda-sdk-browser
# or
npm install koda-sdk-browserIf you don't have a build system, use the embed snippet from the Koda dashboard (Settings → Keys → "Embed snippet") instead — no install required.
Initialize
import { KodaClient } from "koda-sdk-browser";
KodaClient.init({
ingestUrl: "https://koda.your-company.com/api/reports",
projectKey: "koda_pk_...",
environment: "production",
release: "[email protected]",
service: "checkout-frontend", // optional; helps in multi-service projects
widget: { enabled: true } // optional; mounts the floating button + modal
});init is a no-op on the server (Node, Deno, Bun server runtimes), so it's safe to call from shared modules in Next.js / Nuxt / Remix / SvelteKit.
Programmatic report
import { KodaClient } from "koda-sdk-browser";
const outcome = await KodaClient.report({
description: "Checkout button does nothing on Safari 17",
reporter: { name: "Avery", email: "[email protected]" },
includeScreenshot: true,
tags: { surface: "checkout" },
error: caughtError, // optional Error or string
correlationId: requestId // optional; ties this report to a backend request
});
if (!outcome.ok) {
console.warn("report failed:", outcome.error);
}
if (outcome.screenshot && !outcome.screenshot.ok) {
console.warn("screenshot failed:", outcome.screenshot.reason, outcome.screenshot.message);
}What gets captured
Even before you call report(), the SDK silently ringbuffers (default 100 each, configurable):
console.log/warn/errorcallsfetchandXMLHttpRequestactivity (method, URL, status, duration, redacted headers)- Click and navigation breadcrumbs
When report() runs, all of the above plus page context (URL, viewport, locale, timezone, user-agent), the parsed stack trace, the reporter's identity, and an optional screenshot are bundled into a single POST /api/reports.
Customize redaction:
KodaClient.init({
// ...
redact: (value, hint) => {
if (hint.kind === "header" && typeof value === "string") {
return value.replace(/Bearer .+/i, "Bearer [redacted]");
}
return value;
}
});Drop-in widget
KodaClient.init({
// ...
widget: {
enabled: true,
position: "bottom-right",
buttonLabel: "Report a bug",
accentColor: "#7257ff",
defaultIncludeScreenshot: true
}
});The widget renders inside Shadow DOM so host CSS won't leak into it (and vice versa). The widget chunk is fetched on first init only when widget.enabled === true.
Bundle size
| Entry | Size (gzipped) | When |
|---|---|---|
| Core client | ~4KB | Always |
| widget.js | ~5.5KB | Only when widget.enabled === true |
| html-to-image vendor chunk | ~5.7KB | Only on the first report({ includeScreenshot: true }) |
License
MIT
