PushX.FCM (PushX v0.5.0)

Copy Markdown View Source

Firebase Cloud Messaging (FCM) client.

Sends push notifications to Android devices and web browsers using the FCM v1 API with OAuth2 authentication via Goth.

Configuration

Add to your config:

config :pushx,
  fcm_project_id: "my-project-id",
  fcm_credentials: {:file, "priv/keys/firebase-service-account.json"}

Usage

# Simple notification
PushX.FCM.send(device_token, %{
  "notification" => %{
    "title" => "Hello",
    "body" => "World"
  }
})

# Using Message struct
message = PushX.Message.new("Hello", "World")
PushX.FCM.send(device_token, message)

# With custom data
PushX.FCM.send(device_token, notification, data: %{"key" => "value"})

Web Push (Chrome, Firefox, Edge)

FCM supports web push using the same API. Web tokens come from the browser's Firebase Messaging SDK (firebase.messaging().getToken()).

# Web push with click action
PushX.FCM.send(web_token, payload,
  webpush: %{
    "fcm_options" => %{"link" => "https://example.com/page"}
  }
)

# Using web notification helper
payload = PushX.FCM.web_notification("Title", "Body", "https://example.com")
PushX.FCM.send(web_token, payload)

Summary

Functions

Creates a simple notification payload.

Sends a push notification to an Android device with automatic retry.

Sends notifications to multiple devices concurrently.

Sends a data-only message (no visible notification) with automatic retry.

Sends a data-only message without retry.

Sends a push notification without retry.

Sends a web push notification with automatic retry.

Creates a web push notification payload with click action.

Types

option()

@type option() ::
  {:project_id, String.t()}
  | {:data, map()}
  | {:android, map()}
  | {:apns, map()}
  | {:webpush, map()}

payload()

@type payload() :: map() | PushX.Message.t()

token()

@type token() :: String.t()

Functions

notification(title, body, opts \\ [])

@spec notification(String.t(), String.t(), keyword()) :: map()

Creates a simple notification payload.

Examples

iex> PushX.FCM.notification("Hello", "World")
%{"title" => "Hello", "body" => "World"}

send(device_token, payload, opts \\ [])

@spec send(token(), payload(), [option()]) ::
  {:ok, PushX.Response.t()} | {:error, PushX.Response.t()}

Sends a push notification to an Android device with automatic retry.

Uses exponential backoff for transient failures following Google's best practices. Permanent failures (bad token, invalid argument) are not retried.

Options

  • :project_id - Firebase project ID (default: from config)
  • :data - Custom data payload map
  • :android - Android-specific configuration
  • :apns - APNS configuration (for iOS via FCM)
  • :webpush - Web push configuration

Returns

  • {:ok, %PushX.Response{}} on success
  • {:error, %PushX.Response{}} on failure

send_batch(device_tokens, payload, opts \\ [])

@spec send_batch([token()], payload(), [option()]) :: [
  {token(), {:ok, PushX.Response.t()} | {:error, PushX.Response.t()}}
]

Sends notifications to multiple devices concurrently.

Options

All standard options plus:

  • :concurrency - Max concurrent requests (default: 50)
  • :timeout - Timeout per request in ms (default: 30_000)

Returns

A list of {token, result} tuples.

send_data(device_token, data, opts \\ [])

@spec send_data(token(), map(), [option()]) ::
  {:ok, PushX.Response.t()} | {:error, PushX.Response.t()}

Sends a data-only message (no visible notification) with automatic retry.

send_data_once(device_token, data, opts \\ [])

@spec send_data_once(token(), map(), [option()]) ::
  {:ok, PushX.Response.t()} | {:error, PushX.Response.t()}

Sends a data-only message without retry.

send_once(device_token, payload, opts \\ [])

@spec send_once(token(), payload(), [option()]) ::
  {:ok, PushX.Response.t()} | {:error, PushX.Response.t()}

Sends a push notification without retry.

Use this when you want to handle retries yourself or for testing.

send_web(device_token, title, body, link, opts \\ [])

@spec send_web(token(), String.t(), String.t(), String.t(), keyword()) ::
  {:ok, PushX.Response.t()} | {:error, PushX.Response.t()}

Sends a web push notification with automatic retry.

Convenience function that combines web_notification/4 with send/3.

Examples

PushX.FCM.send_web(web_token, "Hello", "World", "https://example.com")

# With options
PushX.FCM.send_web(web_token, "Alert", "Check this out",
  "https://example.com/page",
  icon: "https://example.com/icon.png"
)

web_notification(title, body, link, opts \\ [])

@spec web_notification(String.t(), String.t(), String.t(), keyword()) :: map()

Creates a web push notification payload with click action.

This helper creates a notification optimized for web browsers (Chrome, Firefox, Edge). The link option specifies the URL to open when the notification is clicked.

Arguments

  • title - Notification title
  • body - Notification body
  • link - URL to open when clicked
  • opts - Optional keyword list:
    • :icon - Icon URL for the notification
    • :image - Large image URL
    • :badge - Badge icon URL (small monochrome icon)
    • :tag - Tag for notification grouping
    • :renotify - Whether to alert again for same tag (default: false)
    • :require_interaction - Keep notification until user interacts (default: false)

Examples

# Simple web notification
PushX.FCM.web_notification("New Message", "You have a new message", "https://example.com/messages")

# With icon and badge
PushX.FCM.web_notification("Sale!", "50% off today",
  "https://shop.com",
  icon: "https://shop.com/icon.png",
  badge: "https://shop.com/badge.png"
)