Documentation

bugbottle documentation

One page per topic, generated from the project README, so the page you are reading and the file in the repository are the same text. This is version 1.0.1; the changelog has what moved.

Get started

Install it, record the console, and put a form in front of it.

  • InstallInstall bugbottle with npm or one script tag. It keeps a ring buffer of console errors and posts the report to an endpoint you own.
  • Recording console errorsinitConsoleBuffer keeps the last errors and warnings in a ring buffer. Call it once, as early as your application code runs.
  • window.onerror and unhandledrejectionwindow.onerror and unhandledrejection: the two events a browser fires when nothing caught the error, and what bugbottle records from both.
  • The form (React)useBugReport is a form as state: type, message, the file input, the send button and the queued state, over one machine with no React in it.
  • The form (Vue)useBugReport in Vue is refs and computeds over that state machine. type and message are writable, so v-model works on them.
  • The form (Svelte)createBugReport in Svelte is a readable store: $form for the values, and the methods on form for everything the reporter does.
  • The form (Solid)createBugReport in Solid is one signal over that state machine; every value is an accessor, so the JSX tracks exactly what it reads.
  • Catching render errors (React)BugReportBoundary renders your fallback and reports the render error from it. createRootErrorHandlers covers the errors no boundary catches.
  • Opening it without a buttonOpen the report panel with a keyboard shortcut, a shake, a custom event or your own button, using bugbottle/triggers and no floating icon.
  • The form (anything else)No adapter and no framework: buildReport, collectContext and sendReport, and a form is a textarea, a button and somewhere for the picture.
  • When the network is downcreateQueue keeps reports in localStorage or IndexedDB and flushes them when the browser is back online, so an outage does not lose them.
  • The ready-made panelmountBugbottle puts a floating button and a dialog in a shadow root: a form, a screenshot, a queue and eight languages in about 12 kB.
  • One script tagdist/bugbottle.js is the whole widget in one script tag: no build step, no framework, and a data-endpoint attribute instead of a bundler.
  • Languages and brandingEight languages and the --bb-* CSS variables. Every string a reporter sees lives in a Locale, and your stylesheet never meets ours.

Integrations

Where the report goes and which framework it travels through.

  • Every framework, one tableEvery framework in one table: the hook, the file it goes in, and the four classes of failure it misses — Vue, Next.js, Angular, SvelteKit, Astro and more.
  • ReactA plain React app has no error hook of its own. createRootErrorHandlers covers the root, and in React 19 it is not a development-only path.
  • Vueapp.config.errorHandler in a plain Vue app sees nearly everything, and an onErrorCaptured hook returning false deletes the error first.
  • Sveltesvelte:boundary in Svelte 5 and SvelteKit: onerror, failed, the errors the boundary never sees, and the panel on your error page.
  • SvelteKitSvelteKit: adding handleError deletes the console line, the server hook logs where nobody listens, and a server load error is never reported twice.
  • SolidonError and ErrorBoundary in Solid: the boundary that takes the handler’s place, the event handler that reaches neither, and castError’s new stack.
  • Next.jserror.tsx, global-error.tsx and a button on the error page in Next.js: where a render error is reported without losing its console line.
  • AngularCatch Angular errors without losing the console line: app.config.errorHandler, provideBrowserGlobalErrorListeners and the button on your 500 page.
  • Nuxtvue:error, app:error, error.vue and fatal errors in Nuxt, and why showError() deletes the console line the report is built from.
  • AstroAstro has no error handler, so a report is built from astro:hydration-error and your own try/catch. Includes the island that never hydrates.
  • React RouterReact Router v7, v8 and Remix: the declarative and the data error boundary, useRevalidator on the error page, and three modes that differ.
  • TanStack RouterTanStack Router: onCatch never runs without an errorComponent, and the global boundary is silent in production. The one line that fixes both.
  • TanStack QueryTanStack Query has no error boundary and does not throw by default. QueryCache onError, throwOnError, isError, retry, and the trap in each.
  • WordPressThe bugbottle WordPress plugin mounts the panel and adds the route that receives it. One activation, though it is not in the directory yet.
  • HonoReceive a report in Hono, Cloudflare Workers, Deno, Bun and Node: handleReport is a Request in and a Response out, with no adapter to write.
  • FastifyReceive a report in Fastify with fastifyHandler, raise the default 1 MB bodyLimit, and keep the raw body so a signed report verifies.
  • NestJSA NestJS exception filter runs on the server, so it cannot build a report. The browser side is the panel, and the route needs a 5 MB limit.
  • ExpressexpressHandler in Express: the 100 kB express.json() limit that 413s a screenshot, a signed route behind a body parser, and a 500 that pastes a stack trace.

