# Guideline 2.5.4: Apple rejected your background mode

> Guideline 2.5.4: Apple rejects a background mode declared with no feature using it. Remove the key or show the reviewer the audio, location or call.

Original page: [Guideline 2.5.4: Apple rejected your background mode](https://devoria.fr/en/blog/guideline-2-5-4-background-mode-rejected)
Author: [Mehdi Azizi](https://devoria.fr/en/mehdi-azizi)
Published: 2026-11-04
Content last revised: 2026-11-04


Guideline 2.5.4 limits background modes to their intended purpose: audio, location, VoIP calls, task completion, local notifications. You get rejected when your Info.plist declares one of these modes and the reviewer can't find any feature that needs it. **Remove the key if nothing uses it. Otherwise, show the reviewer the feature in thirty seconds.**

I publish my own iOS apps with Expo. Solys, my alarm clock with mini-games, declares the audio mode: I removed it, then put it back for a different reason. This guide is based on Apple's text, on rejections other developers have published and on my own projects. For the big picture on rejection reasons, read [why Apple rejects an app](https://devoria.fr/en/blog/apple-app-rejection-real-cases).

## What does guideline 2.5.4 say?

The rule fits in one sentence, in section 2 "Performance", part 2.5 "Software Requirements" of the [App Review Guidelines](https://developer.apple.com/app-store/review/guidelines/#2.5.4): "Multitasking apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion, local notifications, etc."

In plain terms: a background service is only for what it was built for. Hence the title "Guideline 2.5.4 - Performance - Software Requirements".

By default, an app that goes to the background gets suspended. To keep running, it declares one or more modes in the `UIBackgroundModes` key of its Info.plist. [Apple's documentation on background modes](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes) asks you to use them sparingly, because of battery life, and to prefer another solution when one exists. **Every mode you declare is a promise the reviewer can check.**

## Background modes and their intended use

| Mode                  | Key                   | Intended use             |
| --------------------- | --------------------- | ------------------------ |
| Audio, AirPlay, PiP   | `audio`               | Audible background sound |
| Location              | `location`            | Continuous location      |
| Voice over IP         | `voip`                | Calls with CallKit       |
| Background fetch      | `fetch`               | Regular network content  |
| Background processing | `processing`          | Scheduled tasks          |
| Remote notifications  | `remote-notification` | Push for new content     |

This table sums up Apple's page. In rejections posted on the forums, `audio`, `location` and `voip` come up the most.

## What does the 2.5.4 rejection message mean?

The message names the mode at issue. Two examples posted by developers on Apple's forums:

- **Audio**: "Your app still declares support for audio in the UIBackgroundModes key in your Info.plist but did not include features that require persistent audio." It goes on to explain that the `audio` key is meant for apps that play audible content in the background, like a music player. It offers two ways out: add that content or remove the key ([forum thread](https://developer.apple.com/forums/thread/95216)).
- **Location**: in a [December 2024 thread](https://developer.apple.com/forums/thread/771202), Apple found no feature other than employee tracking that required persistent location, and wrote that this use alone isn't appropriate.

My take: **the reviewer doesn't read your code, they look for a feature.** They need to be able to start it, send the app to the background and see that it keeps going.

The opposite case happens too. In a [May 2026 thread](https://developer.apple.com/forums/thread/826849), a read-aloud app that genuinely used the `audio` mode was rejected several times: the reviewer couldn't get the audio to start. Another developer writes there that, in his opinion, an attached video unblocked his case. That's a testimonial, not an Apple rule.

## Where does the key come from if you didn't add it?

With Expo, config plugins fill in the Info.plist at prebuild. **So a background mode can end up in your binary without you deciding it.**

### The expo-audio plugin, with its default settings

The [expo-audio documentation](https://docs.expo.dev/versions/latest/sdk/audio/) says it: the `enableBackgroundPlayback` option defaults to `true` and, on iOS, adds the `audio` mode. Declaring the plugin in its short form, `"expo-audio"`, is enough to declare the mode.

That's what I found while reviewing TradaZen before its first submission: short UI sounds in the foreground, but a plugin declared in short form. The fix is one line in `app.json`:

```json
{
  "expo": {
    "plugins": [["expo-audio", { "enableBackgroundPlayback": false }]]
  }
}
```

Other packages add a mode their own way. The `isIosBackgroundLocationEnabled` option of [expo-location](https://docs.expo.dev/versions/latest/sdk/location/) adds `location` only if you turn it on. [expo-background-task](https://docs.expo.dev/versions/latest/sdk/background-task/), on the other hand, adds `processing` at prebuild as soon as it's installed.

### The ios/ folder that keeps the old key

Second trap, which I hit on Solys in July 2026. I had removed `audio` from `app.json`, but the key was still in `ios/Solys/Info.plist`, generated earlier. A prebuild without `--clean` modifies that project instead of recreating it, and the plugin adds the key but never removes it. A local build would have shipped it. A cloud EAS build starts from a fresh prebuild when `ios/` is ignored by git, which was my case.

Before every build, I check what will actually ship:

```bash
npx expo config --type introspect --json | grep -o '"UIBackgroundModes":\[[^]]*\]'
npx expo prebuild --clean --platform ios
```

The first lists the modes the prebuild will write into the Info.plist. The second recreates the native project for a local build, wiping the `ios/` folder. On Solys, the first shows `"UIBackgroundModes":["audio"]`, on TradaZen nothing: both are intentional.

Adding or removing a mode changes the Info.plist, so the binary: **you need a new build, an over-the-air update isn't enough.** The [EAS Update documentation](https://docs.expo.dev/eas-update/introduction/) lists these changes among the ones that require a new binary, same as for [ITMS-90683](https://devoria.fr/en/blog/itms-90683-missing-purpose-string-expo).

## Solys: an audio mode declared, for a real reason

Solys is an alarm clock, but the `audio` mode isn't what makes the alarm ring: **the ringing goes through AlarmKit**, Apple's alarm service available since iOS 26 ([AlarmKit documentation](https://developer.apple.com/documentation/alarmkit)). The system rings, even in silent mode, not the app.

The history of the key, because the reasoning matters more than the line:

1. **Late July 2026, I removed it.** Nothing played sound in the background: the mini-game sound effects stay in the foreground, and the alarm doesn't depend on the app.
2. **Two days later, I put it back**, with night listening. This option records the sounds of your night with the mic and analyzes them on the iPhone. Recording has to continue with the screen locked, and the expo-audio documentation says the background recording option also adds the `audio` mode.

The justification changed in nature: **the mode is for recording, not playing.** Three safeguards, visible in the app:

- listening is an option, off by default, that you turn on from settings or the evening ritual;
- it has its own consent screen, as [rule 2.5.14](https://developer.apple.com/app-store/review/guidelines/#2.5.14) requires for any recording, and nothing leaves the phone;
- the mic closes ten minutes before the alarm, so listening and ringing never get in each other's way.

I can't guarantee a reviewer will always accept this declaration. I can say, for each piece, what it's for and where to see it.

### Alarm apps that kept themselves awake

Before AlarmKit, a third-party alarm app couldn't ring like Apple's alarm. So some libraries kept the app awake: the docs for the Flutter package [alarm2](https://pub.dev/packages/alarm2) describe a silent audio player running until the alarm. But silent audio makes nothing audible. **Since iOS 26, AlarmKit makes this workaround unnecessary.**

## Keep or remove the mode: the decision grid

| Your situation          | What to do              |
| ----------------------- | ----------------------- |
| Short foreground sounds | Remove `audio`          |
| Music or audiobook      | Keep it, show it        |
| Long recording          | Keep + consent          |
| Alarm or timer          | AlarmKit (iOS 26)       |
| Occasional location     | Significant changes     |
| Non-urgent sync         | `fetch` or `processing` |
| Audio or video calls    | `voip` with CallKit     |

For location, Apple's page cites the significant-change location service as an alternative to the `location` mode.

## The other parts of 2.5: 2.5.1 and 2.5.2

### 2.5.1: public APIs and frameworks used for their purpose

"Apps may only use public APIs and must run on the currently shipping OS." The app uses only public APIs, runs on the current OS version and drops anything deprecated. As with 2.5.4, each framework serves its intended purpose, mentioned in the description: HealthKit for health, HomeKit for the smart home. If a library calls a private API, your app takes the rejection.

### 2.5.2: no downloaded code that changes the app

The app stays self-contained in its bundle. It may not "download, install, or execute code which introduces or changes features or functionality of the app". Only educational apps that teach coding get a limited exception, with code that's fully visible and editable by the user.

With Expo, this affects EAS Update, whose documentation reminds you that updates must follow App Store rules. **Keep over-the-air updates for fixes, never to ship a feature the reviewer hasn't seen.** A review-related fix goes through a new build, as I explain in the [guideline 2.1](https://devoria.fr/en/blog/guideline-2-1-app-store-rejection-fix) guide.

## How do you reply to a 2.5.4 rejection?

The conversation happens in your app's App Review section, where you [reply to the App Review message](https://developer.apple.com/help/app-store-connect/manage-submissions-to-app-review/reply-to-app-review-messages/). Two cases:

- **The mode does nothing**: remove it, rebuild, check the introspection, then reply in two sentences.
- **The mode serves a real feature**: reply with the exact path and a short video, then reuse that text in the review notes of every version.

The template I'd use, to adapt (drop the alarm sentence if your app doesn't have one):

```text
Hello,

The "audio" background mode is used only by [feature], an
optional feature that [records / plays] audio while the
device is locked. It is off by default.

How to test:
1. Open [screen] and turn on [feature].
2. Accept the microphone permission if asked.
3. Tap [button], then lock the device.
   [What the reviewer will hear or see.]

Our alarm does not use this mode: it is scheduled with
AlarmKit and rings through the system.

Attached: a short screen recording of these steps.

Best regards,
```

## The 2.5.4 checklist before submitting

- Expo introspection shows only the modes you want, and you can name the feature behind each one.
- No plugin is declared in short form if it adds a mode by default, like expo-audio.
- Your local `ios/` folder keeps no old key, or you build from a clean prebuild.
- The feature starts quickly, with no hidden setting, and the review notes say which mode does what and how to test it.
- Any recording asks for explicit consent and shows a visible indicator. The rules on permission requests are in the [guideline 5.1.1](https://devoria.fr/en/blog/guideline-5-1-1-app-store-rejection) guide.
- For an alarm clock, the ringing goes through AlarmKit, not a sound played from the app.

## Check your submission before sending it

The [Review Kit](https://devoria.fr/en/kits/app-review) bundles my pre-submission checklist, templates for reviewer notes and Claude Code skills that review your project. For a human eye, [book an hour with me](https://devoria.fr/en/coaching): we go through Apple's message and your Info.plist together over video. The full process is on the [app rejected by Apple](https://devoria.fr/en/expertise/app-rejected-by-apple) page.

Getting ready for your first release? [Take the free diagnostic](https://devoria.fr/en/diagnostic): it puts the steps in order and sends you my Apple anti-rejection checklist.

Nobody can guarantee Apple will accept your app. A well-justified background mode, though, can be defended in thirty seconds.

## Frequently asked questions

### What does "Guideline 2.5.4 - Performance - Software Requirements" mean?

It's the rejection title when Apple thinks a background mode in your Info.plist isn't used for its intended purpose. The message names the mode and suggests showing the feature that uses it or removing the key.

### Do you need a new build after a 2.5.4 rejection?

If you remove or change a mode, yes: the key is in the Info.plist, so in the binary. If the mode is justified, a reply with the exact path and a video may be enough.

### Can you keep the audio mode for a few UI sounds?

No. Short sounds played in the foreground don't need it. With Expo, set `enableBackgroundPlayback` to `false` in the expo-audio plugin.

### Does an alarm clock app need the audio mode?

Not to ring, if it relies on AlarmKit, available since iOS 26: the system plays the alarm. On Solys, the `audio` mode is used for night listening, which records with the screen locked.

### Why does Apple cite 2.5.4 when I didn't declare anything?

A plugin may have done it for you: expo-audio adds the `audio` mode by default, and an old `ios/` folder can keep a key you removed from your config. Check with `npx expo config --type introspect`.


## Your project

[Review Kit](https://devoria.fr/en/kits/app-review): My App Store review checklist, the Apple rejections I fixed, a Google Play checklist and three Claude Code skills. $55.

[iOS & Android Kit](https://devoria.fr/en/kits/ios): Build your iPhone and Android app with Claude Code: the starter code from my apps, the path all the way to the stores, and every kit. $109.

[Diagnostic: what's between you and your iPhone app](https://devoria.fr/en/diagnostic): 7 questions, 60 seconds: find out what's really stopping you from publishing your iPhone app, get your 4-step path and the kit that fits you.
