Notifier by Usama Muneer
CommunityA powerful notification system that handles multi-channel notifications with template management, scheduling, and real-time delivery. Built for developers who need enterprise-grade notifications without the complexity.
Author:
Usama Muneer
Package health
Automated checks of this plugin's Composer package
15 checks
- Passed: GitHub Actions pinned to SHA
- Skipped: GitLab CI includes pinned to SHA
- Passed: Open security advisories
- Passed: Dependabot PR responsiveness — No open Dependabot PRs.
- Skipped: Renovate MR responsiveness
- Failed: Dependabot or Renovate configured — No dependency updater configuration found. View details on Plumb
- Skipped: Dependency update cooldown configured
- Failed: Provides a security policy — View details on Plumb
- Passed: Abandoned or archived — No consulted source marks the package abandoned (packagist, github).
- Passed: Commit and release recency — Active: last commit 1 days ago; last release 96 days ago.
-
Passed:
composer.lock not committed by library
—
composer.lockis absent from the released dist archive. - Passed: Dist archive is lean
-
Passed:
Current Laravel version supported
—
Package dependencies resolve together with current Laravel
13.0. -
Passed:
Current PHP version supported
—
Constraint
^8.3supports current PHP8.5. - Skipped: Current Symfony version supported
filament/
namespace. Review the source and install at your own risk. Found
malware or an unresolved security issue the author won't
address?
Report it
.
Documentation
- Support matrix
- Features
- Installation
- Usage
- Analytics & Tracking
- Rate Limiting
- Configuration
- Database Tables
- API Reference
- Testing
- Roadmap (not in 2.0)
- Available Commands
- Contributing
- License
- Architecture & Design
- Screenshots
- Support
A powerful notification system for FilamentPHP that handles multi-channel notifications with template management, scheduling, and real-time delivery. Built for developers who need enterprise-grade notifications without the complexity.
See UPGRADE.md when moving from 1.x, and CHANGELOG.md for what shipped in 2.0.
#Support matrix
| Package | PHP | Laravel | Filament |
|---|---|---|---|
| 2.x | 8.3–8.5 | 11, 12, 13 | 4, 5 |
| 1.5 | 8.2+ | 11, 12, 13 | 4, 5 |
| 1.4 | 8.2+ | 11, 12 | 4, 5 |
#Features
- Multi-channel: Email, in-app (Filament bell), SMS (Twilio), Slack, Discord, and Push (FCM HTTP v1)
- Template management:
{{variable}}substitution (HTML-escaped in emails;{{{variable}}}for trusted HTML) - Scheduled notifications: Queue a send for a specific time (dispatched once)
- Event-driven: Trigger notifications from application events stored in the admin panel
- User preferences: Filament page,
<livewire:notifier-preferences />, and an authenticated REST API - Unsubscribe: Signed one-click links and
List-Unsubscribeheaders - Retries and webhooks: Backoff, fallback channels, and inbound Mailgun / Postmark / SES / Twilio delivery status
- Analytics dashboard: Opens, clicks, channel performance. Treat click rate as the primary metric — Apple Mail Privacy Protection inflates opens
- Signed click tracking: Tracking redirects are signed; unsigned links only follow the app host or
allowed_hosts - Rate limiting: Global, optional per-user / per-channel, with
dropordeferwhen a limit is hit Notifier::fake(): Record sends in host-app tests- CI: GitHub Actions generated by laravel-slipway
#Installation
#1. Install the Package
composer require usamamuneerchaudhary/filament-notifier
#2. Run the Installation Command
php artisan notifier:install
This command will:
- Publish the configuration file
- Run the necessary migrations
- Create sample notification channels and templates
- Set up the basic structure
#3. Register the Plugin
Add the plugin to your Filament panel configuration:
use Usamamuneerchaudhary\Notifier\FilamentNotifierPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentNotifierPlugin::make(),
]);
}
After registration, you'll have access to:
- Notifier Dashboard - Comprehensive analytics and metrics
- Notification Settings - Configure preferences, analytics, and rate limiting
- Notification Preferences - Let panel users manage their own channels (hide with
->preferencesPage(false)) - Notification Resources - Manage channels, events, templates, and notifications
#In-app (Filament bell) channel
The in_app driver writes to Laravel's notifications table via Filament\Notifications\Notification::sendToDatabase(). Before using it:
php artisan make:notifications-table
php artisan migrate
Enable database notifications on the panel:
return $panel
->databaseNotifications()
->plugins([
FilamentNotifierPlugin::make(),
]);
Pass optional template data: action_url, action_label, status (info|success|warning|danger), and icon. Set broadcast on the channel to also push through Echo.
#4. Configure Channels
Update your .env file with your notification channel settings:
# Email Configuration
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="Your App"
# Notifier Package Settings
NOTIFIER_EMAIL_ENABLED=true
NOTIFIER_SLACK_ENABLED=false
NOTIFIER_SMS_ENABLED=false
# Slack Configuration
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
SLACK_CHANNEL=#notifications
# SMS Configuration (Twilio)
TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_PHONE_NUMBER=+1234567890
#Usage
#Basic Notification Sending
use Usamamuneerchaudhary\Notifier\Facades\Notifier;
// Send a notification using the facade
Notifier::send($user, 'user.registered', [
'name' => $user->name,
'email' => $user->email,
]);
// Or using the service directly
$notifier = app('notifier');
$notifier->send($user, 'user.registered', [
'name' => $user->name,
'email' => $user->email,
]);
#Using Service Facades
The package provides convenient facades for accessing services:
use Usamamuneerchaudhary\Notifier\Facades\Preference;
use Usamamuneerchaudhary\Notifier\Facades\Analytics;
use Usamamuneerchaudhary\Notifier\Facades\UrlTracking;
use Usamamuneerchaudhary\Notifier\Facades\NotificationRepo;
// Get user preferences
$preferences = Preference::getUserPreferences($user, 'user.registered');
// Check analytics status
if (Analytics::isEnabled()) {
Analytics::trackOpen($notification);
}
// Safely redirect URLs
return UrlTracking::safeRedirect('https://example.com');
// Find notification by token
$notification = NotificationRepo::findByToken($token);
Note: After installing the package, run composer dump-autoload to register the facades.
#Dependency Injection (Recommended)
For better testability, use dependency injection in your controllers and services:
use Usamamuneerchaudhary\Notifier\Services\PreferenceService;
use Usamamuneerchaudhary\Notifier\Services\AnalyticsService;
class MyController extends Controller
{
public function __construct(
protected PreferenceService $preferenceService,
protected AnalyticsService $analyticsService
) {}
public function index()
{
$preferences = $this->preferenceService->getUserPreferences($user, 'event.key');
if ($this->analyticsService->isEnabled()) {
// Do something
}
}
}
#Scheduled Notifications
use Carbon\Carbon;
// Schedule a notification for later
$notifier->schedule($user, 'reminder.email', Carbon::now()->addDays(7), [
'task_name' => 'Complete project review',
]);
#Event-Based Notifications
Create events, templates and their default channels in the Filament admin (Notifier → Events). You can also register an event in code:
app('notifier')->registerEvent('user.registered', [
'channels' => ['email', 'in_app'],
'template' => 'welcome-email',
'fallbacks' => ['email' => 'sms'],
]);
send(), sendToChannel() and schedule() all honour the recipient's preferences.
#Testing with Notifier::fake()
use Usamamuneerchaudhary\Notifier\Facades\Notifier;
$fake = Notifier::fake();
// code that calls Notifier::send($user, 'user.registered', [...])
$fake->assertSent('user.registered');
$fake->assertSentTo($user, 'user.registered');
$fake->assertSentTimes('user.registered', 1);
$fake->assertNotSent('order.shipped');
$fake->assertSentCount(1);
#Unsubscribe
Emails include a signed {{unsubscribe_url}} and List-Unsubscribe / List-Unsubscribe-Post headers (RFC 8058). GET /notifier/unsubscribe/{user} shows a confirmation page; POST performs the unsubscribe. Embed the same preference grid anywhere with:
<livewire:notifier-preferences />
#Delivery webhooks
POST /notifier/webhooks/{mailgun|postmark|ses|twilio} updates delivered, bounced and complained. Each provider verifies its own signature. Configure keys in config/notifier.php under webhooks. Failed notifications can be retried from the notifications table (row action or Retry failed bulk action). Configure per-event fallbacks as fallbacks => ['email' => 'sms'].
#Continuous integration
This package's GitHub Actions workflow is generated by laravel-slipway. Edit slipway.php, then:
composer slipway:compile
Commit both slipway.php and .github/workflows/slipway.yml. Do not edit the YAML by hand; the slipway-guard job fails if they drift.
#Creating Templates
Templates can be created through the Filament admin panel or programmatically:
use Usamamuneerchaudhary\Notifier\Models\NotificationTemplate;
NotificationTemplate::create([
'title' => 'Welcome Email',
'key' => 'welcome-email',
'type' => 'email',
'subject' => 'Welcome to {{app_name}}, {{name}}!',
'content' => 'Hi {{name}},\n\nWelcome to {{app_name}}! We\'re excited to have you on board.',
'variables' => [
'name' => 'User\'s full name',
'app_name' => 'Application name',
],
]);
#Custom Channel Drivers
Create custom channel drivers by implementing the ChannelDriverInterface:
use Usamamuneerchaudhary\Notifier\Services\ChannelDrivers\ChannelDriverInterface;
use Usamamuneerchaudhary\Notifier\Models\Notification;
class CustomChannelDriver implements ChannelDriverInterface
{
public function send(Notification $notification): bool
{
// Your custom sending logic here
return true;
}
public function validateSettings(array $settings): bool
{
// Validate your channel settings
return !empty($settings['api_key'] ?? null);
}
}
#User Preferences API
The package provides a simple REST API for users to manage their notification preferences. All endpoints require authentication and respect the allow_override setting configured in the admin panel.
#Get All User Preferences
GET /api/notifier/preferences
Authorization: Bearer {token}
Response:
{
"data": [
{
"event_key": "user.registered",
"event_name": "User Registered",
"event_group": "User",
"description": "Sent when a new user registers",
"channels": {
"email": true,
"sms": false,
"push": true
}
}
]
}
#Get Available Events and Channels
GET /api/notifier/preferences/available
Authorization: Bearer {token}
Response:
{
"data": {
"events": [
{
"key": "user.registered",
"name": "User Registered",
"group": "User",
"description": "Sent when a new user registers",
"default_channels": ["email"]
}
],
"channels": [
{
"type": "email",
"title": "Email",
"icon": "heroicon-o-envelope"
},
{
"type": "sms",
"title": "SMS",
"icon": "heroicon-o-device-phone-mobile"
}
]
}
}
#Get Preference for Specific Event
GET /api/notifier/preferences/{eventKey}
Authorization: Bearer {token}
Example:
GET /api/notifier/preferences/user.registered
Response:
{
"data": {
"event_key": "user.registered",
"event_name": "User Registered",
"event_group": "User",
"description": "Sent when a new user registers",
"channels": {
"email": true,
"sms": false
}
}
}
#Update Preference for Event
PUT /api/notifier/preferences/{eventKey}
Authorization: Bearer {token}
Content-Type: application/json
Request Body:
{
"channels": {
"email": true,
"sms": true,
"push": false
},
"settings": {}
}
Response:
{
"data": {
"event_key": "user.registered",
"event_name": "User Registered",
"channels": {
"email": true,
"sms": true,
"push": false
}
},
"message": "Preferences updated successfully."
}
Error Responses:
403 Forbidden- User preference override is disabled by administrator422 Unprocessable Entity- Invalid channel type or validation error404 Not Found- Event not found or inactive
Note: The API will return a 403 error if the admin has disabled allow_override in the notification settings.
#Analytics & Tracking
The package includes comprehensive analytics tracking for email notifications, allowing you to measure engagement and optimize your notification strategy.
#Email Open Tracking
When track_opens is enabled in analytics settings, a 1x1 transparent tracking pixel is automatically injected into all email notifications. When a user opens the email, the pixel loads and tracks the open event.
Tracking Endpoint:
GET /notifier/track/open/{token}
This endpoint:
- Returns a 1x1 transparent PNG pixel
- Records the first open time in
opened_at - Increments the
opens_countcounter - Respects analytics enabled/disabled settings
#Link Click Tracking
When track_clicks is enabled, all URLs in email content are rewritten to signed tracking URLs. When users click links, the system tracks the click and redirects to the original URL.
Apple Mail Privacy Protection prefetches tracking pixels, so open rate is inflated. Use click-through rate as the main engagement metric. Unsigned (legacy) tracking links only redirect to the application host, hosts in notifier.tracking.allowed_hosts, or a URL that already appeared in that notification.
Tracking Endpoint:
GET /notifier/track/click/{token}?url={encoded_url}
This endpoint:
- Records the first click time in
clicked_at - Increments the
clicks_countcounter - Safely redirects to the original URL
- Validates URLs to prevent open redirect vulnerabilities
#Analytics Dashboard
Access the comprehensive analytics dashboard in your Filament admin panel:
Location: Navigate to Notifier → Dashboard in your Filament admin panel.
Dashboard Features:
-
Overview Stats Widget
- Total notifications with trend chart
- Success rate percentage
- Pending notifications count
- Failed notifications count
- Active channels count
-
Engagement Stats Widget
- Total opens
- Open rate percentage
- Total clicks
- Click rate percentage
- Click-through rate
-
Time Series Chart
- 30-day line chart showing sent, opened, and clicked notifications
- Full-width visualization
- Auto-refreshes every 30 seconds
-
Engagement Analytics Chart
- Combined bar and line chart
- Shows opens and clicks
- Overlays open rate % and click rate %
- Dual Y-axis for counts and percentages
- Last 7 days view
-
Channel Performance Chart
- Bar chart comparing all active channels
- Shows sent, opened, and clicked per channel
- Helps identify best-performing channels
-
Rate Limiting Status Widget
- Real-time usage for minute, hour, and day limits
- Color-coded warnings
- Percentage usage indicators
- Auto-refreshes every 10 seconds
All widgets respect the analytics and rate limiting enabled/disabled settings.
#Data Retention
Configure data retention in the analytics settings. Use the cleanup command to remove old analytics data:
# Clean up analytics data older than retention period
php artisan notifier:cleanup-analytics
# Dry run to see what would be cleaned
php artisan notifier:cleanup-analytics --dry-run
The cleanup command:
- Respects the
retention_dayssetting - Anonymizes analytics data
- Can be scheduled via Laravel's task scheduler
#Rate Limiting
The package includes built-in rate limiting to prevent notification abuse and ensure system stability.
#Configuration
Configure rate limits in the Filament admin panel under Notifier → Settings → Rate Limiting:
- Max Per Minute / Hour / Day: Global caps (defaults: 60 / 1000 / 10000)
- When a limit is reached:
drop(default) skips the notification;deferqueues it until the window resets - Max Per User Per Hour / Day and Max Per Channel Per Minute: optional extra caps (
0disables them)
#How It Works
Rate limiting is enforced atomically before notification creation:
- Global limits, then optional per-user and per-channel limits, are reserved together
dropskips the notification;deferstill creates it and delays the job- Rate limit violations are logged
- Counters live in Laravel Cache with a TTL that outlasts the window
#Monitoring
View real-time rate limiting status in the Notifier Dashboard:
- Current usage vs limits for each time period
- Color-coded warnings (red >90%, yellow >75%, green otherwise)
- Percentage usage indicators
#Configuration
Channels, events and templates are stored in the database and edited in Filament. config/notifier.php holds package defaults (queue, retries, tracking hosts, API middleware, webhook secrets, and fallback settings). Publish it with php artisan vendor:publish --tag=notifier-config.
#Database Tables
The package creates the following database tables with the notifier_ prefix to avoid conflicts with Laravel's built-in tables:
notifier_channels- Stores notification channel configurationsnotifier_events- Stores notification event definitionsnotifier_templates- Stores notification templatesnotifier_preferences- Stores user notification preferencesnotifier_notifications- Stores sent notificationsnotifier_settings- Stores global notification settings
Note: These tables are separate from Laravel's built-in notifications table, which is used for database notifications. Our package provides a comprehensive notification management system that works alongside Laravel's native notification system.
#Publishing Migrations
To customize migrations (e.g., for UUID support, different indexes, or schema changes):
php artisan vendor:publish --tag=notifier-migrations
After publishing, edit the migration files in database/migrations/ and run:
php artisan migrate
#API Reference
#NotifierManager
#Methods
send($user, string $eventKey, array $data = []): Send a notificationsendNow($user, string $eventKey, array $data = []): Send immediately without queuingsendToChannel($user, string $eventKey, string $channelType, array $data = []): Send to a specific channelschedule($user, string $eventKey, Carbon $scheduledAt, array $data = []): Schedule a notificationregisterChannel(string $type, $handler): Register a custom channel driverregisterEvent(string $key, array $config): Register an event configurationgetRegisteredChannels(): Get all registered channel typesgetRegisteredEvents(): Get all registered event keys
#Available Facades
#Preference Facade
use Usamamuneerchaudhary\Notifier\Facades\Preference;
Preference::getUserPreferences($user, string $eventKey): array
Preference::getChannelsForEvent(NotificationEvent $event, ?NotificationPreference $preference): array
Preference::shouldSendToChannel($user, string $channelType, array $preferences): bool
#Analytics Facade
use Usamamuneerchaudhary\Notifier\Facades\Analytics;
Analytics::isEnabled(): bool
Analytics::isOpenTrackingEnabled(): bool
Analytics::isClickTrackingEnabled(): bool
Analytics::generateTrackingPixel(string $trackingToken): string
Analytics::trackOpen(Notification $notification): void
Analytics::trackClick(Notification $notification): void
#UrlTracking Facade
use Usamamuneerchaudhary\Notifier\Facades\UrlTracking;
UrlTracking::safeRedirect(string $url): RedirectResponse
UrlTracking::rewriteUrlsForTracking(string $content, string $token): string
#NotificationRepo Facade
use Usamamuneerchaudhary\Notifier\Facades\NotificationRepo;
NotificationRepo::findByToken(string $token): ?Notification
#Models
#NotificationChannel
title: Channel display nametype: Channel type (email, sms, slack, etc.)icon: Icon for the channelis_active: Whether the channel is activesettings: Channel-specific settings
#NotificationTemplate
title: Template display namekey: Unique template identifiertype: Template typesubject: Email subject linecontent: Template content with variable placeholdersvariables: Available variables for the template
#Notification
notification_template_id: Associated templateuser_id: Target userchannel: Channel typesubject: Rendered subjectcontent: Rendered contentstatus: Notification status (pending,sending,sent,delivered,bounced,complained,failed)scheduled_at: Scheduled send timesent_at: Actual send timeopened_at: First time notification was opened (analytics)clicked_at: First time a link was clicked (analytics)opens_count: Total number of opens (analytics)clicks_count: Total number of clicks (analytics)
#Testing
#Running Tests
composer test
The package includes comprehensive tests covering:
- Notification sending, scheduling, retries and fallbacks
- User preferences API (authenticated) and unsubscribe
- Analytics tracking (opens, signed clicks)
- Rate limiting (drop and defer)
- Email, Discord, Push (FCM v1) and in-app drivers
- Delivery webhooks
Notifier::fake()- Analytics cleanup command
#Roadmap (not in 2.0)
Polymorphic / on-demand recipients, localised templates, live preview and test send, template versioning and A/B tests, Blade or Markdown syntax, digests and quiet hours, a Laravel Notification bridge, multi-tenancy, per-link click events, and CSV export. See UPGRADE.md for 1.5 → 2.0 notes.
#Test Coverage
Feature Tests:
NotifierManagerTest- Core notification functionalityAnalyticsTrackingTest- Email open and click trackingRateLimitingTest- Rate limit enforcementAnalyticsCleanupCommandTest- Data retention cleanup
Unit Tests:
RateLimitingServiceTest- Rate limiting service logicEmailDriverTest- Email sending and tracking pixel injection
#Sending Test Notifications
You can send test notifications using the provided command:
# Send a test notification
php artisan notifier:test user.registered --user=1
# Send with custom data
php artisan notifier:test user.registered --user=1 --data="name=John Doe" --data="app_name=Test App"
# Send to specific channel
php artisan notifier:test user.registered --user=1 --channel=email
#Available Commands
php artisan notifier:install- Install the package and create sample dataphp artisan notifier:test {event} [options]- Send test notificationsphp artisan notifier:cleanup-analytics [--dry-run]- Clean up old analytics data based on retention settings
#Cleanup Analytics Command
The cleanup command removes or anonymizes analytics data older than the configured retention period:
# Clean up old analytics data
php artisan notifier:cleanup-analytics
# Preview what would be cleaned (dry run)
php artisan notifier:cleanup-analytics --dry-run
Options:
--dry-run: Show what would be cleaned without actually deleting data
What it does:
- Finds notifications with analytics data older than
retention_days - Anonymizes the data (sets opens/clicks to 0, clears timestamps)
- Preserves notification records for historical reference
- Respects the
analytics.enabledsetting
#Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
#License
This package is open-sourced software licensed under the MIT license.
#Architecture & Design
The package follows Laravel best practices with a clean, service-oriented architecture:
- Service Classes: Regular classes that can be dependency injected or accessed via facades
- Facades: Convenient static access to services (registered in
composer.json) - Dependency Injection: Preferred approach for controllers and testable code
- Service Container: All services are registered as singletons for optimal performance
#Screenshots
#Dashboard Overview
#Analytics & Metrics
|
|
#Notification Management
|
|
#Templates & Settings
|
|
#Support
For support, please open an issue on GitHub or contact me at hello@usamamuneer.me.
The author
Coder, Blogger, Tech Speaker & Web Technologies Enthusiast. Passionate about working on open-source Programming languages & Tools while utilizing my Product Development skills.
From the same author
Spatie Model States Visualizer
State-aware Kanban board and status timeline components for Filament v5. Filament Model States provides a plug and play auto-detection for enums, Spatie Model States, or plain database values. Built to sit on top of: spatie/laravel-model-status > powers the timeline (status history log) spatie/laravel-model-states > powers transition validation and column discovery on the Kanban board (optional but recommended)
Author:
Usama Muneer
Adment
A simple custom ad & Google AdSense manager for Filament v5 with placements, responsive (and GIF/video) creatives, weighted A/B rotation, scheduling windows, geo/device targeting, impression & CTR analytics, obfuscated click tracking, AdSense Auto Ads & ad units, ads.txt management, and an optional public JSON API.
Author:
Usama Muneer
Command Palette
A Spotlight/CMD+K style command palette for quick navigation and actions across Filament panels.
Author:
Usama Muneer
FilaRank Pro
SEO toolkit for Filament with live scoring, readability analysis, SERP preview, head tag rendering, redirect management, site-wide health reports and many more.
Author:
Usama Muneer
Featured Plugins
A selection of plugins curated by the Filament team
Soft Theme
A theme that gives panels a warm, approachable look with rounded shapes, gentle colors, and serif headings.
Filament
Compact Theme
A theme that makes data-heavy panels easier to scan by fitting more useful information on each screen.
Filament
Advanced Tables (formerly Filter Sets)
Supercharge your tables with powerful features like user-customizable views, quick filters, multi-column sorting, advanced table searching, convenient view management, and more. Compatible with Resource Panel Tables, Relation Managers, Table Widgets, and Table Builder!
Kenneth Sese

