Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Notification Preview Laravel Package

pxlrbt/laravel-notification-preview

Preview Laravel notifications in the browser without sending them. Render mail, database, and broadcast notifications to check their look and content before they reach real users, speeding up development and testing of every notification class.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it as a dev dependency — it is a local development tool, not a runtime dependency:

composer require pxlrbt/laravel-notification-preview --dev
php artisan vendor:publish --provider="Pxlrbt\NotificationPreview\NotificationPreviewServiceProvider"

The publish creates config/notification-preview.php, which is the first file to read. Expect keys for the route path/prefix, the middleware stack applied to the preview routes, an authorization callback or gate, and the directories that get scanned for classes (typically app/Notifications and app/Mail). Adjust the path if /notification-preview collides with an existing route.

Boot php artisan serve and open the preview route in the browser. You get an index of every discovered notification and mailable class. Click one and the package instantiates it and calls the relevant rendering method against a notifiable you pick, showing mail as HTML and as the plain-text alternative, and database / broadcast channels as their raw payload.

First use case: you have an InvoicePaid notification whose toMail() returns a Mailable with a Blade view. Instead of sending yourself an email, wiring Mailhog, or dumping (new InvoicePaid($invoice))->toMail($user)->render() in tinker, you open the preview, pick the notification, pick a User notifiable, and iterate on the Blade template with a normal browser refresh. That edit → refresh → inspect loop is the entire value proposition; everything below is about making that loop reliable.

Implementation Patterns

Register representative notifiables. The preview needs a $notifiable to render against, and User::first() is rarely representative. Most installs end up with a small map in the config (or a dedicated seeder) that returns realistic instances — a paid invoice, a user with an avatar and a name containing an umlaut, a team account. Treat this map as fixture data and keep it in version control: the preview is only as good as the model it renders against, and "it looked fine in the preview" is a common source of missing-data bugs in production emails.

Iterate mail in two passes. Design the HTML first, then immediately flip to the text tab. Laravel's text version is generated from the Markdown/Blade source, and long URLs, tables, and button-only CTAs consistently break there. Reviewing both tabs in the same session is the cheapest way to catch it.

Preview payloads, not sends. For database and broadcast channels the package shows the array your toDatabase() / toBroadcast() / toArray() returns. Use this to sanity-check field names against the frontend that will consume them — a renamed key in toArray() is otherwise only discovered when the bell icon in the UI goes blank.

Guard it like a debug tool. The default middleware is web; that is not access control. In config/notification-preview.php add auth (or auth:admin), and register an authorization callback that checks environment or a gate ability. Better still, wrap the whole thing:

// config/notification-preview.php
'middleware' => ['web', 'auth'],
'enabled' => env('APP_ENV') === 'local',

Previews render real notification content — customer names, invoice amounts, password-reset links, signed URLs. A preview route reachable from staging is a data leak with a friendly UI.

Use it as review artifact. Because mail renders as static HTML, you can screenshot the preview route in a browser test (Dusk/Pest browser plugin) or via a headless-Chrome step in CI, and attach the image to the PR that changes a mail template. That converts "design reviewed the email" from a manual forward-to-yourself ritual into a build artifact.

On-demand notifications. For notifications implementing routeNotificationForMail() / routeNotificationFor*() on the notifiable, the preview follows the same path resolution the real send would. Verify on-demand variants (no User model, just an address) by previewing with the on-demand configuration the package exposes; those are the code paths most likely to break because they're rarely exercised by real traffic.

Gotchas and Tips

Constructor dependencies are the number-one failure. Notifications and Mailables with required constructor arguments (__construct(public Order $order)) can't be instantiated without a factory. The package uses reflection to build the class; anything it can't resolve either errors or requires you to supply a binding. The pragmatic fix is to keep one no-arg "kitchen sink" notification per template, or bind a preview factory in a service provider so the reflection path resolves. Plan for this before you refactor notifications to constructor injection — it's the main friction point new adopters hit.

Discovery is path-based and often cached. Classes outside the configured directories (e.g. app/Domain/Billing/Notifications) silently won't appear. After adding a notification, if it's missing from the index, run php artisan optimize:clear — a cached config or a cached class list is the usual culprit, not a package bug.

Side effects inside toMail() still run. No notification is dispatched, but any query, API call, or Storage read inside your rendering code executes against whatever database the app is pointed at. Never run the preview against a production connection; a notification that lazy-loads relations can also throw LazyLoadingViolationException in strict-mode apps where the real queued job would not.

Payload ≠ persisted record. The database tab shows what toDatabase() returns, not a DatabaseNotification row. Type casting, data column serialization, and the shape your frontend reads are all still your responsibility.

Custom channels aren't rendered. Slack, SMS, Expo, etc. have no renderer — at best you see the raw array. Don't expect the preview to validate those; keep a dedicated test for them.

Attachments and embeds can be fragile. ->attachData() is fine, but ->embed() / ->attach() with relative paths resolve against the preview request, not the queue worker's CWD. If a mail previews with a broken logo but sends correctly, this is why.

Locale and timezone. Previews render in the app's current locale and the configured timezone. Formatted dates and translated copy will look wrong compared to the recipient's actual locale unless you switch app()->setLocale() in middleware or a query parameter. Add a locale switcher to your preview middleware if you ship in more than one language.

Route caching. Preview routes registered conditionally won't survive php artisan route:cache in production — which is fine, since you don't want them there. If you ever see "route not defined" after deploying a build that ran route:cache locally, that's the cause.

Version and platform currency. Pin ^1.1 and confirm the PHP constraint matches your runtime. v1.1.0 was a compatibility-only release adding Laravel 13 support — no API change, no migration. Treat future 1.x bumps the same way: opportunistic patch-level adoption, but re-run your suite against the new Laravel major, since a compatibility bump is a signal of maintenance health rather than a formal support guarantee. Also confirm whether 1.1.0 narrowed support for older Laravel versions before assuming the line covers an app still on 11 or 12.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast