Install & Compatibility
Where this runs
tested against v2.4.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.782s · 48.3MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 6.3s · import 0.712s · 50MB
48MB installed
● package 48MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
webpush
✓ from pywebpush import webpush
Convenience function for a single push notification send.
WebPusher
✓ from pywebpush import WebPusher
Class for more granular control, especially for resending to the same recipient or encoding data separately.
WebPushException
✓ from pywebpush import WebPushException
Exception class raised on push failures.
This quickstart demonstrates sending a WebPush notification using the `webpush` convenience function. It requires a `subscription_info` object (obtained from the client-side browser), a VAPID private key, and VAPID claims. The VAPID private key and sender info are typically loaded from environment variables for security. Data is sent as a JSON string. Error handling for `WebPushException` is included.
import os
import json
from pywebpush import webpush, WebPushException
# --- Configuration --- #
# Get VAPID private key from environment variable for security
VAPID_PRIVATE_KEY = os.environ.get('WEBPUSH_VAPID_PRIVATE_KEY', 'your-vapid-private-key-here')
# Your email or a mailto: URL for VAPID identification
VAPID_SENDER_INFO = os.environ.get('WEBPUSH_SENDER_INFO', 'mailto:admin@example.com')
# Example PushSubscription object (obtained from the client-side)
# In a real application, this would be retrieved from a database.
subscription_info = {
"endpoint": "https://fcm.googleapis.com/fcm/send/SOME_ENDPOINT_ID",
"keys": {
"auth": "SOME_AUTH_KEY",
"p256dh": "SOME_P256DH_KEY"
}
}
# The payload data to send
message_data = {
"title": "Hello from pywebpush!",
"body": "Your notification arrived.",
"icon": "/images/notification-icon.png"
}
try:
# Define VAPID claims. The 'aud' (audience) must be the origin of the push service endpoint.
# pywebpush attempts to guess 'aud' but it's best to be explicit.
# 'exp' (expiration) is set to 12 hours by default if not provided.
vapid_claims = {
"sub": VAPID_SENDER_INFO,
"aud": subscription_info['endpoint'].split('/fcm/send/')[0] # Extract origin for FCM
}
print("Attempting to send push notification...")
response = webpush(
subscription_info=subscription_info,
data=json.dumps(message_data), # Data should be a JSON string for common use cases
vapid_private_key=VAPID_PRIVATE_KEY,
vapid_claims=vapid_claims
)
print(f"Push notification sent successfully! Status: {response.status_code}")
print(f"Response: {response.text}")
except WebPushException as e:
print(f"Failed to send push notification: {e}")
print(f"Response body: {e.response_body}")
# Handle specific errors, e.g., expired subscription, invalid VAPID keys
except Exception as e:
print(f"An unexpected error occurred: {e}")
# Example of using WebPusher class for more control (e.g., encoding data separately)
# try:
# pusher = WebPusher(subscription_info)
# encoded_data = pusher.encode(json.dumps(message_data))
# # You can now send encoded_data with custom HTTP client if needed
# # Or use pusher.send() if you want pywebpush to handle HTTP request
# # response = pusher.send(json.dumps(message_data), headers=headers_dict) # headers_dict would include VAPID auth
# print("Data encoded successfully via WebPusher.")
# except WebPushException as e:
# print(f"Error encoding data: {e}")
Errors
Common errors & fixes
pywebpush.webpush_errors.RequestError: Push service returned error 401: Unauthorized
The VAPID keys (public or private) are incorrect, mismatched, or improperly formatted, leading to an authentication failure with the push service.
fixVerify that your `vapid_public_key` and `vapid_private_key` are correctly generated, stored, and passed as base64 URL-safe strings, and ensure `vapid_claims` contains a valid `sub` (e.g., `mailto:your@email.com`).
pywebpush.webpush_errors.WebPushException: Payload too large
The size of the encrypted message payload exceeds the maximum limit (typically 4096 bytes) allowed by the push service provider.
fixReduce the content of the `message` sent to the push service, as larger payloads cannot be delivered via Web Push.
pywebpush.webpush_errors.RequestError: Push service returned error 400: Bad Request
The `vapid_claims` dictionary provided to `send_web_push` is missing required fields (like `sub`) or contains malformed values, causing the push service to reject the request.
fixEnsure the `vapid_claims` dictionary includes a valid `sub` field (e.g., `{"sub": "mailto:your@email.com"}`) and that all values are correctly formatted. ModuleNotFoundError: No module named 'webpush'
The user is attempting to import the library using `webpush`, but the correct package name for the installed library is `pywebpush`.
fixChange the import statement from `import webpush` to `import pywebpush` or from `from webpush import send_web_push` to `from pywebpush import send_web_push`.
Upgrade
Version history
2.4.0latest on PyPI · released Aug 6, 2026
Audit
Dependencies
pythonrequiredRequires Python 3.10 or newer.