375 stars · MPL-2.0 · 2.5.0 on PyPI (2026-08-29)
A way to reach a returning visitor who never gave you an email address.
▶Repo detailsthe review · specs · pros & cons · install
What it is
The Python implementation of Web Push: it encrypts a payload with the VAPID scheme and hands it to the browser's push service, which delivers a notification to the visitor's desktop or Android device. This is the server half; the browser half is a service worker and a permission prompt you write yourself.
Why it matters
Every audience tool in this ledger assumes an email address — Listmonk, the lead magnet, Mautic below. But most people who read one tutorial will not hand one over, and a push subscription costs them a single click and no personal data at all. For a channel publishing bilingual tutorials on a schedule, "the next video is up" is precisely the notification people accept and do not resent. It is also the only re-engagement channel that needs no sending domain, no SPF, no DKIM and no DMARC — none of the machinery checkdmarc (Ed.8 #1) exists to police, and none of the deliverability risk. At 374 stars this is genuinely under the radar, and it is the standard Python implementation.
- Pure Python, MPL-2.0, drops straight into FastAPI — no third-party service, no per-notification cost, no visitor data leaving your box.
- Works on desktop Chrome, Firefox and Edge, and on Android, which covers most of a technical audience.
- No email address means no consent-and-deliverability chain to maintain, which for a solo founder is a genuine saving.
- 374 stars and effectively one maintainer, who says so plainly in the README. Read the source, vendor it, and do not build a business-critical channel on it without a fallback.
- iOS Safari only supports push for sites installed to the home screen, which removes a large slice of your reachable audience before you start.
- A permission prompt fired on page load is a bounce; an over-used channel is an unsubscribe you cannot win back. This one is easy to do badly.
Subscriptions live in a Postgres table beside your users; the service worker ships with the Astro content site rather than the React SPA; sending fans out through a Procrastinate (Ed.5 #10) job so a slow push service never blocks a request.