Open source July 2026
Wirebug

Wirebug

Wirebug

Wirebug is a drop-in feedback widget for Laravel. It captures the technical context of a bug report automatically, optionally records the user's screen through native browser APIs, and stores everything in your own database.

Installation

composer require edulazaro/wirebug
php artisan migrate

The migration is registered by the package, so there is nothing to publish to run it.

Dependencies worth knowing. The report form renders as a modal from wiremodal (Composer installs it automatically) and every open and close goes through window.Wiremodal. Alpine.js and wiremodal must both be present on the page. If wiremodal's JavaScript is not loaded, clicking the button silently does nothing.

The CSS is not injected for you, and the import order matters: wiremodal first, then wirebug, which builds on top of it.

@import '../../vendor/edulazaro/wiremodal/resources/css/wiremodal.css';
@import '../../vendor/edulazaro/wirebug/resources/css/wirebug.css';

With the order reversed the modal renders unstyled.

Usage

The whole integration surface is one Blade component, usually placed in the logged-in app shell:

<x-wirebug />

Wirebug shares the wire* theme attribute with wiremodal, wiretoast and wirecookies:

<html data-wire-theme="studio">

Trigger styles

The default is a floating square button in a bottom corner. The alternative is an edge tab stuck flush to the side of the screen, which drops its label and shows only the icon on narrow viewports.

<x-wirebug trigger="tab" position="bottom-right" tab-label="Feedback" />

Every visible string is overridable through a prop (title, tab-label and the rest) or you can publish the translations and manage the text in language files.

Screen recording

When the user clicks record, Wirebug uses the browser's native getDisplayMedia and MediaRecorder. No encoding library, and no server involved until the report is sent. Nothing records until that click.

Once recording starts the modal closes and a small in-app overlay takes over with a live timer plus Stop and Discard controls, so the user can reproduce the bug across the app. On stop, the modal reopens with the video already attached.

'recording' => [
    'enabled'     => true,
    'max_seconds' => 90,
    'max_kb'      => 51200,
    'bitrate'     => 2000000,
],

Two megabits is plenty to read a UI and keeps a full ninety seconds comfortably under the size limit.

Behaviour to know: the recording lives in the page's JavaScript context, so it survives wire:navigate navigation, and a user can start recording on one screen and keep going as Livewire swaps pages. A hard reload ends it, because the browser discards the JS context.

The record button only appears on desktop browsers that support the API.

What gets stored

Reports live in a wirebug_reports table in your own database. Alongside the message, Wirebug captures the current URL, the user agent, the viewport, the app locale and the referer, with no input from the user. Set the capture_context config flag to false to disable that block.

An optional screenshot goes through Laravel's Storage on whatever disk you configure; the row keeps only the path, so local and S3-compatible disks behave identically.

Reading reports back

use EduLazaro\WireBug\Models\BugReport;

BugReport::new()->latest()->get();   // fresh reports, status 'new'
BugReport::ofType('bug')->get();
$report->reporter;                   // the User, Client... or null for a guest

reporter is a polymorphic relation, so a triage screen is a few queries and no extra schema.

Careful with the type keys. They are bug, idea and other, and the middle one is labelled "Suggestion" in the UI. Filtering for suggestions is BugReport::ofType('idea'), not ofType('suggestion').

Front-end hook

Wirebug dispatches a wirebug-sent event on window after a successful send.

built and maintained by Edu Lazaro · MIT license