Skip to main content

async-firebase logo

Lightweight asynchronous Python client for Firebase Cloud Messaging (FCM)

PyPI download month PyPI version fury.io PyPI license PyPI pyversions CI Codacy coverage

  • Free software: MIT license
  • Requires: Python 3.10+

Features

  • Extremely lightweight and does not rely on firebase-admin which is hefty
  • Send push notifications to Android, iOS, and Web devices
  • Multicast push notifications (up to 500 targets 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.

Message Types

FCM supports notification messages (displayed automatically by the system when the app is in the background), data messages (handled entirely by your app), and a combination of both. Use notification messages for user-visible alerts; use data messages for silent pushes, background syncs, or when your app needs full control over how content is processed.

See Set the message type in the official Firebase documentation for details.

Platform Configs

Build platform-specific configs using the .build() classmethod. The builders support both notification and data-only messages — simply omit notification/alert fields to produce a data-only payload.

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(), and client.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,
        fids=["fid_1", "fid_2", "fid_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 target.

MulticastMessage accepts fids (Firebase installation IDs), tokens (deprecated), or both — up to 500 targets combined.

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: fid, token, topic, or condition. token is deprecated in favor of fid (the Firebase installation ID of the target app instance).

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

async_firebase-6.2.2.tar.gz (120.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

async_firebase-6.2.2-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file async_firebase-6.2.2.tar.gz.

File metadata

  • Download URL: async_firebase-6.2.2.tar.gz
  • Upload date:
  • Size: 120.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for async_firebase-6.2.2.tar.gz
Algorithm Hash digest
SHA256 6a2ebef5a058c29ece0b2bad2a0e99f5c8be70e39365989da6c9aef4b603f116
MD5 959689576b6c0381e7a930e63c9879cc
BLAKE2b-256 888a5c779a297819251b104fdc208cff03a7a6df0aec149e0696c35259e5a79a

See more details on using hashes here.

File details

Details for the file async_firebase-6.2.2-py3-none-any.whl.

File metadata

  • Download URL: async_firebase-6.2.2-py3-none-any.whl
  • Upload date:
  • Size: 29.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for async_firebase-6.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6e574c3449375e1d142439e6b5e052a51c921a4aaae602450f9a93da7297155f
MD5 4a3ff1b1af5ac81466c16d7c6caf13fb
BLAKE2b-256 52da24aab6f3d521a766184502ef6fd0cde509a4f8704b3d2412d4a8e7d19be0

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

6.2.2 This release

2 files

6.2.1

2 files

6.2.0

2 files

6.1.2

2 files

6.1.1

2 files

6.1.0

2 files

6.0.2

2 files

6.0.1

2 files

6.0.0

2 files

5.2.0

2 files

5.1.1

2 files

5.1.0

2 files

5.0.0

2 files

4.1.0

2 files

4.0.0

2 files

3.12.1

2 files

3.12.0

2 files

3.11.0

2 files

3.10.0

2 files

3.9.0

2 files

3.8.0

2 files

3.7.0

2 files

3.6.3

2 files

3.6.2

2 files

3.6.1

2 files

3.6.0

2 files

3.5.0

2 files

3.4.1

2 files

3.4.0

2 files

3.3.0

2 files

3.2.0

2 files

3.1.1

2 files

3.1.0

2 files

3.0.0

2 files

2.7.0

2 files

2.6.1

2 files

2.6.0

2 files

2.5.1

2 files

2.5.0

2 files

2.4.0

2 files

2.3.0

2 files

2.2.0

2 files

2.1.0

2 files

2.0.3

2 files

2.0.2

2 files

2.0.1

2 files

2.0.0

2 files

1.9.1

2 files

1.9.0

2 files

1.8.0

2 files

1.7.0

2 files

1.6.0

2 files

1.5.0

2 files

1.4.0

2 files

1.3.5

2 files

1.3.4

2 files

1.3.3

2 files

1.3.2

2 files

1.3.1

2 files

1.3.0

2 files

1.2.1

2 files

1.2.0

2 files

1.1.0

2 files

1.0.0

2 files

0.4.0

2 files

0.3.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page