The context you need to reproduce a bug is already in the reporter's browser

This is me

This is me

A bug report arrives as a screenshot in Slack and the words "it's broken".

No URL. No browser. No viewport. No idea what was clicked. So you ask, and by the time the answer comes back the person has lost the thread of what they were doing, and half the time the answer is wrong anyway because nobody reads their own user agent for fun.

What is frustrating about this is that none of that information was ever missing. It was all sitting in the reporter's browser at the exact moment they decided something was wrong. It just had no way to travel with the complaint.

Ask nothing, capture at report time

The design follows from one observation: the moment the user clicks "report" is the moment the context is still true.

Not five minutes later in a Slack thread, when they have navigated away. Not in a form that asks them to type their browser version. At the click, window.location, the user agent, the viewport, the locale and the referer are all right there and all free:

'capture_context' => true,

That is the whole feature, and it removes the entire first round trip of every bug conversation. It is also the reason the widget has to live inside the app rather than being a link to a form: a separate reporting page would capture the context of the reporting page, which is the one page that is definitely working.

The flag exists because collecting a user agent and a URL is still collecting data about a person, and some apps will not want to. Defaulting it on is the right call for the common case; making it undeletable would not be.

Recording with the browser, not with a vendor

Text plus a URL still loses the interactions. "I clicked the thing and it did the wrong thing" needs motion to be reproducible, and screenshots freeze exactly the wrong instant.

Every hosted feedback tool solves this with a session replay recorder, and the way they solve it is instrumenting your app permanently. A script that runs on every page for every user, watching the DOM, streaming to somebody else's servers, so that the small fraction of sessions containing a bug are already captured when someone reports one.

That trade is bad in both directions for the apps I build. It sends my users' sessions to a third party by default, and it pays a continuous runtime cost for a rare event.

So recording is native and opt-in at the moment of use: getDisplayMedia and MediaRecorder, both in the browser already. No encoding library, no vendor, no server contact until the report is actually sent. Before the click, the cost is exactly zero: there is nothing running.

The consequence is that you only capture from the click onward, so the user has to reproduce the bug rather than hand over the past. That is the real cost of the choice and I think it is worth paying. It also forced a small design detail: the modal has to get out of the way once recording starts, because the bug is somewhere else in the app. So it closes, and a floating overlay with a timer and Stop/Discard takes over until they come back.

One nice accident of living in the page's JS context: recording survives wire:navigate, so a user can wander across a Livewire app mid-capture. A hard reload kills it and there is nothing to be done about that.

The reports are rows in your database

They land in wirebug_reports, in your database, reachable with Eloquent:

BugReport::new()->latest()->get();
$report->reporter;   // User, Client... or null for a guest

reporter is polymorphic because "who reported this" is not the same shape in every app, and a screenshot goes through Laravel's Storage so the row holds a path and a local disk behaves like S3.

The point of all of it is that a bug report is application data. It joins against your users, it filters by your tenants, it gets a triage screen built with the same tools as everything else. In a hosted tool it is data about your app that lives outside your app, that you query in someone else's UI, and that you cannot join to anything.

If I had to defend one decision here it is this one. The recording is the feature people notice; the table is the feature that matters in a year.

Installation, the trigger styles, config and the model API are on the Wirebug page. Source on GitHub, package on Packagist.