Web push notifications in PHP
minishlink/web-push is the standard PHP library for Web Push — and the one Pusharoo’s own sender is built on. Here’s a complete, production-minded setup.
- composer require minishlink/web-push installs the library.
- VAPID::createVapidKeys() generates your key pair once.
- queueNotification() + flush() sends in batches and returns a report per subscription.
- Delete subscriptions whose report says isSubscriptionExpired().
Install
composer require minishlink/web-pushThe library needs a modern PHP 8 version with the openssl, curl and mbstring extensions (and gmp is recommended for speed). Check its README for the exact versions supported by the release you install.
Create VAPID keys once
<?php
require 'vendor/autoload.php';
use Minishlink\WebPush\VAPID;
print_r(VAPID::createVapidKeys()); // ['publicKey' => '...', 'privateKey' => '...']Store both in environment variables; ship only the public key to the browser (VAPID explained).
Store subscriptions
<?php
// subscribe.php — receives JSON from pushManager.subscribe()
$sub = json_decode(file_get_contents('php://input'), true);
if (!isset($sub['endpoint'], $sub['keys']['p256dh'], $sub['keys']['auth'])) { http_response_code(400); exit; }
$stmt = $pdo->prepare('INSERT INTO push_subs (endpoint, p256dh, auth) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE p256dh = VALUES(p256dh), auth = VALUES(auth)');
$stmt->execute([$sub['endpoint'], $sub['keys']['p256dh'], $sub['keys']['auth']]);
http_response_code(201);Queue, flush and clean up
<?php
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;
$webPush = new WebPush(['VAPID' => [
'subject' => 'mailto:[email protected]',
'publicKey' => getenv('VAPID_PUBLIC_KEY'),
'privateKey' => getenv('VAPID_PRIVATE_KEY'),
]], ['TTL' => 3600]);
$payload = json_encode(['title' => 'Back in stock', 'body' => 'Linen Shirt, size M', 'url' => '/p/linen-shirt']);
foreach ($pdo->query('SELECT endpoint, p256dh, auth FROM push_subs') as $row) {
$webPush->queueNotification(Subscription::create([
'endpoint' => $row['endpoint'],
'keys' => ['p256dh' => $row['p256dh'], 'auth' => $row['auth']],
]), $payload);
}
foreach ($webPush->flush() as $report) {
if ($report->isSubscriptionExpired()) {
$pdo->prepare('DELETE FROM push_subs WHERE endpoint = ?')->execute([$report->getEndpoint()]);
}
}Running it at scale
- Send from a CLI worker or cron job, not inside a web request.
- Flush in batches (for example a few hundred at a time) to limit memory.
- Reuse one
WebPushinstance per batch so connections are reused. - Log the report reasons for non-expired failures and retry 429/5xx later.
A minimal table
CREATE TABLE push_subs (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
endpoint VARCHAR(700) NOT NULL,
p256dh VARCHAR(120) NOT NULL,
auth VARCHAR(40) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uniq_endpoint (endpoint(500))
);Endpoints can be long, so index a prefix. Add columns for language, timezone or a user ID if you want to segment (segmentation ideas).
Payload and options
- Keep the JSON payload small: title, body, URL, icon and image URL — the encrypted message must fit in about 4 KB.
- Set
TTLper campaign: short for flash sales, long for articles (headers). - Use the
urgencyandtopicoptions where your library version supports them. - Never log full subscription keys alongside personal data.
The hosted shortcut
Pusharoo’s sender uses this same library, plus a queue, segments, schedules, automations, signed webhooks and automatic cleanup — free with no limits. If you just need notifications on a PHP site (WordPress, Laravel or plain PHP), install sw.js and the snippet instead (setup guide), or see Laravel push notifications.
Questions
Is minishlink/web-push free to use?
Yes, it’s open source under the MIT license.
Does PHP web push need Firebase?
No. The library sends standard Web Push with VAPID to every browser’s push service.
Why is sending slow?
Each notification is encrypted individually. Install the gmp extension, batch sends and run them in a background worker.
Keep reading
Laravel browser push notifications (no Firebase)
laravel-notification-channels/webpush setup, VAPID keys, storing subscriptions and a WebPush notification class.
Web push notifications with Node.js
Install web-push, generate keys, save subscriptions with Express, send with TTL and clean up dead endpoints.
VAPID keys for web push, explained
What the key pair does, how the signed JWT works, how to generate keys and why rotation breaks lists.
The Web Push API in JavaScript: a working example
Register a worker, ask on click, subscribe with VAPID, store the subscription and send — complete code.
More in Developers: Service worker push events, done right · The Web Push protocol, explained · Web push notifications in React and Next.js · Declarative Web Push, explained · Firebase web push vs. standard web push · All guides
Free for life. No limits.
Unlimited subscribers, campaigns and automations. No badges. About five minutes to install.