Install & Compatibility
Where this runs
tested against v0.9.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.920 runs
installs and imports cleanly · install 0.0s · import 0.471s · 38.3MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 4.5s · import 0.514s · 39MB
36MB installed
● package 36MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
APNsClient
✓ from apns2 import APNsClient
✗ from apns2.client import APNsClient
This quickstart demonstrates sending a single push notification using both certificate-based (.pem) and token-based (.p8) authentication methods. It also includes an example of sending a batch of notifications using token-based authentication. Remember to replace placeholder values with your actual APNs credentials and device token, preferably using environment variables for sensitive data.
import os
from apns2.client import APNsClient
from apns2.payload import Payload
from apns2.credentials import TokenCredentials
import collections
# --- Configuration from environment variables ---
# For certificate-based authentication (P8/PEM file)
CERTIFICATE_PATH = os.environ.get('APNS_CERTIFICATE_PATH', 'path/to/your/certificate.pem')
# For token-based authentication (P8 file details)
AUTH_KEY_PATH = os.environ.get('APNS_AUTH_KEY_PATH', 'path/to/your/AuthKey.p8')
AUTH_KEY_ID = os.environ.get('APNS_AUTH_KEY_ID', 'YOUR_KEY_ID') # E.g., 'ABC123DEFG'
TEAM_ID = os.environ.get('APNS_TEAM_ID', 'YOUR_TEAM_ID') # E.g., 'XXXXXXXXXX'
# Common notification parameters
DEVICE_TOKEN = os.environ.get('APNS_DEVICE_TOKEN', 'your_device_token_hex_string')
TOPIC = os.environ.get('APNS_BUNDLE_ID', 'com.example.YourApp') # Your app's bundle ID
# Set to True for development/sandbox environment, False for production
USE_SANDBOX = bool(os.environ.get('APNS_USE_SANDBOX', 'True').lower() == 'true')
def send_notification_certificate_based():
if not os.path.exists(CERTIFICATE_PATH):
print(f"Warning: Certificate file not found at {CERTIFICATE_PATH}. Skipping certificate-based send.")
return
print("\n--- Sending notification with Certificate-Based Authentication ---")
try:
client = APNsClient(CERTIFICATE_PATH, use_sandbox=USE_SANDBOX)
payload = Payload(alert="Hello from Cert!", sound="default", badge=1)
response = client.send_notification(DEVICE_TOKEN, payload, TOPIC)
print(f"Certificate-based response: {response.status_code} {response.reason}")
except Exception as e:
print(f"Error sending certificate-based notification: {e}")
def send_notification_token_based():
if not os.path.exists(AUTH_KEY_PATH) or AUTH_KEY_ID == 'YOUR_KEY_ID' or TEAM_ID == 'YOUR_TEAM_ID':
print("Warning: Token authentication details incomplete or AuthKey.p8 not found. Skipping token-based send.")
return
print("\n--- Sending notification with Token-Based Authentication ---")
try:
token_credentials = TokenCredentials(auth_key_path=AUTH_KEY_PATH, auth_key_id=AUTH_KEY_ID, team_id=TEAM_ID)
client = APNsClient(credentials=token_credentials, use_sandbox=USE_SANDBOX)
payload = Payload(alert="Hello from Token!", sound="default", badge=1)
response = client.send_notification(DEVICE_TOKEN, payload, TOPIC)
print(f"Token-based response: {response.status_code} {response.reason}")
# Example of sending multiple notifications in a batch (Token-based)
Notification = collections.namedtuple('Notification', ['token', 'payload'])
notifications = [
Notification(payload=payload, token=DEVICE_TOKEN)
]
print("Sending batch notification...")
batch_responses = client.send_notification_batch(notifications=notifications, topic=TOPIC)
for res in batch_responses:
print(f"Batch response for {res.token}: {res.status_code} {res.reason}")
except Exception as e:
print(f"Error sending token-based notification: {e}")
if __name__ == '__main__':
send_notification_certificate_based()
send_notification_token_based()
print("\nQuickstart finished. Check your device for notifications if configuration was correct.")
Debug
Known issues
breakingApple deprecated the legacy binary APNs protocol. This library exclusively uses the HTTP/2 protocol. If migrating from an older APNs library using the binary protocol, significant code changes are required.fixEnsure your APNs provider certificate or token is configured for HTTP/2. Use the `APNsClient` and `Payload` classes as shown in the quickstart. Review Apple's official APNs documentation for HTTP/2 provider API.
affects: <0.7.0 (or any library using binary protocol)
gotchaAPNs certificates (.pem, .p12) have a limited validity period (typically 12 months) and will expire. An expired certificate will prevent notifications from being delivered.fixMonitor your Apple Developer account for certificate expiration notifications. Renew your certificate *before* it expires using the same Apple ID, then update the certificate file on your server. If it expires, you might need to re-enroll devices if a new certificate is generated instead of renewed. For token-based authentication, ensure your .p8 key is valid and not revoked.
affects: All versions
gotchaUsing the wrong APNs environment (sandbox vs. production) for a device token will result in notification delivery failures without clear error messages from Apple, often appearing as 'success' from the library's perspective but not reaching the device.fixEnsure `use_sandbox=True` for development builds and `use_sandbox=False` for production builds. Device tokens obtained from development builds can only receive notifications from the sandbox APNs environment, and vice-versa for production tokens.
affects: All versions
gotchaThe maximum payload size for a push notification is 4KB (4096 bytes) for regular notifications and 5KB (5120 bytes) for VoIP notifications. Exceeding this limit will result in a 'Payload Too Large' error (HTTP 413).fixKeep your notification payloads concise. If you need to send more data, consider using a background fetch mechanism in your app to pull additional content after a minimal notification is received.
affects: All versions
gotchaWhen using token-based authentication, APNs expects providers to update their authentication token no more than once every 20 minutes. Updating too frequently can lead to throttling or a 'TooManyProviderTokenUpdates' error.fixCache the `APNsClient` instance with `TokenCredentials` and reuse it for multiple notifications. The library's `TokenCredentials` handles token refreshing automatically when needed, typically before expiration (hourly). Avoid creating a new `APNsClient` or `TokenCredentials` instance for every single push.
affects: All versions (token-based authentication)
Upgrade
Version history
0.9.0latest on PyPI · released May 16, 2025
Audit
Dependencies
No dependency data recorded yet.