MainSDK
Search⌘K
Integrations

Apple Push Notification service

Use Apple Push Notification service (APNs) for MainSDK push on iOS - signing key, bundle ID, environments, main.yaml, testing and swapping.

1 interface1 driverWritten guide
Updated 2026-10-28

Apple Push Notification service (APNs) is the only way to deliver push notifications to iPhone and iPad apps. In a MainSDK app it is a push driver for notify: when push is the channel a person is reached on and they use an Apple device, APNs delivers it. Pick the APNs driver when you send push directly, usually next to FCM for Android; with Expo, Expo talks to APNs for you.

Interfaces it serves

Pick Apple Push Notification service in main.yaml for any of these. Your calls stay the same, and you can swap later.

Before you start

  1. Join the Apple Developer Program with the team that owns your app.
  2. Enable push notifications for your app's identifier (bundle ID).
  3. Create an APNs authentication key. Token-based authentication uses one signing key for all your apps. Note the key ID and your team ID; the key file can be downloaded only once.
  4. Know the two environments. APNs has a development (sandbox) environment for builds from Xcode and a production environment for TestFlight and App Store builds. A device token works only in the environment it was issued for.

Store the signing key in your secrets manager, never in code or the app bundle.

Configure

main.yaml
notify:
  channels: [push, whatsapp, sms, email]
  push: { drivers: [fcm, apns] }   # or via: expo

How the APNs driver takes its key, key ID, team ID, bundle ID and environment is not in the spec yet; the key will be a secret: reference such as secret:APNS_AUTH_KEY (suggested name). A literal key fails validation with MAIN-CONFIG-0004.

Use it

app/notifications/setup.ts
import { notify } from "mainsdk/notify";

await notify.push.register();   // asks permission on iOS, stores the token

await notify(user, { template: "order.shipped", category: "transactional" });

Local development and testing

  • Test real pushes on a device with a development build, against the APNs sandbox.
  • createTestApp() from @mainsdk/testing runs notify on its in-memory fake, and chaos.on("notify", { outage: true }) simulates an outage.
  • Until a push driver is configured, the push channel is skipped.

What MainSDK adds on top

  • Push only with the person's opt-in; opt-outs and quiet hours respected.
  • No personal data in push payloads, which also keeps lock-screen previews free of it.
  • A retry with the same idempotency key never sends twice.

See Notifications.

Limits and notes

  • The APNs driver comes with the expo-adapter spec (phase 3, milestone 1.1).
  • iOS asks the person for permission once; if they decline, push is skipped and notify tries the next channel.
  • Where device tokens are stored is not in the spec yet.

Swap to or from it

main.yaml
notify:
  push: { drivers: [fcm, apns], via: expo }   # was { drivers: [fcm, apns] }

FAQ

Why do pushes work from Xcode but not from TestFlight? TestFlight and App Store builds use the production APNs environment, and tokens from a development build don't work there.

Do I need APNs if I use Expo? You still need an APNs key, but you give it to Expo and set via: expo.

Next

Open questions

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet