Async Firebase Client - a Python asyncio client to interact with Firebase Cloud Messaging in an easy way.
Project description
Lightweight asynchronous Python client for Firebase Cloud Messaging (FCM)
- Free software: MIT license
- Requires: Python 3.10+
Features
- Extremely lightweight and does not rely on
firebase-adminwhich is hefty - Send push notifications to Android, iOS, and Web devices
- Multicast push notifications (up to 500 tokens per call)
- Send to topics and topic conditions
- TTL, priority, and collapse-key support
- Dry-run mode for testing
- Topic management (subscribe/unsubscribe devices)
- Async context manager for proper resource cleanup
Installation
pip install async-firebase
Quick Start
import asyncio
from async_firebase import AsyncFirebaseClient, Message, AndroidConfig
async def main():
async with AsyncFirebaseClient() as client:
client.creds_from_service_account_file("secret-store/mobile-app-79225efac4bb.json")
# or using a dictionary
# client.creds_from_service_account_info({...})
android_config = AndroidConfig.build(
priority="high",
ttl=2419200,
collapse_key="push",
title="Store Changes",
body="Recent store changes",
data={"discount": "15%", "key_1": "value_1"},
)
message = Message(android=android_config, token="device-token-here")
response = await client.send(message)
print(response.success, response.message_id)
if __name__ == "__main__":
asyncio.run(main())
send() returns an FCMResponse with success (bool), message_id (str), and exception (on failure) attributes.
Platform Configs
Build platform-specific configs using the .build() classmethod:
Android
from async_firebase import AndroidConfig
android_config = AndroidConfig.build(
priority="high",
ttl=2419200,
collapse_key="push",
data={"discount": "15%", "key_1": "value_1"},
title="Store Changes",
body="Recent store changes",
)
To send a data-only message (no notification), simply omit all notification fields:
android_config = AndroidConfig.build(
priority="high",
ttl=2419200,
collapse_key="push",
data={"discount": "15%", "key_1": "value_1"},
)
New in v6.0: image, ticker, sticky, event_timestamp, local_only, notification_priority, vibrate_timings_millis, default_vibrate_timings, default_sound, light_settings, default_light_settings, fcm_options, direct_boot_ok, bandwidth_constrained_ok, restricted_satellite_ok.
iOS (APNs)
from async_firebase import APNSConfig
apns_config = APNSConfig.build(
priority="normal",
ttl=2419200,
apns_topic="store-updated",
collapse_key="push",
title="Store Changes",
alert="Recent store changes",
badge=1,
category="test-category",
custom_data={"discount": "15%", "key_1": "value_1"},
)
To send a data-only APNS message, omit all alert fields:
apns_config = APNSConfig.build(
priority="high",
ttl=2419200,
collapse_key="push",
badge=0,
category="test-category",
content_available=True,
custom_data={"key_1": "value_1"},
)
New in v6.0: subtitle, sound as CriticalSound, fcm_options, live_activity_token.
Web Push
from async_firebase import WebpushConfig
webpush_config = WebpushConfig.build(
data={"discount": "15%"},
title="Store Changes",
body="Recent store changes",
link="https://example.com/store",
)
Note:
client.build_android_config(),client.build_apns_config(), andclient.build_webpush_config()are deprecated. Use the.build()classmethods directly.
Multicast
Send notifications to up to 500 devices at once:
from async_firebase import AsyncFirebaseClient, MulticastMessage, AndroidConfig
async with AsyncFirebaseClient() as client:
client.creds_from_service_account_info({...})
android_config = AndroidConfig.build(priority="high", title="News", body="Breaking news!")
multicast = MulticastMessage(
android=android_config,
tokens=["token_1", "token_2", "token_3"],
)
batch_response = await client.send_each_for_multicast(multicast)
for resp in batch_response.responses:
print(resp.success, resp.message_id)
send_each_for_multicast() returns an FCMBatchResponse containing individual FCMResponse objects for each token.
Topics
Sending to a topic
from async_firebase import AsyncFirebaseClient, Message, AndroidConfig
async with AsyncFirebaseClient() as client:
client.creds_from_service_account_info({...})
message = Message(
android=AndroidConfig.build(priority="high", title="News", body="Update!"),
topic="breaking-news",
)
response = await client.send(message)
A Message accepts exactly one of: token, topic, or condition.
Managing topic subscriptions
from async_firebase import AsyncFirebaseClient
async with AsyncFirebaseClient() as client:
client.creds_from_service_account_info({...})
# Subscribe
response = await client.subscribe_devices_to_topic(
device_tokens=["token_1", "token_2"],
topic_name="breaking-news",
)
# Unsubscribe
response = await client.unsubscribe_devices_from_topic(
device_tokens=["token_1", "token_2"],
topic_name="breaking-news",
)
Advanced Usage
Dry-run mode
Validate messages without actually sending them:
response = await client.send(message, dry_run=True)
Dry-run is available on send(), send_each(), and send_each_for_multicast().
Direct dataclass construction
For full control, construct message dataclasses directly instead of using .build():
from datetime import datetime, timezone
from async_firebase.messages import APNSConfig, APNSPayload, ApsAlert, Aps, Message
apns_config = APNSConfig(
headers={
"apns-expiration": str(int(datetime.now(timezone.utc).timestamp()) + 7200),
"apns-priority": "10",
"apns-topic": "test-topic",
"apns-collapse-id": "something",
},
payload=APNSPayload(
aps=Aps(
alert=ApsAlert(title="some-title", body="alert-message"),
badge=0,
sound="default",
content_available=True,
category="some-category",
mutable_content=False,
custom_data={
"link": "https://link-to-somewhere.com",
"ticket_id": "YXZ-655512",
},
)
),
)
message = Message(apns=apns_config, token="device-token-here")
response = await client.send(message)
Error handling
Send failures raise specific exceptions from async_firebase.errors:
from async_firebase.errors import (
AsyncFirebaseError,
UnregisteredError,
QuotaExceededError,
InvalidArgumentError,
)
try:
response = await client.send(message)
except UnregisteredError:
# Device token is no longer valid — remove it
...
except QuotaExceededError:
# FCM rate limit hit — back off and retry
...
except AsyncFirebaseError as e:
print(e.code, e.message)
Failed responses also populate FCMResponse.exception without raising, depending on the send method.
Changelog
See CHANGES.md for the full release history.
License
async-firebase is offered under the MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file async_firebase-6.1.0.tar.gz.
File metadata
- Download URL: async_firebase-6.1.0.tar.gz
- Upload date:
- Size: 81.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.12 Linux/6.17.0-1008-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6b0dc7afad025c4a25c9837f43a3e474cedcad2dce5ed5f276da3961c6caf2a
|
|
| MD5 |
7663076166c26ab50fbd4a4ca16b792a
|
|
| BLAKE2b-256 |
e262114f7deb972b9388bf0397e51271fc7f4357bf2c8b0a738b43c3d0f42f65
|
File details
Details for the file async_firebase-6.1.0-py3-none-any.whl.
File metadata
- Download URL: async_firebase-6.1.0-py3-none-any.whl
- Upload date:
- Size: 28.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.12 Linux/6.17.0-1008-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5eaa88208cb6b6007537766a627a56bd4d7824b456f7491835b9eb471d4b2804
|
|
| MD5 |
54f484f1ad8dbac2326a530375ce3159
|
|
| BLAKE2b-256 |
99a8938f7c4efa08257a74b2be46c2afe91778f7af5c74c1f27dd13e2bc0a061
|