Evidence

What a report carries besides the sentence someone typed.

  • Pointing at the elementpickElement() turns the cursor into a crosshair and resolves with a CSS selector, the element's text and its attributes, so the report names it.
  • What happened beforeinitBreadcrumbs records the last few clicks, navigations and submits, so the report says what the reporter was doing when it broke.
  • What the network didinitNetwork records the failed and the slow requests, never a body and never a header, so 'the save button does nothing' names the fetch.
  • Performance and storageWeb Vitals, long tasks, navigation timings, the JS heap and a storage snapshot, so a report says whether it was slow and what the browser held.
  • Replay with rrwebattachRrweb(record) puts the last half-minute of your own rrweb events in the report, masked, and trimmed to the window and the byte cap.
  • ScreenshotscaptureScreenshot takes a renderer rather than importing one, so html-to-image stays optional. Field values are masked for the render.

Server

Receiving a report, checking it, and sending it onward.

  • Receiving a reporthandleReport is the whole endpoint: it validates every field, scrubs, decides what happens to the screenshot, stores the report and calls the sinks.
  • RecipesThe endpoint is the same everywhere; only the sentence that produces a Request differs. One short recipe per framework and per host.
  • Sending it somewhereEleven sinks in bugbottle/server: Slack, Discord, Teams, mail, GitHub, Linear, Jira, GitLab, Sentry, SMTP and a plain webhook.
  • The payloadThe JSON your endpoint receives, field by field: what is required, what is optional, and which limit applies to each of them.
  • Feeding reports to an agentA report with a selector, the element's text, the page path and the last console errors is usually enough context for a coding agent.

Privacy

The part to read before you turn screenshots on.

  • Please read this partA screenshot holds whatever the reporter could see. Read this before you turn screenshots on, and before bugbottle goes near personal data.

Reference

The exported surface, a round trip you can run, and the Action.

  • APIEvery export in bugbottle, what it takes and what it returns. From 1.0 the list is a contract, and a rename needs a major version.
  • A working exampleA Node server and a plain HTML form with no build step: bugbottle/server receives the report and checks every field in it.
  • GitHub ActionA GitHub Action that validates exported bugbottle reports in CI, so a report that reaches your repository is checked before anyone reads it.
  • ReleasingHow a bugbottle release is cut: the version bump, the changelog, npm run release, and what CI does with the tag afterwards.

About

The answers a data protection question needs, who writes this, and under which licence.

  • A privacy checklistWhat bugbottle collects, where the report goes, how long you keep it, and the questions to have answered before somebody asks them.
  • Who makes itbugbottle is made by Mads Holst Jensen, a freelance developer in Denmark. MIT licensed, no company behind it, and no plan kept secret.
  • Licencebugbottle is MIT licensed, so it is free to use in commercial and closed-source work. There is no other licence and no paid tier.
  • Compared withWhere bugbottle sits next to Marker.io, Jam, Sentry User Feedback, BugPin and rrweb.
  • ChangelogEvery release, what it added, what it fixed and what it cost in bytes.
  • SupportThere is no paid tier. What a donation goes to, what it does not buy, and how to help without money.
  • Self-hostedThere is no server to run. Three ways to receive a report yourself, what it costs to operate, and five traps.