usamamuneerchaudhary/filament-notifier
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.
composer require usamamuneerchaudhary/filament-notifier
php artisan notifier:install
This command will:
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:
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
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,
]);
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.
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
}
}
}
use Carbon\Carbon;
// Schedule a notification for later
$notifier->schedule($user, 'reminder.email', Carbon::now()->addDays(7), [
'task_name' => 'Complete project review',
]);
Register events in your config/notifier.php:
'events' => [
'user.registered' => [
'channels' => ['email', 'slack'],
'template' => 'welcome-email',
],
'order.completed' => [
'channels' => ['email', 'sms'],
'template' => 'order-confirmation',
],
],
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',
],
]);
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);
}
}
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 /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 /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 /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
}
}
}
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 inactiveNote: The API will return a 403 error if the admin has disabled allow_override in the notification settings.
The package includes comprehensive analytics tracking for email notifications, allowing you to measure engagement and optimize your notification strategy.
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:
opened_atopens_count counterWhen track_clicks is enabled, all URLs in email content are automatically rewritten to use tracking URLs. When users click links, the system tracks the click and redirects to the original URL.
Tracking Endpoint:
GET /notifier/track/click/{token}?url={encoded_url}
This endpoint:
clicked_atclicks_count counterAccess the comprehensive analytics dashboard in your Filament admin panel:
Location: Navigate to Notifier → Dashboard in your Filament admin panel.
Dashboard Features:
Overview Stats Widget
Engagement Stats Widget
Time Series Chart
Engagement Analytics Chart
Channel Performance Chart
Rate Limiting Status Widget
All widgets respect the analytics and rate limiting enabled/disabled settings.
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:
retention_days settingThe package includes built-in rate limiting to prevent notification abuse and ensure system stability.
Configure rate limits in the Filament admin panel under Notifier → Settings → Rate Limiting:
Rate limiting is enforced before notification creation:
View real-time rate limiting status in the Notifier Dashboard:
// config/notifier.php
'channels' => [
'email' => [
'enabled' => true,
'driver' => 'smtp',
'from_address' => 'noreply@example.com',
'from_name' => 'Your App',
],
'slack' => [
'enabled' => true,
'webhook_url' => env('SLACK_WEBHOOK_URL'),
'channel' => '#notifications',
],
'sms' => [
'enabled' => true,
'driver' => 'twilio',
'account_sid' => env('TWILIO_ACCOUNT_SID'),
'auth_token' => env('TWILIO_AUTH_TOKEN'),
'phone_number' => env('TWILIO_PHONE_NUMBER'),
],
],
'events' => [
'user.registered' => [
'channels' => ['email', 'slack'],
'template' => 'welcome-email',
'delay' => 0, // Send immediately
],
'order.shipped' => [
'channels' => ['email', 'sms'],
'template' => 'order-shipped',
'delay' => 300, // 5 minutes delay
],
],
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 settingsNote: 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.
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
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 keysuse 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
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
use Usamamuneerchaudhary\Notifier\Facades\UrlTracking;
UrlTracking::safeRedirect(string $url): RedirectResponse
UrlTracking::rewriteUrlsForTracking(string $content, string $token): string
use Usamamuneerchaudhary\Notifier\Facades\NotificationRepo;
NotificationRepo::findByToken(string $token): ?Notification
title: Channel display nametype: Channel type (email, sms, slack, etc.)icon: Icon for the channelis_active: Whether the channel is activesettings: Channel-specific settingstitle: Template display namekey: Unique template identifiertype: Template typesubject: Email subject linecontent: Template content with variable placeholdersvariables: Available variables for the templatenotification_template_id: Associated templateuser_id: Target userchannel: Channel typesubject: Rendered subjectcontent: Rendered contentstatus: Notification status (pending, sent, 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)composer test
The package includes comprehensive tests covering:
Feature Tests:
NotifierManagerTest - Core notification functionalityAnalyticsTrackingTest - Email open and click trackingRateLimitingTest - Rate limit enforcementAnalyticsCleanupCommandTest - Data retention cleanupUnit Tests:
RateLimitingServiceTest - Rate limiting service logicEmailDriverTest - Email sending and tracking pixel injectionYou 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
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 settingsThe 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 dataWhat it does:
retention_daysanalytics.enabled settingThis package is open-sourced software licensed under the MIT license.
The package follows Laravel best practices with a clean, service-oriented architecture:
composer.json)For support, please open an issue on GitHub or contact me at hello@usamamuneer.me.
How can I help you explore Laravel packages today?