Fejlrapporter, der kommer med beviserne vedhæftet.

Jeg blev ved med at få mails, hvor der stod »Gem-knappen gør ingenting«, og ikke ret meget andet. Det her er den del, der vedhæfter alt det, jeg ellers selv skulle spørge om.

bugbottle samler det, browseren allerede ved, i det øjeblik nogen opdager fejlen: stien, vinduets størrelse, konsolfejlene fra de sidste par minutter, elementet brugeren peger på, og et skærmbillede, hvis du slår det til. Så sender den det hele som JSON til en rute, du selv har skrevet. Intet kontrolpanel, ingen konto, ingen mellemmand. Dine rapporter rammer aldrig mine servere, for dem er der ikke nogen af.

Version 1.0.1, udgivet 8. september 2026. Ingen afhængigheder. Hvad der er ændret.

bugbottle-panelet åbent oven på denne side: en besked om en gem-knap, der ikke gør noget, elementet brugeren har peget på, og en send-knap.
Panelet fra bugbottle/ui, taget her på siden. Knappen i hjørnet åbner det samme.

Hvad det gør, og hvad du selv skriver

Du skriver formularen
Biblioteket holder styr på tilstanden, samler beviserne og sender af sted. Det tegner ikke noget, medmindre du beder om det færdige panel.
Du ejer endepunktet
En rapport er et JSON-kald til en rute, du selv har skrevet. Der er ikke noget, man skal oprette sig hos. Funktionerne, der kontrollerer det, følger med i bugbottle/server.
Det fylder ingenting
Nul afhængigheder og én indgang per del, så en side kun betaler for det, den faktisk importerer. Kernen fylder 1,4 kB gzippet. Tabellen længere nede har resten.
Brugeren kan pege
pickElement() giver en kort CSS-vælger, elementets tag, den synlige tekst og placeringen tilbage. Nok til at jeg, eller en kodeagent, kan åbne den rigtige fil i stedet for at gætte.
Det taler otte sprog
Dansk, engelsk, svensk, norsk, tysk, hollandsk, fransk og spansk. Alle tekster kan skiftes ud, og panelet henter sit udseende fra en håndfuld CSS-variabler. I legepladsen for temaer skifter et rigtigt panel udseende, mens du skruer på knapperne, og koden til at kopiere står nedenunder.
En nedetid koster ikke rapporten
bugbottle/queue gemmer en mislykket afsendelse i localStorage og sender den, når browseren er tilbage. Nægter lageret at tage imod, ryger billedet frem for rapporten — og køen skriver en linje om det i rapporten, så ingen forveksler et tabt skærmbillede med et, der aldrig blev taget. Når netværket er nede (på engelsk).
Serversiden stoler ikke på noget
Alt, hvad browseren sender, bliver behandlet som fjendtligt: længder bliver klippet, nulbytes fjernet, og et skærmbillede kontrolleret på signaturen i de afkodede bytes frem for på den type, det påstår at have.
Der er en tjekliste til privatlivsspørgsmålet
Hvert felt en rapport kan indeholde, hvad der står i det, hvor længe det bør gemmes, og et afsnit du kan skrive ind i din egen persondatapolitik: tjeklisten for privatliv er skrevet til den, der skal svare på spørgsmålet — på dansk, med den engelske udgave ved siden af.

Tre måder at installere det på

Alle tre sender den samme JSON til en rute, du selv skriver. Vælg efter, hvad projektet allerede har.

Med en bundler

Installér det, begynd at opsamle konsolfejl, og montér panelet.

terminal
npm install bugbottle
main.js
import { initConsoleBuffer } from "bugbottle";
import { mountBugbottle } from "bugbottle/ui";
import { da } from "bugbottle/locales";

initConsoleBuffer();
mountBugbottle({ endpoint: "/api/feedback", locale: da });

Ét script-tag

Til et websted uden byggetrin: et WordPress-tema, en statisk side, et kundewebsted som en anden udruller. Det monterer sig selv ud fra data-attributterne.

Der er to filer. bugbottle.js har det hele med; bugbottle.slim.js er det samme panel på alle otte sprog uden tegneværktøjet, målingerne, ryst-for-at-rapportere og netværksloggen — og siger det i konsollen, hvis du beder om en af dem.

index.html
<script
  src="https://cdn.jsdelivr.net/npm/bugbottle@1.0.1/dist/bugbottle.js"
  data-endpoint="/api/feedback"
  data-locale="da"
  data-brand="Acme"
></script>

WordPress

Et plugin, der monterer det samme panel og beholder rapporterne i installationen selv: en privat indholdstype med en liste i wp-admin, valgfri mail, dansk og engelsk. Én aktivering, intet byggetrin, ingen udvikler ved hånden.

Hent pluginet, eller læs indstillingerne først.

Hvad hver indgang koster, målt ved 1.0.1
Import Gzippet
bugbottle 1.4 kB
bugbottle/react 5.7 kB
bugbottle/vue 5.8 kB
bugbottle/svelte 5.6 kB
bugbottle/solid 5.7 kB
bugbottle/ui 11.6 kB
bugbottle/annotate 1.4 kB
bugbottle/breadcrumbs 1.3 kB
bugbottle/network 1.2 kB
bugbottle/perf 1.3 kB
bugbottle/queue 1.5 kB
bugbottle/queue-idb 0.7 kB
bugbottle/triggers 1.3 kB
bugbottle/shake 0.7 kB
bugbottle/sign 0.4 kB
bugbottle/rrweb 0.7 kB
bugbottle/locales-extra 4.7 kB
script-tagget ovenfor 24.6 kB
samme tag, bugbottle.slim.js 21.0 kB

