SDK reference

Customize the trigger button

Re-skin the built-in trigger, show it only when something breaks, or hide it entirely and drive the SDK from your own UI.

The SDK ships with a small "Report a bug" pill mounted in a screen corner. Most customers leave it as-is — it's recognizable, low-stakes, and matches the default brand. When you want something different, the trigger has three customization layers, from light to heavy:

  1. Tweak the built-in pill — color, position, label.
  2. Hide it until something breaks — reveal on first error.
  3. Replace it with your own UI element — your button, your placement, your event handler.

Every option lives under ui in BugJar.init(). All are optional; defaults are sensible for "drop the script tag and ship." All examples below assume you're calling init() from inside the bugjar:ready listener documented in Getting started.

1. Tweak the built-in pill

window.addEventListener('bugjar:ready', () => {
  BugJar.init({
    ui: {
      position: 'bottom-right',     // bottom-right | bottom-left | top-right | top-left
      primaryColor: '#ea580c',      // any CSS color
      triggerLabel: 'Report a bug', // any string
    },
  });
});
Option Default Notes
position 'bottom-right' Pin to any of the four screen corners. The pill keeps a small inset from the edge; if your app already has UI in that corner (intercom, livechat), pick a different one.
primaryColor '#ea580c' Drives the pill background, the consent-panel accent, and the in-progress record button. Any valid CSS color works ('#ff66aa', 'rgb(20, 99, 220)', named colors).
triggerLabel 'Report a bug' The text inside the pill. Swap for your product voice — 'Send feedback', 'Found a bug?', 'Tell us'. Keep it short; the pill auto-sizes but very long strings will look awkward on mobile.

Examples

// Subtle on a corporate dashboard
ui: { primaryColor: '#475569', triggerLabel: 'Send feedback' }

// Vibrant on a marketing site
ui: { primaryColor: '#ff007a', position: 'bottom-left', triggerLabel: 'Tell us 👋' }

// Match a dark theme
ui: { primaryColor: '#22d3ee' }

2. Show only when something breaks

If you don't want a permanent "report a bug" affordance on every page (it can read as "we expect this to break"), set showOnError: true. The trigger stays hidden until the SDK observes a console.error, an unhandled exception, or a 4xx/5xx network response — then it slides in and stays for the rest of the page lifetime.

window.addEventListener('bugjar:ready', () => {
  BugJar.init({ ui: { showOnError: true } });
});

Composes with the rest of the ui options — you still pick the color, position, and label.

The "what counts as an error" set is broad on purpose — better to reveal the trigger when something might have broken than to hide it through a true bug. Specifically, the SDK observes:

  • Any console.error call.
  • Any unhandled exception or unhandled promise rejection.
  • Any fetch that resolves with response.status >= 400.
  • Any fetch that rejects (network failure, DNS error, CORS preflight failure, user-aborted request).

If your app makes a lot of allowed-to-fail requests — third-party analytics beacons that 404, deliberate aborts on route change — showOnError will trip on them too. For apps with that pattern, stick with the always-visible default or keep the trigger hidden behind your own UI element.

3. Bring your own button

Set showTrigger: false to suppress the built-in pill entirely. Then call BugJar.open() from whatever click handler you want.

window.addEventListener('bugjar:ready', () => {
  BugJar.init({ ui: { showTrigger: false } });
});

document.querySelector('#my-feedback-button').addEventListener('click', () => {
  BugJar.open();
});

BugJar.open() mounts the consent panel; the user picks what to capture and starts the recording from there. BugJar.close() cancels an in-progress capture (rarely useful from your code — the consent panel has its own close button — but exposed for completeness).

Common patterns

Header menu item. Put "Report a bug" in the user dropdown alongside Settings and Sign out:

function UserMenu() {
    return (
        <Menu>
            <MenuItem onClick={() => navigate('/settings')}>Settings</MenuItem>
            <MenuItem onClick={() => BugJar.open()}>Report a bug</MenuItem>
            <MenuItem onClick={logout}>Sign out</MenuItem>
        </Menu>
    );
}

Contextual help on a specific page. Some flows are notorious for bug reports — checkout, onboarding step 3, the integrations page. Add a contextual "Something not working?" link only on those:

<aside class="page-help">
    Something not working?
    <button onclick="BugJar.open()">Record what's happening</button>
</aside>

Keyboard shortcut. Power users like a global hotkey:

window.addEventListener('keydown', (e) => {
    if (e.shiftKey && e.metaKey && e.key === 'B') {
        e.preventDefault();
        BugJar.open();
    }
});

Custom floating action button. If the built-in pill clashes with your design system, render your own and hide ours:

<button
    aria-label="Report a bug"
    onClick={() => BugJar.open()}
    className="fixed bottom-6 right-6 rounded-full bg-pink-500 px-5 py-3 shadow-lg"
>
    🐛 Report
</button>

What you can't customize (yet)

  • Consent-panel styling beyond primaryColor. The accent color is themed, but typography, modal chrome, and the recording controls aren't exposed for override. This is deliberate while the consent flow is still evolving — we don't want to ship a customization surface that constrains the next iteration.
  • The trigger's HTML. The built-in pill is a single rendered element; you can't pass children or restyle internals. Switching to showTrigger: false and rendering your own button is the supported "I want full control" path.
  • Custom animations. The pill uses a small built-in slide-in. There's no override hook.

If one of these is blocking, open an issue on GitHub — they're stable surfaces to add once we know they're being asked for.