> ## Documentation Index
> Fetch the complete documentation index at: https://docs.autosana.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing Push Notifications

> Test real APNs and FCM delivery on Autosana virtual devices.

Autosana can test the complete push-notification journey on iOS Simulators and Android Emulators: your app registers for remote notifications, your backend or managed provider sends a real notification, and the flow verifies both delivery and deep-link behavior.

Use this guide for visible notifications such as alerts, reminders, messages, and order updates.

<Info>
  Push-notification testing on physical iOS and Android devices requires an
  enterprise contract. [Contact us](mailto:founders@autosana.ai) for
  private-device availability and setup.
</Info>

## How a push test works

A typical test follows the same path as a real user:

1. Autosana installs and opens your test build.
2. The app requests notification permission and registers for remote notifications.
3. The app associates the resulting token or provider subscription with the test user.
4. The flow performs the action that schedules the notification, or runs a [runtime hook](/hooks#runtime-hooks) that calls your existing test endpoint.
5. The agent presses Home and waits for the notification.
6. The agent verifies the notification, taps it, and checks the destination screen.

Autosana does not need your APNs key or Firebase service-account credentials. Your backend or managed provider remains responsible for sending the notification.

Depending on the integration, your backend may store a raw APNs device token, an FCM or Expo registration token, or a managed-provider subscription.

## Prepare your test environment

Before writing the flow:

1. Choose a test account that can safely receive notifications in your development or staging environment.
2. Make the app send its latest device or registration token to your backend—or refresh its managed-provider subscription—after login and whenever the registration changes.
3. Make sure your backend or provider can confirm that the current push registration is associated with the test account before the flow triggers the notification.
4. Configure the build to use the same push provider and backend environment that the flow will exercise.

<Tip>
  A dedicated account is not required for sequential tests; you can reuse an
  existing automation account. If push tests can overlap, give each run or
  worker a separate account or another unique targeting key. Reusing one account
  can cause a notification to reach the wrong run when registrations overwrite
  one another or multiple registrations remain associated with the same user.
</Tip>

<Warning>
  Treat push registrations as temporary. Installing a new build, clearing app
  data, or resetting a virtual device can change the token or provider
  subscription. Refresh it during every run; do not copy one from an earlier run
  into the flow.
</Warning>

## Platform requirements

<Tabs>
  <Tab title="iOS Simulator">
    Autosana supplies an iOS 16 or later Simulator runtime. Your app's minimum deployment target can be lower than iOS 16.

    Configure the remaining requirements in your project:

    | Requirement                             | Where to configure it                                                                                                                                                                                                                                                                                   |
    | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Apple silicon Simulator build (`arm64`) | Build the app for an iOS Simulator on an Apple silicon Mac or CI runner, then upload the resulting `.app` as a `.zip`. See [Building Your Mobile App for Our Cloud](/app-build-guide).                                                                                                                  |
    | Push Notifications capability           | In Xcode, select the project and app target, open **Signing & Capabilities**, click **+ Capability**, and add **Push Notifications**. With manual signing, also enable Push Notifications for the explicit App ID in **Certificates, Identifiers & Profiles**, then regenerate its development profile. |
    | `aps-environment=development`           | Xcode adds this to the app target's entitlements when you enable the capability and use development signing. It does not go in `Info.plist`. Do not disable code signing or strip the app's signature when producing this build.                                                                        |
    | APNs registration                       | In the app or its push SDK, request notification permission and call `registerForRemoteNotifications()` during launch or sign-in.                                                                                                                                                                       |
    | Token association                       | For direct APNs, send the token from `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)` to your test backend. For FCM, Expo, or another managed provider, use its SDK callback to associate the resulting registration token or subscription with the signed-in test account.           |

    EAS Build and the Expo Push Service are independent. EAS Build syncs the Apple capabilities declared by your project, but running `eas build` alone does not add the push entitlement.

    * If the app uses the `expo-notifications` client library, add its config plugin. The plugin adds the development APNs entitlement even when your backend sends directly through APNs, FCM, or another provider instead of the Expo Push Service.
    * If the app does not use `expo-notifications`, declare `aps-environment: development` under `ios.entitlements` in the Expo app configuration, or use the push provider's config plugin when it manages this capability.
    * If the project has a native `ios` directory and does not use Continuous Native Generation, configure the capability in Xcode.

    You can verify the uploaded build before compressing it:

    ```bash theme={null}
    codesign -d --entitlements :- /path/to/YourApp.app
    ```

    The output must contain `aps-environment` with the value `development`.

    <Warning>
      **iOS Simulator tokens only work with the APNs sandbox.** If your backend
      connects to APNs directly, send these tokens to
      `api.sandbox.push.apple.com`. Do not send them to the production endpoint,
      `api.push.apple.com`; APNs will reject the token, commonly with a
      `BadDeviceToken` response.

      If you send through Firebase, Expo, OneSignal, or another push provider,
      you normally do not select the APNs hostname yourself. Make sure that
      provider is configured to deliver this development build through the APNs
      sandbox.
    </Warning>

    ### Configure your push provider

    Your provider must preserve the Simulator token's development environment all the way to APNs. Use the matching instructions below; if your provider is not listed, look for its **development**, **sandbox**, or **APNs environment** setting.

    #### [Direct APNs](https://developer.apple.com/documentation/usernotifications/sending-notification-requests-to-apns)

    Send the Simulator token to `api.sandbox.push.apple.com` and use the app's Simulator bundle ID as the `apns-topic`. Do not retry a `BadDeviceToken` response against the production endpoint.

    #### [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/ios/get-started)

    Continue sending the FCM registration token through the normal Firebase Admin SDK or FCM HTTP v1 endpoint. In the Firebase console, make sure the iOS app has a development APNs authentication key or certificate; FCM handles the connection to the APNs sandbox.

    #### [Expo](https://docs.expo.dev/push-notifications/push-notifications-setup/)

    When using an `ExpoPushToken`, send to the Expo Push Service normally. Install `expo-application` so `expo-notifications` can detect the iOS push environment, or pass `development: true` to `getExpoPushTokenAsync` for the Simulator build. Do not force `development` to `false`. If you retrieve a native APNs token and send it yourself, follow the Direct APNs instructions above.

    #### [OneSignal](https://documentation.onesignal.com/docs/en/ios-sdk-setup)

    Configure the OneSignal app for the APNs development environment. If you provision it through the OneSignal API, set `apns_env` to `development` because the API defaults this field to `production`; use a `.p8` key enabled for both Sandbox and Production.

    #### [Customer.io](https://docs.customer.io/journeys/channels/push/developer-guide/)

    In **Workspace Settings > Push > iOS**, enable **Send all push notifications to sandbox**. Customer.io recommends using a separate workspace for the sandbox environment, which also prevents Simulator registrations from mixing with production users.

    #### [Braze](https://braze-inc.github.io/braze-swift-sdk/documentation/braze/apns-certificate/)

    Use a separate Braze App or App Group for the development build and configure it with the development APNs credential. Braze allows only one active `.p12` certificate per app, so do not replace a live app's production certificate just to test a Simulator build.

    #### [Airship](https://docs.airship.com/developer/sdk-integration/apple/installation/advanced-integration/)

    Initialize the Simulator build with the Airship development/test app key and secret. Let the current Airship SDK infer the APNs environment from the build, or set `inProduction` to `false` when your integration selects it explicitly.

    #### [AWS SNS](https://docs.aws.amazon.com/sns/latest/api/API_CreatePlatformApplication.html)

    Create an SNS platform application whose platform is `APNS_SANDBOX`, register the Simulator token against that application's ARN, and send through the resulting endpoint. Do not register the token under an `APNS` production platform application.

    #### [Azure Notification Hubs](https://learn.microsoft.com/en-us/azure/notification-hubs/configure-apple-push-notification-service)

    Use a separate notification hub configured under **Apple (APNS)** in **Sandbox** mode. Do not switch a shared production hub to sandbox because registrations are tied to the APNs environment.

    #### [Iterable](https://support.iterable.com/hc/en-us/articles/360035112332-Push-Notification-Testing-and-Troubleshooting)

    Configure the Iterable app for `APNS_SANDBOX` and target the token generated by the Simulator build. A production registration or production push credential cannot be used with that token.

    Each Simulator and host Mac combination receives its own token, and the token's length can vary. Store the token as an opaque string without assuming a fixed size or format.

    If you use Firebase Cloud Messaging on iOS, use Firebase Apple SDK 10.3.0 or later and configure an APNs authentication key in the matching Firebase project. If Firebase method swizzling is disabled, pass the APNs token to Firebase Messaging in your app code.
  </Tab>

  <Tab title="Android Emulator">
    Upload an `.apk` or `.aab` configured for the Firebase project used by your test environment. The build must:

    * Include Firebase Cloud Messaging and the correct Firebase configuration.
    * Request `POST_NOTIFICATIONS` at runtime on Android 13 or later.
    * Create the notification channel used by the test on Android 8 or later.
    * Upload the newest FCM registration token to your test backend.

    Unlike APNs, FCM does not have a separate sandbox endpoint. Send the Emulator's registration token through the normal Firebase Admin SDK, FCM HTTP v1 endpoint, or managed provider. Use a development or staging Firebase project when you need to keep test registrations and messages separate from production.

    Autosana's Android Emulator image includes Google APIs and Google Play services. If your app enforces Play Integrity or Firebase App Check, configure the provider's supported test or debug path for the Autosana build.
  </Tab>
</Tabs>

See [Building Your Mobile App for Our Cloud](/app-build-guide) for artifact and architecture requirements.

## Create the flow

### Trigger the notification from the app

Use the normal application workflow whenever an in-app action schedules the notification. For example:

```text theme={null}
Log in as ${env:PUSH_TEST_EMAIL}.
Accept notification permission if the app asks for it.
Enable the order-ready reminder for the test order.
Verify that the app confirms the reminder is scheduled.
Press Home so the app is in the background.
Wait up to 30 seconds for an “Order ready” notification.
Verify that the notification appears.
Tap the notification.
Verify that the app opens the test order.
```

The scheduling action and delay belong to your application. Autosana only needs instructions that describe when to press Home, how long to wait, what notification to expect, and what should happen after it is tapped.

### Trigger the notification with a runtime hook

Use a runtime hook when the application has no convenient in-app trigger. The hook should call a narrow test endpoint that tells your backend to send a named notification to the dedicated test user.

1. Add these values to the app's Autosana environment:
   * `PUSH_TEST_URL`
   * `PUSH_TEST_API_KEY` as a secret
   * `PUSH_TEST_USER_ID`

2. Create a cURL hook named `Trigger Test Push`:

```bash theme={null}
curl --fail-with-body -X POST "${env:PUSH_TEST_URL}" \
  -H "Authorization: Bearer ${env:PUSH_TEST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"${env:PUSH_TEST_USER_ID}","template":"order-ready"}'
```

3. Reference the hook at the correct point in the flow:

```text theme={null}
Log in as the push-notification test user.
Accept notification permission if the app asks for it.
Wait until the app confirms that notifications are enabled for this account.
Press Home so the app is in the background.
Run ${hooks:Trigger Test Push}.
Wait up to 30 seconds for an “Order ready” notification.
Verify that the notification appears.
Tap the notification.
Verify that the app opens the test order.
```

Runtime hooks run synchronously, so the agent waits for the endpoint response before continuing. A successful endpoint response confirms only that your backend accepted the request; the notification appearing on the virtual device is the end-to-end assertion.

<Tip>
  Have the test endpoint return a distinct error when the test user has no
  current push registration. This makes registration failures easier to
  distinguish from provider delivery failures.
</Tip>

## Test the important app states

Create separate flows when your application handles notifications differently in each state:

* **Background:** press Home before sending, then verify and tap the notification.
* **Foreground:** keep the app open and verify the app's foreground presentation or in-app handling.
* **Cold start:** terminate or fully close the app through your normal test workflow, send the notification, and verify the deep-linked destination after tapping it.
* **Notification service extension:** verify any modified title, body, attachment, or category produced by the extension.

Background or silent data delivery is controlled by the operating system and is not guaranteed to run immediately. Use bounded waits, avoid sending notifications repeatedly in a tight loop, and retain physical-device coverage for business-critical background processing.

## Testing notifications on real devices

For device selection, run behavior, and availability, see [Real Device Testing](/real-device-testing). For supported artifacts and standard physical-device build instructions, see [Real device builds](/app-build-guide#real-device-builds-ipa).

Physical push-notification testing uses private devices so the app's original signing and notification entitlements can be preserved. It requires an enterprise contract; [contact us](mailto:founders@autosana.ai) for availability and onboarding.

## Troubleshooting

| Problem                                             | What to check                                                                                                                                                                                                                           |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The permission prompt does not appear               | The app may already have permission in the current session, or Android permission may have been granted during setup. Confirm the OS notification setting and run from a clean device state when testing first-run permission behavior. |
| The backend reports no target                       | Confirm the app logged in as the expected user and finished updating its push registration during this run before the trigger.                                                                                                          |
| APNs returns `BadDeviceToken`                       | Send to the sandbox endpoint, use the current token, and check the bundle ID/topic and `aps-environment=development` entitlement.                                                                                                       |
| FCM returns `UNREGISTERED`                          | The app was reinstalled or its data was cleared. Launch the app and upload the new token before sending again.                                                                                                                          |
| Android receives a message but displays nothing     | Check notification permission, the channel ID and channel settings, and whether the payload is a notification message or a data message.                                                                                                |
| The iOS Simulator never registers                   | Check the Push Notifications capability, development entitlement, APNs credentials, and that the build targets iOS 16 or later.                                                                                                         |
| The hook succeeds but no notification appears       | Inspect the APNs or FCM response and confirm that the provider accepted the current token. The hook response and device delivery are separate stages.                                                                                   |
| A silent or background notification is inconsistent | The OS can delay or suppress background work. Reduce test frequency and use a private physical device for critical coverage.                                                                                                            |

## Provider references

* [Apple: Xcode 14 Simulator remote-notification support](https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes)
* [Apple: Registering an app with APNs](https://developer.apple.com/documentation/usernotifications/registering-your-app-with-apns)
* [Firebase: Set up FCM for Android](https://firebase.google.com/docs/cloud-messaging/android/get-started)
* [Firebase Apple SDK release notes](https://firebase.google.com/support/release-notes/ios)
