iguazoft / yii2-push-notifications
Web Push Notifications for Yii2 — VAPID-based push with Service Worker support
Package info
github.com/dannyrios81/yii2-push-notifications
Type:yii2-extension
pkg:composer/iguazoft/yii2-push-notifications
Requires
- php: >=8.0
- minishlink/web-push: ^8.0
- yiisoft/yii2: ~2.0
Requires (Dev)
- phpunit/phpunit: ^10.0
README
Web Push Notifications for Yii2 — send real-time alerts to your users even when they have the browser closed.
Built on the Web Push API with VAPID authentication and Service Workers. No external paid service required — pushes go directly from your server to the browser.
Table of Contents
- What it does
- How it works
- Requirements
- Installation
- Configuration
- Usage
- Widget reference
- PushManager reference
- HTTP API endpoints
- Browser compatibility
- Troubleshooting
What it does
This extension lets you send push notifications to your Yii2 application users directly from your PHP server, with no third-party service needed. Notifications appear as native OS alerts with a system sound, even when:
- The browser tab is minimized or in the background
- The browser is open but on a different tab
- The browser is completely closed (the OS must be running)
Typical use cases:
| Use case | Example |
|---|---|
| New private message | "Juan sent you a message" |
| Order status update | "Your order #1042 has been shipped" |
| System alert | "Server CPU usage above 90%" |
| Scheduled announcement | "Maintenance window starting in 10 minutes" |
| New comment or mention | "Maria replied to your post" |
How it works
YOUR SERVER BROWSER VENDOR USER'S BROWSER
│ │ │
│ 1. User clicks "Enable" │ │
│ ◄─────────────────────────────────────────────────────────┤
│ │ │
│ 2. Save subscription │ │
│ (endpoint + keys) │ │
│ ◄─────────────────────────────────────────────────────────┤
│ │ │
│ 3. Yii::$app->push->send() │ │
├──────────────────────────────►│ │
│ │ 4. Forward to browser │
│ ├───────────────────────────►│
│ │ │
│ │ 5. Service Worker │
│ │ wakes up → │
│ │ showNotification() │
│ │ 🔔 + system sound │
The extension handles all the complexity:
- VAPID authentication to prove your server's identity
- Service Worker that intercepts push events in the background
- Subscription management stored in your database
- Auto-cleanup of expired subscriptions
Requirements
| Requirement | Version |
|---|---|
| PHP | >= 8.0 |
| Yii2 | ~2.0 |
| PHP extension | gmp or bcmath |
| Protocol | HTTPS required (or localhost for development) |
Why HTTPS? Browsers only allow Service Workers and the Push API on secure origins. For local development,
http://localhostis treated as secure.
Installation
Step 1 — Install via Composer
composer require iguazoft/yii2-push-notifications
Step 2 — Generate VAPID keys
VAPID keys are a cryptographic pair that proves to browser vendors that push messages actually come from your server. You generate them once and store them in your config.
php yii push/generate-keys
Output:
✅ VAPID keys generated successfully.
Copy these values into config/web.php:
'vapidPublicKey' => 'BNa7...long base64 string...Xk=',
'vapidPrivateKey' => 'abc...long base64 string...Z4=',
Important: Keep
vapidPrivateKeysecret. Never commit it to version control — use environment variables or a local config file excluded from git.
Step 3 — Add the component to config/web.php
'components' => [ 'push' => [ 'class' => \iguazoft\push\components\PushManager::class, 'vapidPublicKey' => 'YOUR_PUBLIC_KEY_HERE', 'vapidPrivateKey' => 'YOUR_PRIVATE_KEY_HERE', 'vapidSubject' => 'mailto:admin@yoursite.com', ], ],
vapidSubjectmust be either amailto:address or a URL. Browser vendors use it to contact you if there is an issue with your push traffic.
Step 4 — Run the migration
Creates the push_subscriptions table in your database.
php yii migrate --migrationPath=@vendor/iguazoft/yii2-push-notifications/src/migrations
That's it. The extension auto-registers its URL routes and console commands.
Usage
1. Add the subscribe button
Place the PushSubscribe widget anywhere in your layout or view. It renders a button that handles everything: registering the Service Worker, requesting browser permission, and saving the subscription to your server.
Basic usage:
echo \iguazoft\push\widgets\PushSubscribe::widget();
With custom labels:
echo \iguazoft\push\widgets\PushSubscribe::widget([ 'buttonLabel' => '🔔 Enable notifications', 'subscribedLabel' => '🔕 Disable notifications', 'loadingLabel' => 'Please wait...', ]);
With custom CSS classes (e.g. Bootstrap or DaisyUI):
echo \iguazoft\push\widgets\PushSubscribe::widget([ 'buttonLabel' => 'Enable notifications', 'buttonOptions' => ['class' => 'btn btn-outline-primary btn-sm'], ]);
What the button does step by step:
- User clicks the button
- The browser shows its native "Allow notifications?" prompt
- If allowed, the browser creates a unique subscription object (endpoint URL + encryption keys)
- The widget POSTs this to
/push/subscribeand saves it to your database - The button text changes to the
subscribedLabelvalue - If the user clicks again, the subscription is cancelled and removed
The widget automatically remembers the subscription state on page reload.
2. Send a notification from PHP
Use Yii::$app->push anywhere in your application: controllers, models, queue jobs, console commands, event handlers.
Send to a specific user:
Yii::$app->push->send('New message', 'You have 1 unread message', $userId);
Send to all subscribers:
Yii::$app->push->sendToAll('Announcement', 'Scheduled maintenance at 22:00');
With extra options:
Yii::$app->push->send( 'Order shipped', 'Your order #1042 is on its way', $userId, [ 'icon' => '/img/logo-192.png', // notification icon (PNG, min 192×192px) 'badge' => '/img/badge-72.png', // small monochrome icon (Android, 72×72px) 'url' => '/orders/1042', // page to open when user clicks 'tag' => 'order-1042', // replaces previous notification with same tag 'image' => '/img/product.png', // large image inside the notification ] );
Handling the result:
$result = Yii::$app->push->sendToAll('Flash sale', '50% off everything — today only!'); echo "Sent: {$result['sent']}\n"; echo "Failed: {$result['failed']}\n"; if (!empty($result['errors'])) { foreach ($result['errors'] as $error) { Yii::error("Push error: $error", 'push'); } }
The return value is always an array with three keys:
| Key | Type | Description |
|---|---|---|
sent |
int |
Number of notifications successfully delivered |
failed |
int |
Number of failed deliveries |
errors |
string[] |
Error messages for failed deliveries |
Tip: Expired or unregistered subscriptions are automatically deleted from the database when a delivery fails with a 410 Gone response.
Real-world example — notify on new order in a controller:
public function actionCreate() { $order = new Order(); if ($order->load(Yii::$app->request->post()) && $order->save()) { // Notify the customer Yii::$app->push->send( 'Order received', "Order #{$order->id} has been placed successfully.", $order->user_id, ['url' => "/orders/{$order->id}"] ); // Notify all admins foreach (User::find()->where(['role' => 'admin'])->all() as $admin) { Yii::$app->push->send( 'New order', "Order #{$order->id} from {$order->user->name}", $admin->id, ['url' => "/admin/orders/{$order->id}"] ); } return $this->redirect(['view', 'id' => $order->id]); } return $this->render('create', ['model' => $order]); }
3. Console commands
The extension registers a push command group automatically in console applications.
Show subscription statistics:
php yii push/stats
📊 Active push subscriptions
─────────────────────────────
Total: 1,204
Users: 891
Anonymous: 313
Send to all subscribers:
php yii push/send-all "Title" "Message body" # With a click URL php yii push/send-all "Maintenance" "System restart in 5 minutes" "/status"
Send to a specific user by ID:
php yii push/send 42 "Title" "Message body" php yii push/send 42 "Account alert" "Unusual login detected" "/security"
Generate new VAPID keys:
php yii push/generate-keys
Automate with cron:
# Send a daily digest every day at 8:00 AM 0 8 * * * /usr/bin/php /var/www/myapp/yii push/send-all "Daily digest" "Your summary is ready" "/digest"
Widget reference
Full list of properties for \iguazoft\push\widgets\PushSubscribe:
| Property | Type | Default | Description |
|---|---|---|---|
buttonLabel |
string |
'Activar notificaciones' |
Button text when not subscribed |
subscribedLabel |
string |
'Desactivar notificaciones' |
Button text when subscribed |
loadingLabel |
string |
'Procesando...' |
Button text during processing |
buttonOptions |
array |
[] |
HTML attributes for the <button> element |
containerOptions |
array |
[] |
HTML attributes for the outer <div> |
vapidPublicKey |
string |
(auto) | VAPID public key — read automatically from Yii::$app->push if not set |
swUrl |
string |
'/push/push/sw' |
Service Worker URL (use default unless you remap routes) |
subscribeUrl |
string |
'/push/push/subscribe' |
Endpoint to save a subscription |
unsubscribeUrl |
string |
'/push/push/unsubscribe' |
Endpoint to remove a subscription |
vapidKeyUrl |
string |
'/push/push/vapid-key' |
Endpoint to fetch VAPID public key dynamically |
Styling the button with data attributes:
The button gets the CSS class push-subscribe-btn automatically. You can target it in your stylesheet:
.push-subscribe-btn { /* your styles */ } .push-subscribe-btn[data-push-active="1"] { /* styles when subscribed */ }
PushManager reference
\iguazoft\push\components\PushManager is the Yii2 application component registered as Yii::$app->push.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
vapidPublicKey |
string |
'' |
VAPID public key (Base64 URL-safe) |
vapidPrivateKey |
string |
'' |
VAPID private key (Base64 URL-safe) |
vapidSubject |
string |
'mailto:admin@example.com' |
Contact address for VAPID |
ttl |
int |
0 |
Message time-to-live in seconds (0 = server maximum) |
Methods
send(string $title, string $body, ?int $userId = null, array $options = []): array
Sends a notification to all subscriptions belonging to a user. If $userId is null, sends to all subscribers (same as sendToAll).
$result = Yii::$app->push->send('Title', 'Body', $userId, $options);
sendToAll(string $title, string $body, array $options = []): array
Sends a notification to every active subscriber in the database.
$result = Yii::$app->push->sendToAll('Title', 'Body', $options);
generateVapidKeys(): array
Generates a new VAPID key pair. Run once during setup.
$keys = Yii::$app->push->generateVapidKeys(); // ['publicKey' => '...', 'privateKey' => '...']
Available $options keys
| Key | Type | Description |
|---|---|---|
url |
string |
Page to open when the user clicks the notification |
icon |
string |
URL to notification icon (PNG, recommended 192×192px) |
badge |
string |
URL to small monochrome icon shown in Android status bar (72×72px) |
image |
string |
URL to a large image displayed inside the notification |
tag |
string |
Notification identifier — a new notification with the same tag replaces the previous one |
HTTP API endpoints
These routes are registered automatically when the extension bootstraps.
| Method | URL | Description |
|---|---|---|
GET |
/push/sw |
Serves the Service Worker JavaScript file |
POST |
/push/subscribe |
Saves a new push subscription |
POST |
/push/unsubscribe |
Removes a push subscription |
GET |
/push/vapid-key |
Returns the VAPID public key as JSON |
POST /push/subscribe — request body:
{
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"keys": {
"p256dh": "BNa7...",
"auth": "abc..."
}
}
POST /push/subscribe — response:
{ "success": true, "id": 57 }
POST /push/unsubscribe — request body:
{ "endpoint": "https://fcm.googleapis.com/fcm/send/..." }
Browser compatibility
| Browser | Support | Notes |
|---|---|---|
| Chrome 50+ | ✅ | Full support |
| Edge 17+ | ✅ | Full support |
| Firefox 44+ | ✅ | Full support |
| Samsung Internet 4+ | ✅ | Full support |
| Safari 16.4+ | ✅ | Requires iOS 16.4 or macOS Ventura+ |
| Safari < 16.4 | ❌ | Not supported |
| IE / Old Edge | ❌ | Not supported |
The widget automatically hides itself on unsupported browsers.
Troubleshooting
"Service Worker registration failed"
- Your app must be served over HTTPS. On local development, use
http://localhost(any other hostname without HTTPS will fail). - Check that
/push/push/swreturns a 200 response withContent-Type: application/javascript.
Notifications not arriving
- Verify VAPID keys are set correctly in
config/web.php. - Check that the PHP extension
gmporbcmathis enabled:php -m | grep -E 'gmp|bcmath'. - Run
php yii push/statsto confirm subscriptions exist in the database. - Check browser notification permissions (the browser may have silently blocked them).
"InvalidConfigException: PushManager requires vapidPublicKey..."
- You haven't added the
pushcomponent toconfig/web.php. Follow Step 3 of Installation.
Notifications arrive but no sound plays
- Sound is controlled by the OS and browser notification settings, not by the application. Check your system's notification settings for the browser.
- On Windows, verify that browser notifications are not set to "Banner only" (silent mode) in System → Notifications.
The subscribe button doesn't appear
- The user's browser doesn't support the Push API (see Browser compatibility).
- The widget hides itself automatically in this case — this is expected behavior.
Migration fails with "Table already exists"
- The table
push_subscriptionsalready exists. Skip the migration or check for conflicts with existing tables.
License
MIT © iguazoft