Get started
One script tag
For a site with no build step — a WordPress theme, a static page, a client
site somebody else deploys — dist/bugbottle.js is a self-contained bundle
that mounts the panel from the tag itself, the annotator included. About
23.9 kB gzipped:
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bugbottle.js"
data-endpoint="/api/feedback"
data-locale="da"
data-primary="#e11d48"
data-brand="Mahope"
></script>dist/ is committed, so the same file is on jsDelivr from the git tag as well:
https://cdn.jsdelivr.net/gh/mahope/[email protected]/dist/bugbottle.js. Pin a
version in either form; @latest is a way to have a stranger's next release
run on your page.
Two builds #
There are two files, and they are the same panel:
| File | Gzipped | What is in it |
|---|---|---|
dist/bugbottle.js |
24.2 kB | Everything: the annotator, the timings and storage snapshot, shake-to-report and the network log, all switchable from an attribute. |
dist/bugbottle.slim.js |
20.6 kB | The same panel, the console, breadcrumbs, the element picker, the offline queue, the scrubber, the signer and all eight locales — without those four. |
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bugbottle.slim.js"
data-endpoint="/api/feedback"
></script>From the git tag it is
https://cdn.jsdelivr.net/gh/mahope/[email protected]/dist/bugbottle.slim.js.
The slim build reads every attribute in the table below except four, which it
ignores because the code behind them is not in it: data-annotate,
data-perf, data-shake and data-network. Write one and it says
so on the console once, in English — that is a message to whoever wrote the
script tag, not to the reporter, so it is not translated. window.bugbottle
is the same namespace without createAnnotator, initPerf, onShake,
requestShakePermission and initNetwork.
The saving is smaller than the four modules weigh on their own, because inside one bundle they share gzip's dictionary, and two of their costs stay behind on purpose: the annotator's labels are in all eight locales, which are data, and the panel's own annotator toolbar is a static import. Every language still works in the slim build; that is the trade it makes.
| Attribute | Effect |
|---|---|
data-endpoint |
Where the report is POSTed. Required — without it nothing mounts. |
data-locale |
Language tag through resolveLocale. Defaults to <html lang>, then English. |
data-position |
bottom-right (default), bottom-left, top-right, top-left. |
data-primary |
Accent colour of the button and the primary action. |
data-brand |
Name in the panel header. |
data-logo |
Image URL shown before the title and on the trigger. |
data-trigger |
Selector for your own button. Without it, the floating one is rendered. |
data-contact |
Present, with any value, asks the reporter how to reach them; required also refuses to send without it. Off without the attribute. |
data-scrub |
Present, with any value, redacts the report with scrubReport before it is sent. |
data-network |
Present, with any value, records the failed and slow requests. The same switch as the panel's network option. See "What the network did". |
data-perf |
Present, with any value, records the Web Vitals and lists what is in the browser's stores — names and lengths, never values. The same switch as the panel's perf option. See "Performance and storage". |
data-sign-key |
Signs the body with this key. A key in the page source is public, so this deters spam rather than authenticating anybody; see Signing requests. |
data-queue |
Present, with any value, keeps a failed report in localStorage and sends it when the browser is online again. With data-sign-key the queued reports are signed at delivery too. See "When the network is down". |
data-extra |
JSON object merged into every report, e.g. data-extra='{"appVersion":"1.4.2"}'. |
data-mask="off" |
Stops masking the screenshot. Only matters once you give mount a renderer; see Masking. |
data-annotate="off" |
Leaves out "Edit picture" and its rectangle, arrow and blur. This build carries the annotator, so the attribute only switches it off; it does not make the file smaller. Only matters once you give mount a renderer; see Marking the picture. |
data-shortcut |
The combination that opens the panel. mod+shift+b unless you say otherwise; off installs no listener. |
data-shake |
Present, with any value, opens the panel when the phone is shaken; a number is the threshold in m/s² (data-shake="12" is a lighter flick). On iOS nothing arrives until the page calls window.bugbottle.requestShakePermission() from a button of its own. See "Shake to report". |
data-open-on-error |
Present, with any value, opens the panel on an uncaught error. prefill also fills the message in. |
The tag also patches the console immediately and starts breadcrumbs, so an error thrown before the page finishes loading is still in the report.
There is no screenshot in this build. A renderer means html-to-image, which
is far larger than everything else here put together, and forcing it on every
page that only wants the panel is the wrong trade. The bundle exposes the
building blocks on window.bugbottle — mount (mountBugbottle),
initConsoleBuffer, initBreadcrumbs, initNetwork, initPerf,
createQueue,
locales, resolveLocale, scrubReport, buildReport, sendReport,
pickElement, createAnnotator, onShortcut, onUncaughtError,
onShake, requestShakePermission and
version — so a
page that wants pictures can load html-to-image itself and call
window.bugbottle.mount({ endpoint, screenshot }). Leave data-endpoint off
the tag and nothing mounts on its own:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bugbottle.js"></script>
<script>
window.bugbottle.initConsoleBuffer();
window.bugbottle.mount({
endpoint: "/api/feedback",
locale: window.bugbottle.locales.da,
scrub: window.bugbottle.scrubReport,
});
</script>Subresource integrity. A CDN is a third party executing code on your site. Pin the file with its hash so a swapped file cannot run:
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bugbottle.js"
integrity="sha384-…"
crossorigin="anonymous"
data-endpoint="/api/feedback"
></script>jsDelivr shows the hash on the file's page, or compute it yourself:
curl -s <url> | openssl dgst -sha384 -binary | openssl base64 -A. The hash
changes with every version, so it has to be updated with the version.