koalafacade/filament-crash
Filament Crash gives your Filament admin panel a graceful crash screen: it catches unhandled exceptions, logs the details, and shows users a friendly error page instead of a raw stack trace, keeping diagnostics available for developers while maintaining a polished experience. Simple to install.
filament-crash is a deliberately hostile plugin: when its condition is met, it takes the Filament admin panel offline so an unpaid client sees a "your project is locked" screen instead of the app. It's a blunt instrument, so treat setup as an ops task, not just a composer require.
Minimal path:
composer require koalafacade/filament-crash
php artisan vendor:publish --tag="filament-crash-config"
Pin the version ("koalafacade/filament-crash": "1.*") — the last release is January 2023, so you want a lockfile you control rather than floating to whatever dev-main looks like today.
Then register it against the panel you want to protect, in app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->id('admin')
->plugin(\KoalaFacade\FilamentCrash\CrashPlugin::make());
}
Where to look first: the published config file. Everything that matters — whether the crash is armed, the message shown, the payment URL — lives there. Read the plugin's composer.json at the same time and compare its filament/filament constraint against your installed major version before you spend time wiring it in.
First use case: the classic one is a staging/production gate. You deploy the client's panel with the crash armed and disabled by a single config value; when the final invoice clears you flip it and run php artisan config:clear. The value of the package is that the "unpaid" state is a first-class, reversible switch rather than a manual return abort(403) you have to remember to remove.
Do not start by arming it in local. Get it rendering the locked screen in a throwaway environment first, confirm the panel comes back when the flag flips, and only then put it in front of a real client.
Environment-scoped arming. The single most important pattern. Never let the crash fire locally or in CI:
// config/filament-crash.php
'enabled' => env('FILAMENT_CRASH_ENABLED', false),
# .env.production
FILAMENT_CRASH_ENABLED=true
Because env() is resolved at config-build time, this survives config:cache correctly — but only if you always change it via .env and re-cache, never by editing the cached config.
Date-based grace period. If the package exposes a check callback (most of these do), use it to arm automatically after a due date rather than relying on you remembering:
'enabled' => fn () => now()->greaterThan(
config('filament-crash.grace_until')
),
This turns the plugin into a "rent is due on the 1st" mechanism instead of a manual kill switch.
Remote / signed check instead of a local flag. A local boolean is trivially defeated — the client edits .env, comments out the plugin line, or runs composer remove. If you actually need enforcement rather than a nudge, back the check with something the client can't fake in five minutes: a signed token fetched from your own license endpoint, validated with a public key, and short-TTL cached. Use the plugin's callback/extension point for this and keep the verification logic in your own package so it's not one config edit away from off.
Panel-scoped application. In a multi-panel app (client admin + your internal support panel), register the plugin on the client panel only. Filament plugins are per-panel; if you register globally you lock yourself out of your own support tooling on the day of the dispute.
Branded lock screen. Publish and override the crash view (resources/views/vendor/filament-crash/...) so the page shows your agency name, invoice reference, and a payment link. A raw 402 or a stack trace reads as "the site is broken" and gets you a support call; a branded page reads as "this is intentional."
Ops workflow. Treat disarming as a deploy: flip the env var, config:cache, hit the login page in a private window, confirm redirect to the dashboard. If you're running multiple app servers, this must go through your normal deploy pipeline — a manual .env edit on one box is how you get a half-locked panel.
filament/filament constraint in composer.json before installing; if it doesn't allow your version, fork it into your own namespace (koalafacade → youragency) rather than forcing the constraint with --ignore-platform-reqs. You want the ability to patch it yourself..env and you flip it without php artisan config:cache, nothing happens and you'll spend an hour debugging a working package./livewire/update XHRs and either render a broken component or throw opaque JS errors instead of your lock screen. Test with a dashboard tab already open — the behaviour that matters is what a logged-in user mid-session sees, not what a cold visitor sees.phpunit.xml should set FILAMENT_CRASH_ENABLED=false, or add an app()->environment('testing') guard. A plugin whose job is to break HTTP is a great way to get a wall of unrelated failing tests.dontReport list, or configure the plugin's "quiet" mode if it has one.How can I help you explore Laravel packages today?