iguazoft/yii2-push-notifications

Web Push Notifications for Yii2 — VAPID-based push with Service Worker support

Maintainers

Package info

github.com/dannyrios81/yii2-push-notifications

Type:yii2-extension

pkg:composer/iguazoft/yii2-push-notifications

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-10 16:35 UTC

This package is auto-updated.

Last update: 2026-03-10 16:48:52 UTC


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

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://localhost is 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 vapidPrivateKey secret. 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',
    ],
],

vapidSubject must be either a mailto: 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:

  1. User clicks the button
  2. The browser shows its native "Allow notifications?" prompt
  3. If allowed, the browser creates a unique subscription object (endpoint URL + encryption keys)
  4. The widget POSTs this to /push/subscribe and saves it to your database
  5. The button text changes to the subscribedLabel value
  6. 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/sw returns a 200 response with Content-Type: application/javascript.

Notifications not arriving

  • Verify VAPID keys are set correctly in config/web.php.
  • Check that the PHP extension gmp or bcmath is enabled: php -m | grep -E 'gmp|bcmath'.
  • Run php yii push/stats to confirm subscriptions exist in the database.
  • Check browser notification permissions (the browser may have silently blocked them).

"InvalidConfigException: PushManager requires vapidPublicKey..."

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_subscriptions already exists. Skip the migration or check for conflicts with existing tables.

License

MIT © iguazoft