Push
Subscribe the current service worker to web push messages, inspect the existing subscription and unsubscribe - the client half of the Web Push protocol, fully typed.
@inject Bit.Butil.Push pushMDN reference
web-push npm package or
WebPush NuGet package. This page demonstrates the client side only.
Returns true when the runtime exposes ServiceWorkerRegistration.pushManager. Chromium and Firefox support push broadly; Safari supports it from 16.1 on macOS, and on iOS only for web apps added to the Home Screen.
var supported = await push.IsSupported();Push subscriptions belong to a service worker registration. This button registers the demo /sw.js, whose push handler shows a notification with the received payload.
Bit.Butil.ServiceWorker serviceWorker
<button @onclick="RegisterWorker">Register /sw.js</button>
{
private async Task RegisterWorker() => await serviceWorker.Register("/sw.js");
}// Nothing in a page can receive a push: the browser wakes the service worker, which is why a
// subscription belongs to a registration rather than to a tab.
self.addEventListener('push', event => {
const text = event.data ? event.data.text() : '(no payload)';
// Chromium enforces the userVisibleOnly promise the subscription made: a push handler that
// shows no notification eventually loses the subscription.
event.waitUntil(self.registration.showNotification('Bit.Butil push demo', { body: text }));
});
// The endpoint can be rotated by the push service, which arrives here rather than in the page. The
// new subscription has to be sent to your server, or it goes on pushing to the old endpoint.
self.addEventListener('pushsubscriptionchange', event => {
event.waitUntil(self.registration.pushManager
.subscribe(event.oldSubscription.options)
.then(subscription => fetch('/api/push/subscriptions', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(subscription)
})));
});Creates a push subscription for the active service worker. The applicationServerKey is your VAPID public key (base64-url encoded); generate a key pair once on your machine and keep the private key on your server. userVisibleOnly defaults to true because Chromium requires every push to result in a user-visible notification.
# Once per application, not once per user. The public half goes to the browser as the
# applicationServerKey; the private half stays on your server and signs every push you send.
npx web-push generate-vapid-keys Bit.Butil.Push push
{
// The public half of the VAPID key pair, base64-url encoded.
private const string ApplicationServerKey = "BPk3...your public key...";
private async Task Subscribe()
{
var sub = await push.Subscribe(applicationServerKey: ApplicationServerKey);
if (sub.IsActive is false) return;
// sub.Endpoint, sub.P256dh and sub.Auth are the three values your server needs to push to
// this browser; sub.ExpirationTime is usually null. Nothing on this side can send a push.
await http.PostAsJsonAsync("/api/push/subscriptions", sub);
}
}Returns the current subscription for the active service worker, or a payload with IsActive set to false when none exists. Send the Endpoint, P256dh and Auth values to your application server - that is everything it needs to push to this browser.
var sub = await push.GetSubscription();
if (sub.IsActive)
{
// persist sub.Endpoint, sub.P256dh and sub.Auth on your server
}Deactivates the active subscription and returns true when one was removed. Remember to also delete the subscription record from your application server, or it will keep pushing into the void.
var removed = await push.Unsubscribe();API reference
ValueTask<bool> IsSupported()ValueTask<PushSubscriptionInfo> GetSubscription()ValueTask<PushSubscriptionInfo> Subscribe(string applicationServerKey, bool userVisibleOnly = true)ValueTask<bool> Unsubscribe()bool IsActive { get; set; }string Endpoint { get; set; }long? ExpirationTime { get; set; }string P256dh { get; set; }string Auth { get; set; }