---
title: "Better Notifications with FCM AndroidConfigV2"
description: "Better Notifications with FCM AndroidConfigV2"
published: "2026-11-03"
last_updated: "2026-11-03"
authors:
  - "Aaron Labiaga (Developer Programs Engineer)"
  - "Arthur Thompson (Developer Programs Engineer)"
categories:
  - "Cloud Messaging"
  - "Android"
canonical_url: "https://firebase.blog/posts/2026/11/fcm-android-config-v2"
---

# Better Notifications with FCM AndroidConfigV2

*Published November 3, 2026 by Aaron Labiaga (Developer Programs Engineer), Arthur Thompson (Developer Programs Engineer)*

---
Firebase Cloud Messaging (FCM) v2 brings more predictability and reliability to remote notifications for the Android ecosystem. Start using FCM ACv2 today by following our [guidelines](https://firebase.google.com/docs/cloud-messaging/send/v2-api).

For Android developers, FCM push notifications are essential for delivering real-time, engaging mobile experiences. But throughout the years, as the Android Ecosystem evolved, delivering push notifications across changes in battery management modes, power-saving states, and background queueing systems has introduced unpredictable delays. Non-deterministic delivery timelines directly impact user experience and decrease engagement across key app workflows.

### The challenge: Solving last-mile notification delays

To understand the improvements in ACv2, let's examine how legacy notification payloads flow to the Android OS.

![Diagram showing FCM v1 on-device message delivery flow from App Server and FCM Server through GmsCore, BroadcastQ, JobScheduler, and NotifManager with red markers indicating gates that can cause delays such as Deep Doze, Quota, Light Doze, and Standby/Doze](https://firebasestorage.googleapis.com/v0/b/first-class-blog.appspot.com/o/blog-assets%2F2026%2F11%2Ffcm-android-config-v2%2Foptimized%2Ffig1-fcm-v1-delivery.jpg?alt=media)
*Fig 1: Visualization of the FCM v1 on-device message delivery and the various gates that cause delay.*

Under the v1 FCM payload structure, messages are dispatched via broad system broadcasts. Once received on the device by Google Play services (GMSCore), the message is handed over to the application through the single entry point in the FCM Android SDK, [onMessageReceived](https://firebase.google.com/docs/cloud-messaging/android/receive-messages#override-onmessagereceived).

This legacy model suffers from significant structural limitations. Because the legacy `onMessageReceived` callback has a `void` return type, the system receives zero feedback regarding whether the application successfully rendered a notification, ran out of background execution time, or crashed.

Android's ecosystem has also grown complex. Evolving changes and restrictions on various device resources (battery management, doze modes, app standby buckets) have caused unpredictable message delays for an API that was designed in a different era.

Additionally, the v1 API does not provide clear, enforced guidelines for developers.

- **On the client side**, it fails to help applications easily maintain valid lifecycle states.
- **On the server side**, the legacy message priority API (high vs normal) often led developers to guesswork configuration settings rather than declaring explicit intent.

### The solution

FCM ACv2 is an update that ensures timely notification delivery with a well-lit API that will make it easier for developers to do the right thing and difficult to do the wrong thing.

In v2, the new device data flow changes how the application handles messages for notifications. These changes allow for a modernized API with improved guard rails.

![Diagram showing FCM v2 on-device message delivery flow where FCM Server sends an FCM Message to the gcm module (GMSCore), which routes Notification to the FCM SDK and App with a 20-second timeout protecting timeliness, returning Notification metadata feedback to GMSCore and posting directly to the platform Notification API](https://firebasestorage.googleapis.com/v0/b/first-class-blog.appspot.com/o/blog-assets%2F2026%2F11%2Ffcm-android-config-v2%2Foptimized%2Ffig2-fcm-v2-delivery.jpg?alt=media)
*Fig 2: Visualization of the FCM v2 on-device message delivery and how timeliness of message delivery is improved.*

- **On the client side,** callbacks require developers to return a `NotificationResponse` object, providing metadata and feedback directly back to the platform; allowing the system to facilitate timeliness and reliability. On the device, the FCM SDK and GMS Core take primary ownership of posting the notification directly through Android's Notification API, guaranteeing timely delivery even if app code to handle the notification is absent.
- **On the server side,** ambiguous priority configurations (normal vs high) for messages are deprecated in favor of message intent-driven fields, BackgroundSync vs RemoteNotification.

### A simpler API with intent-driven messaging

![Diagram comparing Send Message Types in v2: BackgroundSync for non-urgent tasks (possibly delayed to optimize device battery) versus RemoteNotification for user-visible updates (no delay, must post a user-visible notification unless app is in foreground or user permits background runs)](https://firebasestorage.googleapis.com/v0/b/first-class-blog.appspot.com/o/blog-assets%2F2026%2F11%2Ffcm-android-config-v2%2Foptimized%2Ffig3-acv2-message-types.jpg?alt=media)
*Fig 3: The message types in ACv2 and the successor to message priorities 'normal' vs 'priority'.*

1. **`BackgroundSync` (Non-Urgent Data Sync):** Designed for data updates, cache refreshes, and state updates. Delivery is batched and scheduled to optimize battery health, preserving power without triggering unexpected user-facing notifications.
2. **`RemoteNotification` (Urgent & User-Visible):** For time-sensitive, user-facing notifications. These messages bypass Doze restrictions and battery batching delays to alert users immediately.

#### RemoteNotification payload features

- **Auto-Rendered Notifications:** If `mutable_content` is set to `false` (default), GMS Core immediately renders and displays the server-provided notification payload to the status bar without waking application background code.
- **Mutable Content Customization:** Setting `mutable_content` to `true` instructs GMS Core to bind to the client application and invoke `onNotificationReceived(RemoteMessage)`. Wherein the app can modify the notification: e.g. end-to-end encryption decryption, dynamic image attachment, or localized text rendering, prior to display.
- **Fallback Protection:** A server-defined notification fallback payload is included within `remote_notification` even when `mutable_content` is set to `true`. GMS Core uses this backup payload if the application callback times out, crashes or exceeds operational suppression limits.
- **v1 Compatibility Flag:** Set `use_as_v1_data_message` to `true` to ensure older client installations receive pure data broadcasts if migrating from legacy data-only structures.

#### BackgroundSync payload features

When issuing a `background_sync` payload, combine it with a `collapse_key`. If a device is offline, FCM collapses intermediate queued messages, delivering only the most recent data payload upon device wakeup. Both `background_sync` and `remote_notification` will continue to support the existing payload of up to 4KB of data.

#### Send request changes

The FCM AndroidConfigV2 API replaces generic configuration knobs with intent-oriented message types. Server-side requests now explicitly distinguish between `AndroidRemoteNotification` (`remote_notification`) for user-visible alerts and `AndroidBackgroundSyncMessage` (`background_sync`) for non-urgent tasks like background data synchronization. Delivery priority is inferred directly from the selected message type, and the structure remains backward compatible so server and client components can be upgraded independently.

An example of sending an `android_v2` `remote_notification` payload via the FCM HTTP v1 `messages:send` endpoint with `mutable_content` enabled, a fallback `notification`, and custom `data`:

**`send-notification.sh`**

```bash
curl -X POST \
  "https://fcm.googleapis.com/v1/projects/${PROJECT_ID}/messages:send" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{
    "message": {
      "token": "<DEVICE_REGISTRATION_TOKEN>",
      "android_v2": {
        "ttl": "3600s",
        "collapse_key": "chat_updates",
        "data": {
          "conversation_id": "12345"
        },
        "remote_notification": {
          "mutable_content": true,
          "notification": {
            "title": "New message",
            "body": "You have a new message",
            "channel_id": "messages"
          }
        }
      }
    }
  }'
```

### Server-side send request restructuring

Updating server backend requests to support `ACv2` is fully backward compatible. When target servers send `ACv2`, FCM automatically translates the message payload for devices running older client SDK versions, allowing backend teams to deploy updates without waiting for full app updates across user bases.

In your HTTP v1 REST payload, replace the legacy android configuration block with `android_v2`. Standard options such as time-to-live (TTL), `collapse_key`, and `restricted_package_name` remain configurable alongside your selected intent structure.

### Modernizing client callbacks on Android

To handle v2 messages on Android, apps update their service extending [FirebaseMessagingService](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService). Instead of routing all incoming traffic through a central `onMessageReceived()` method, developers implement specialized callbacks.

#### 1. Handling remote notifications (onNotificationReceived)

When a RemoteNotification arrives with `mutable_content: true`, GMS Core binds directly to the app and calls [onNotificationReceived(message)](https://firebase.google.com/docs/cloud-messaging/send/v2-api#handling-remotenotifications). The method requires returning a `NotificationResponse` object to give explicit feedback back to the platform:

- **Modifying notifications:** Construct a [`Notification`](https://developer.android.com/reference/androidx/core/app/NotificationCompat) and wrap it in `NotificationResponse.create()`. Values from the server fallback payload can be read directly from the incoming message while adding local enrichments.
- **Suppressing notifications:** If the user currently has the relevant activity or active chat open, suppress display by returning `NotificationResponse.suppress()`.
- **Streaming and Cancelling ([`FcmNotificationManager`](https://github.com/firebase/firebase-android-sdk/blob/feature/fcm-android-config-v2-eap/firebase-messaging/src/main/java/com/google/firebase/messaging/FcmNotificationManager.java)):** For advanced workflows—such as posting grouped conversation summaries or cancelling outdated alerts before displaying new ones—retrieve an instance of `FcmNotificationManager` using `getFcmNotificationManager(message)`. Developers can invoke `postNow()` and `cancelNow()` in a streaming sequence before returning `manager.finished()`.

An example of the v2 way of handling a `RemoteNotification` when `mutable_content` is set to `true`:

**`MyFirebaseMessagingService.java`**

```java
// Common case

@Override
public NotificationResponse onNotificationReceived(
    RemoteMessage message) {
  // create the notification...
  return NotificationResponse.post("tag1", 1, new Notification());
}
```

A more advanced example of handling a `RemoteNotification`, posting and cancelling multiple notifications, achieved via `FcmNotificationManager`:

**`MyFirebaseMessagingService.java`**

```java
// Advanced use - post & cancel multiple notifications
@Override
public NotificationResponse onNotificationReceived(RemoteMessage message) {
  FcmNotificationManager manager =
      getFcmNotificationManager(message);
  for (int i = 0; i < 10; i++) {
    // posts and cancels are immediate
    manager.postNow("tag" + i, i, new Notification());
    manager.cancelNow("tag" + i, i);
  }
  return manager.finished(); // invalidates the manager
}
```

#### 2. Handling background synchronization (onBackgroundSyncReceived)

For non-urgent data operations, override `onBackgroundSyncReceived()`. Because BackgroundSync is optimized for background work, posting user-visible UI notifications from this callback is discouraged.

#### 3. Handling queue cleanups (onDeletedMessages)

If a device remains offline for an extended period or server queues exceed capacity limits, pending messages may be dropped prior to delivery. Overriding `onDeletedMessages()` allows your application to schedule a complete state resynchronization with your application server.

### Policy enforcement: Timeliness and suppression limits

To ensure system reliability across the Android ecosystem, there are strict operational boundaries to `RemoteNotification` processing:

- **20-Second Processing Timeout:** When `mutable_content` is enabled, `onNotificationReceived(RemoteMessage)` must return a valid `NotificationResponse` within 20 seconds. If execution times out, GMS Core automatically renders and posts the default server fallback notification.
- **25% Background Suppression Limit:** Apps can suppress up to 25% of background notification traffic before original notifications are automatically posted; foreground suppressions and apps with unrestricted background permissions are exempt.

> **Note:** Policy parameters such as the 20 second timeout and the 25% suppression threshold may change before General Availability (GA).

### Migration summary and next steps

Adopting `AndroidConfigV2` resolves notification delay issues and simplifies client-side service handling. Because server payloads and client callbacks are designed for incremental rollout, engineering teams can begin updating backend messaging schemas immediately, followed by upgrading client SDK handlers.

Start by updating server send pipelines to output `android_v2` structures, and review your Android client service implementations to adopt `onNotificationReceived(RemoteMessage)` and `onBackgroundSyncReceived(RemoteMessage)` today.

#### Legacy v1 vs. new v2 API

| Feature | Legacy (ACv1) | New (ACv2) |
| --- | --- | --- |
| **Priority Definition** | Explicit `priority: "high"` or `"normal"` | Implied by message type `remote_notification` vs `background_sync` |
| **Notification Posting** | App manually invokes `NotificationManager.notify()` | FCM SDK / GMS Core posts directly or via structured `NotificationResponse` |
| **Client Callbacks** | `onMessageReceived(RemoteMessage)` `onDeletedMessages()` | `onNotificationReceived(RemoteMessage)`, `onBackgroundSyncReceived(RemoteMessage)`, `onDeletedMessages()` |

### Relevant resources

- [Migrate from FCM HTTP v2 API to Android ConfigV2](https://firebase.google.com/docs/cloud-messaging/send/v2-api)
- [Firebase Cloud Messaging troubleshooting & FAQ](https://firebase.google.com/docs/cloud-messaging/troubleshooting)