Bundlet med esbuild, minificeret, uden html-to-image. CI fejler, hvis tallene vokser ud over budgettet.

Vil du hellere bygge formularen selv? useBugReport fra bugbottle/react giver dig den samme kerne uden en linje færdig HTML: afsnittet om formularen (på engelsk).

Mangler du et sted at lade rapporterne lande? Kør indbakken: én container, ét kodeord. examples/inbox er en Node-server uden afhængigheder, der tager imod rapporterne, skriver hver enkelt på disken ved siden af sit billede og viser en liste, man kun kan læse, bag INBOX_PASSWORD. Der følger en Dockerfile og en compose.yml med, så en VPS til 30 kroner og et domæne er hele udrulningen.

Åbn panelet, og læs hvad der ville være blevet sendt

Knappen i hjørnet er det rigtige bugbottle/ui-panel med den danske sprogfil, kørende fra den samme dist/, som npm sender ud. Åbn det, skriv en linje, peg på noget her på siden, og tryk send.

Der er ingen server bag. Demoen giver biblioteket sit eget fetch, gemmer den rapport, der ville være blevet sendt, og viser den her med toMarkdown fra bugbottle/server, som er den samme funktion, du ville bruge til teksten i en sag.

Billedet er tegnet, ikke taget. Et rigtigt skærmbillede tegnes af siden med bugbottle/html-to-image, og denne side har ikke noget privat sted at lægge et, så demoen giver panelet en funktion, der maler et forenklet billede af dette afsnit på et lærred — et farvebånd øverst, nogle tekstbjælker og knappen. Vedhæft det, så dukker "Rediger billedet" op: det er den rigtige editor fra bugbottle/annotate med rektanglet, pilen og sløringen.

Rapporten som Markdown

toMarkdown(rapport)

            

Der bliver ikke sendt noget. Der findes ingen server bag siden: rapporten bliver bygget og vist i din egen browser, og lukker du fanen, er den væk. Det billede, siden tegnede, og det du måtte markere på det, går samme vej.

Elleve steder, en rapport kan lande

At gemme en rapport er én ting; at se den er en anden. bugbottle/server har elleve færdige afsendere med — ti af dem er en formatering oven på ét fetch-kald, den ellevte er en lille SMTP-klient, og ingen af dem har en eneste afhængighed:

  • Resend
  • SMTP
  • Webhook
  • Slack
  • Discord
  • Teams
  • GitHub
  • GitLab
  • Jira
  • Linear
  • Sentry

Ingen af dem læser dine miljøvariabler: nøglen, adressen og tokenet er argumenter, så man kan se på kaldet, hvor hemmeligheden kommer fra — og intet af det kan drive med over i en browserpakke. Tabellen i dokumentationen har, hvad hvert enkelt kræver, hvad en rapport bliver til der, hvilke af dem du selv kan hoste, og hvad det koster i en serverpakke at importere det (på engelsk).

Læs det her, før du slår skærmbilleder til

Et skærmbillede af din applikation indeholder alt, hvad den, der melder fejlen, kunne se. I et journalsystem kan det være et billede af en patient; i et lønsystem en løn; i dit måske nogens indbakke eller en halvskrevet besked, der aldrig blev sendt.

Tre ting følger heraf, og dem kan biblioteket ikke gøre for dig:

  1. Læg skærmbilleder et privat sted. Hvis din objektlagring har offentlig læseadgang, og det har mange mediearkiver, kan alt, hvad du lægger derind, hentes af enhver, der kender adressen. Brug en separat lagerplads uden offentlig adgang.
  2. Vis dem kun gennem en rute, der kræver login. Giv aldrig et skærmbillede en offentlig adresse. Slå nøglen op ud fra rækken i databasen frem for at tage den fra forespørgslen, så et id ikke kan bruges til at gennemsøge hele lageret.
  3. Sig det, før billedet bliver taget. Skriv det i formularen ved siden af afkrydsningsfeltet, ikke i en politik, ingen åbner.

Det er også værd at overveje at kræve, at folk er logget ind. Et anonymt skærmbillede er et, ingen bagefter kan spørges om, og ingen kan få at vide er blevet slettet. Hele afsnittet i dokumentationen.

Hvem der skriver på det

Jeg hedder Mads Holst Jensen, er freelance web- og AI-udvikler i Danmark og arbejder under navnet Mahope. bugbottle er blevet til i kundearbejde: to apps, hvor brugerne blev ved med at melde fejl, jeg ikke kunne genskabe. Så byggede jeg den del, der samler beviserne, og pillede stykker af den, indtil den var lille nok til at give væk.

Jeg bygger den slags til andres produkter også: vejen en bruger går, når noget er galt, det interne værktøj ingen har haft tid til, integrationen der skal blive ved med at virke, når jeg er gået igen. Er det dét, du mangler, så skriv og fortæl, hvad det drejer sig om.

Mads Holst Jensen mahoje.dk [email protected]