Getting started
Install @bugjar/reporter with two script tags — a bugjar:ready handler that calls BugJar.init({...}) with your hooks, and the SDK loader. Every config option documented in one place.
Two script tags in your HTML. Your customers can file consent-gated bug reports.
Install
Drop the snippet from Settings → Projects → Your project → Install into the <head> of any page where bug reporting should be available:
<script>
window.addEventListener('bugjar:ready', () => {
BugJar.init({
// your config + hooks go here
// onReportSubmitted: (id) => { ... },
// ui: { position: 'bottom-right' },
});
});
</script>
<script src="https://console.bugjar.app/sdk/proj_live_yourkey.js" type="module" async></script>
Two <script> tags: the first registers a handler for the SDK's bugjar:ready event and calls BugJar.init({...}) with your config and hooks; the second loads the SDK from your project's URL. The URL identifies your project, so init() doesn't need a projectKey — the server inlines it ahead of the bundle. The trigger button appears bottom-right of every page where the snippet is loaded.
Ordering: the synchronous inline script registers the listener during HTML parse, before the deferred module SDK script can fire the event. Listener is always registered in time — no race condition.
Changes you make in the dashboard propagate within ~60 seconds on the next page load — no need to re-paste the snippet when you flip a setting.
The SDK ships from BugJar's own origin — no third-party CDN reference in your HTML, no extra origin in your Content-Security-Policy allowlist. Copy the snippet from your dashboard so the project key is pre-filled.
Get your project key
The project key lives in your BugJar dashboard at Settings → Projects → Your project. It looks like proj_live_01kqt7z6f5.... The key is safe to embed client-side — it identifies the project, not the user, and the redaction + presigned-URL flow keeps customer data out of our servers regardless.
Configuration
BugJar.init(config) accepts the following. All fields are optional — projectKey is auto-filled from the inlined window.__BUGJAR_CONFIG__ the dashboard serves alongside the SDK bundle.
Top-level
| Option | Type | Default | Notes |
|---|---|---|---|
projectKey |
string |
from inlined config | Override only if you need to target a different project from the one this SDK URL was generated for (rare). |
user |
{ id, metadata? } |
none | Identifies the end user reporting the bug. Attached to every submission from this session. |
userToken |
string (JWT) |
none | Server-signed JWT identifying the user. Required when the project is in HMAC verification mode. Sign on your backend, never in the browser. See User identity. |
strictMode |
boolean |
false |
When true, every redaction category — including the optional ones the dashboard would normally let you relax via capture invitations — is enforced. Use for compliance-critical surfaces. |
captureTokenParam |
string |
'bugjar_capture' |
Query-string parameter name the SDK reads to pick up a capture-invitation token. Rename if it collides with your routing. |
onReportSubmitted |
(reportId: string) => void |
noop | Fires after a successful upload. Useful for analytics, success toasts, or chaining your own UI. |
onError |
(err: Error) => void |
noop | Fires on upload, capture, or token-resolution failures. Errors are also surfaced inside the consent panel; this hook is for your monitoring. |
capture — what gets recorded
BugJar.init({
projectKey: 'proj_live_...',
capture: {
maxDurationSec: 90,
captureNetwork: true,
captureConsole: true,
captureMicrophone: true,
networkBufferSize: 100,
consoleBufferSize: 500,
},
});
| Option | Default | Notes |
|---|---|---|
maxDurationSec |
90 |
Hard cap on how long a single recording can run. The user can stop earlier; this is the ceiling. |
captureNetwork |
true |
Buffer the last N HTTP requests in memory. Headers and bodies pass through the redaction pipeline before joining the manifest. |
captureConsole |
true |
Buffer the last N console.* calls and unhandled errors. Same redaction pipeline. |
captureMicrophone |
true |
Offer microphone narration in the consent panel. The user still grants browser permission at record time — this just shows or hides the option. |
networkBufferSize |
100 |
Ring-buffer size for network entries. Lower if your app is chatty and you don't need the full window. |
consoleBufferSize |
500 |
Ring-buffer size for console entries. |
DOM replay (rrweb) and the in-page drawing tool are always on when the user enables them in the consent panel — there are no init flags for those. To exclude specific DOM nodes from replay, mark them with data-bugjar-block (excluded entirely) or data-bugjar-mask (layout kept, content masked). See Redaction for the full list of attributes and the always-mask categories.
ui — trigger appearance and behavior
BugJar.init({
projectKey: 'proj_live_...',
ui: {
position: 'bottom-right',
primaryColor: '#ea580c',
showTrigger: true,
showOnError: false,
triggerLabel: 'Report a bug',
},
});
| Option | Default | Notes |
|---|---|---|
position |
'bottom-right' |
One of 'bottom-right', 'bottom-left', 'top-right', 'top-left'. |
primaryColor |
'#ea580c' |
Any CSS color string. Drives the trigger fill, the consent-panel accent, and the record button. |
showTrigger |
true |
When false, the SDK doesn't render its built-in pill. You bring your own UI element and call BugJar.open() from your click handler. |
showOnError |
false |
When true, the trigger stays hidden until the page hits a console.error, an unhandled exception, or a 4xx/5xx response. After that it appears and stays for the rest of the page. Composes with showTrigger: if showTrigger is false, this does nothing. |
triggerLabel |
'Report a bug' |
Label inside the built-in trigger. Override to match your product voice ('Send feedback', 'Found something?', etc.). |
User identity
Two ways to attach the end user to reports — pick whichever matches your project's verification mode (set in Settings → Projects → Verification).
Open mode — pass user directly:
BugJar.init({
projectKey: 'proj_live_...',
user: { id: 'usr_42', metadata: { plan: 'pro', orgId: 'org_8' } },
});
The metadata object is opaque to BugJar — anything JSON-serializable works. Shown alongside the report in the dashboard.
HMAC mode — sign a JWT on your backend, pass userToken:
// Server (any language). HS256, signed with the project's signing_secret.
// Required claims: sub (user id), exp (≤ 1 hour after iat).
// Optional: email, metadata.
const token = jwt.sign({ sub: 'usr_42', email: '[email protected]' }, SIGNING_SECRET, { expiresIn: '1h' });
// Browser
BugJar.init({
projectKey: 'proj_live_...',
userToken: token,
});
The SDK forwards the token; the BugJar API verifies the signature and rejects unsigned submissions. Use this whenever you need to prove the report came from the user it claims — support escalation flows, paid-tier gating, anything you'd otherwise need to cross-reference against your auth system.
Custom triggers
If showTrigger: false, drive the SDK from your own UI:
BugJar.init({ projectKey: 'proj_live_...', ui: { showTrigger: false } });
document.querySelector('#my-feedback-button').addEventListener('click', () => {
BugJar.open();
});
BugJar.close() cancels an in-progress capture. See Customize the trigger for header-menu, hotkey, and contextual-button patterns, or API reference for the complete runtime surface.
What happens next
When the user clicks the trigger:
- A consent panel explains what's about to be recorded.
- They choose what to capture (replay, microphone, drawing).
- They reproduce the bug, narrate, draw — for up to
maxDurationSecseconds. - They review the redacted output, then click Send.
- Your dashboard pings. The replay is ready.
For redaction details, see Redaction.