iOS Critical Alerts in Capacitor Apps (FCM + Push Notifications)

If you ever tried to add iOS Critical Alerts to a Capacitor app, you probably discovered the annoying part:

You can send a critical notification payload…

…but iOS won’t treat it as critical unless your app has:

  1. the Critical Alerts entitlement from Apple
  2. the Critical Alert permission granted by the user
  3. the correct APNS/FCM payload

We got this request from a client for an existing Capacitor app that already used the official @capacitor/push-notifications plugin with Firebase Cloud Messaging (FCM) with Django as Backend.

This is what we did to make it work.

Step 1: Get the Critical Alerts entitlement from Apple

Critical Alerts are not available to every app by default.

Apple requires an entitlement:

com.apple.developer.usernotifications.critical-alerts

Docs: https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.developer.usernotifications.critical-alerts

Once Apple approves your request, you can enable it in Xcode.

Step 2: Enable “Critical Alerts” capability in Xcode

Open your iOS project in Xcode and go to:

Signing & Capabilities → + Capability → Critical Alerts

Make sure it actually appears in your entitlements file as:

com.apple.developer.usernotifications.critical-alerts

If it doesn’t, add it manually (this sometimes happens).

Step 3: The real issue — requesting permission for critical alerts

Here’s the catch:

The official Capacitor push notifications plugin doesn’t request critical alert permission.

When we dug into the native iOS code, we found the whole difference is adding one option to the authorization request:

UNUserNotificationCenter.current().requestAuthorization(
  options: [.alert, .sound, .badge, .criticalAlert]
) { granted, error in
  ...
}

Without .criticalAlert, iOS won’t grant critical-alert permission, even if your entitlement is correct.

Step 4: We created a small Capacitor plugin to request critical alerts permission

Because the official plugin doesn’t support it, we built a tiny Capacitor plugin that only does one thing:

✅ Request/check Critical Alerts permission on iOS

✅ Then you can keep using the official plugin for everything else

Get the Plugin here: https://www.npmjs.com/package/capacitor-critical-alerts

GitHub here: https://github.com/alonw0/capacitor-critical-alerts

Install:

npm install capacitor-critical-alerts
npx cap sync

Use it in your app:

import { CriticalAlerts } from 'capacitor-critical-alerts';

const requestCriticalAlerts = async () => {
  const status = await CriticalAlerts.checkPermissions();
  if (status.criticalAlerts !== 'granted') {
    const result = await CriticalAlerts.requestPermissions();
    console.log('Critical alerts permission:', result.criticalAlerts);
  }
};

Step 5: Send the correct APNS payload through FCM

After the user grants permission, the rest is “just payload”.

You need to include the critical sound object in your APS payload:

{
  "aps": {
    "alert": "This is a Critical Alert!",
    "badge": 1,
    "sound": {
      "critical": 1,
      "name": "your_custom_sound.aiff",
      "volume": 1.0
    }
  }
}

Or in Django when using firebase admin package fcm_django you can use the firebase objects like this:

device.send_message(
    Message(
        notification=Notification(
            title="Title text",
            body="Body text"
        ),
        data={"data": "test data"},
        apns=APNSConfig(
            payload=APNSPayload(
                aps=Aps(
                    sound=CriticalSound(
                        name="default",
                        critical=True,
                        volume=1
                    )
                )
            )
        ),
        # ...
    )
)

That’s it.

Once entitlement ✅ + permission ✅ + payload ✅ are in place — you’re good to go.

Bonus: Custom Sound for Critical Alerts

If you want a custom sound for your critical alert in iOS:

  1. The sound has to be bundled with your app
  2. It has to be a CAF, AIFF, or WAV format and less than 30 seconds
  3. Name it in the payload ("name": "alert.wav") and place it inside the Resources directory in Xcode
  4. Update the JSON payload with your sound filename

Links: