Skip to content
Developers · 8 min read

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.

Updated By the Pusharoo team
In short
  • 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-push

The 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 WebPush instance 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 TTL per campaign: short for flash sales, long for articles (headers).
  • Use the urgency and topic options 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.

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.