skip to content

With expo-notifications, how do you set or clear the app icon badge, and why can setBadgeCountAsync resolve false?

level: juniorimportance: nice to knowfreq 22%

answer

  1. a number on the app icon
  2. setBadgeCountAsync(0) clears it
  3. iOS needs allowBadge
  4. not every Android launcher shows badges
  5. the app keeps the count

basics

~10 s

Call Notifications.setBadgeCountAsync(n), where 0 clears the badge, and read it with getBadgeCountAsync. It resolves false on iOS when the badge permission was not granted, and on Android launchers that do not support icon badges.

solid answer

~40 s

`Notifications.setBadgeCountAsync(count)` sets the number on the app icon, `0` clears it, and `getBadgeCountAsync()` reads it back. The promise resolves a boolean: on **iOS** it is `false` when the user has not granted `allowBadge` (which the default permission request includes); on **Android** it is `false` when the device's launcher does not support icon badges, which varies by device. The badge is not derived from your notifications: the app must compute it, for a medication app for example the doses still due today, and set it when that changes, such as after a Taken action or when the app opens. A scheduled notification can also carry `badge` in its content, and on iOS the foreground handler's `shouldSetBadge` decides whether a foreground notification updates it.

code

typescript · 7 lines
typescript
import * as Notifications from 'expo-notifications';

export async function refreshDosesBadge(dosesDueToday: number): Promise<boolean> {
  const shown = await Notifications.setBadgeCountAsync(Math.max(0, dosesDueToday));
  // false: no badge permission on iOS, or a launcher without badge support on Android
  return shown;
}

go deeper

for a junior

Remember setBadgeCountAsync with 0 to clear, and that it resolves false when the badge cannot be shown.

for a middle

Explain the two failure causes (missing allowBadge on iOS, launcher support on Android) and why the app, not the OS, owns the number.

for a senior

Keep the badge correct in production: one compute-and-set function, recomputed on launch and after actions, with the boolean result treated as a hint rather than an error.

for a principal

Decide whether a badge adds value for the product at all, since it is platform-dependent and easy to let drift out of sync with reality.

## What the badge is The **badge** is the small number shown on the app icon. In a medication app it can show how many doses are still due today. expo-notifications exposes it through two calls: - `Notifications.setBadgeCountAsync(count)` sets it; **`0` clears it**; - `Notifications.getBadgeCountAsync()` reads the current value. ## Why setting it can fail `setBadgeCountAsync` resolves a boolean that says whether the badge was actually set: | Platform | Resolves `false` when | |---|---| | iOS | The user has not granted the badge permission (`allowBadge`) | | Android | The device's launcher does not support app icon badges | On iOS, the default `requestPermissionsAsync()` call asks for alerts, badges and sounds together, so an app that requested permission with custom options and left `allowBadge` out cannot set a badge. On Android, badge support depends on the launcher the device ships with; expo-notifications uses a badge library that talks to supported launchers, and the result is simply `false` elsewhere. Code should treat the badge as an enhancement, never as the only place important information appears. ## The app owns the number The operating system does not count your notifications for you. Clearing notifications from the tray does not reset the number set with `setBadgeCountAsync` on iOS, and scheduling a reminder does not increase it unless the content says so. The reliable approach: 1. Compute the value from app data, for example doses scheduled for today minus doses recorded as taken. 2. Set it whenever that data changes: after a Taken action, after the day rolls over, when the app opens. 3. Set `0` when nothing is due. ## Other ways the badge changes - A notification's content can include `badge`, so a scheduled reminder can set the number when it is delivered. - On iOS, the foreground notification handler's `shouldSetBadge` decides whether a notification delivered while the app is open applies its badge. - On Android, a channel's `showBadge` setting affects whether that channel's notifications contribute to the launcher's badge display. ## Testing the badge Badge behavior is easy to miss in development, so check it deliberately: 1. On iOS, request permission with and without `allowBadge` and confirm the boolean result changes. 2. On two different Android devices, confirm whether the launcher shows a number, a dot or nothing. 3. Record a dose, background the app, and check the number dropped. 4. Change the device date to the next day and confirm the count is recomputed on launch. ## Keeping it correct for a medication app - Recompute on launch, since the day may have changed while the app was closed. - Update it inside the handler for the Taken action, so the count drops immediately. - Avoid setting it from several places with different logic; one function that computes and sets the badge keeps it consistent. ## Badges and push When the server also sends pushes, the badge can be set from two places: the push content and the app. If the server does not know which doses were taken offline, its number will drift from the app's. A simple rule avoids that: let the app be the only writer of the badge, recomputing it whenever the app runs, and do not set badge values from the server at all. ## Common mistakes - Assuming the badge equals the number of notifications in the tray. - Ignoring the boolean and assuming the badge is always visible. - Requesting iOS permission without `allowBadge`, then wondering why the badge never appears. - Forgetting to reset to `0`, leaving a stale number after all doses are taken.

  • Why does the badge still show 2 after the user swiped away all medication notifications on iOS?
    The badge number is separate state that the app sets; dismissing notifications does not change it. The app must recompute the value, for example when it opens or when a dose is recorded, and call `setBadgeCountAsync` with the new number, or `0` when nothing is due.

saying these in an interview costs you the question

  • The badge automatically equals the number of notifications in the tray
  • setBadgeCountAsync always succeeds on Android
  • Clearing the tray also clears the badge set with setBadgeCountAsync
  • iOS shows the badge even if allowBadge was not granted
  • Passing a negative number is the way to clear the badge