APNS (Apple Push Notification Service) is Apple's infrastructure service for delivering push notifications to ecosystem devices: iPhone, iPad, Mac, Apple Watch, and Apple TV. The service ensures reliable message delivery through a persistent TLS connection between the device and Apple servers. According to Apple Developer Documentation, APNS uses the HTTP/2 protocol for bidirectional communication with application servers.
Key Takeaways
Apple Push Notification Service (APNS) is Apple's proprietary service for routing push notifications from the application server to user devices. Unlike FCM, APNS does not support Android or other platforms — it is entirely tied to the Apple ecosystem.
The service operates through a persistent TLS connection that each Apple device establishes with APNS servers at startup. This connection is maintained in the background and used to deliver notifications with minimal latency.
APNS handles all delivery infrastructure: encryption, authentication, prioritization, and retransmission when the device is unavailable. The developer only needs to provide a properly formatted payload and a valid push token.
Originally, APNS worked through a binary protocol on ports 2195–2196. Since 2015, Apple has transitioned the service to the modern HTTP/2 protocol, which supports multiplexing, header compression, and server push notifications. HTTP/2 became mandatory in June 2020.
The push notification delivery process through APNS consists of five stages: device registration, obtaining a push token, sending a request from the server, APNS routing, and delivery to the device.
If the device is unavailable (powered off or no network), APNS stores the most recent message for each app and delivers it when the connection is restored. The maximum storage duration is 4 weeks, after which the message is deleted.
Apple supports two methods for authenticating the application server when sending push notifications. Each method has its own characteristics regarding validity period, management, and ease of use.
| Parameter | Token-based (p8) | Certificate-based (.p12) |
|---|---|---|
| Validity | Indefinite (key does not expire) | Limited to certificate validity (usually 1 year) |
| Rotation | Not required unless the key is compromised | Mandatory annual replacement |
| Multi-app | One key for all apps in the account | Separate certificate for each app |
| Environment | One key for Sandbox and Production | Different certificates for Sandbox and Production |
Token-based authentication is the Apple-recommended method since 2019. You create a single p8 key in Apple Developer Console, upload it to your server, and sign each APNS request with it. The key never expires and works for all apps in your account.
For new projects, Token-based authentication is clearly preferable: one p8 key for the entire account, indefinite, with no environment binding. Certificate-based (.p12) is still used in legacy projects but requires annual replacement and separate certificates for Sandbox and Production. Consider certificate expiration when planning CI/CD.
APNS supports three types of push notifications, which differ in their behavior on the device and request attribute requirements. The choice of type depends on the UX scenario and message urgency.
For Background notifications, you must specify the content-available: 1 key and set priority to 5 (power-efficient delivery). The system may limit the number of background notifications if the app does not process them in a timely manner.
APNS supports two priority values: 10 (immediate delivery) and 5 (power-efficient). For alert notifications, use 10 — the user should receive them right away. For background notifications, use 5 — the system may delay delivery to save battery. Incorrect priority for background notifications may lead to APNS rejection.
APNS accepts payload in JSON format with a maximum size of 4 KB for regular notifications and 5 KB for VOIP. The payload contains the mandatory aps dictionary with display settings and optional custom fields.
{
"aps": {
"alert": {
"title": "New message",
"body": "You have 3 unread chats"
},
"badge": 3,
"sound": "default",
"category": "message_category",
"thread-id": "chat_room_42"
},
"customData": {
"chatId": "42"
}
}
The thread-id key groups notifications in the iOS Notification Center. The category key links the notification to a UNNotificationCategory for displaying action buttons. Without these keys, all notifications appear individually.
In addition to the mandatory aps dictionary, the APNS payload can contain any custom fields at the top level. These fields are accessible to the app through the userInfo dictionary when processing the notification. Custom data is convenient for passing entity identifiers, screens, or links. The maximum payload size is 4 KB, so avoid transferring large amounts of data via push; load them via API after opening the notification.
To send a push notification from the server, you need to execute a POST request to the APNS endpoint with proper authentication headers. Below is an example in Node.js using Token-based authentication.
const http2 = require("http2")
const fs = require("fs")
const jwt = require("jsonwebtoken")
const token = jwt.sign(
{ iss: "TEAM_ID", iat: Math.floor(Date.now() / 1000) },
fs.readFileSync("AuthKey.p8"),
{ algorithm: "ES256", keyid: "KEY_ID" }
)
const payload = JSON.stringify({
aps: { alert: { title: "Hello!", body: "Test push" } }
})
const client = http2.connect(
"https://api.push.apple.com"
)
const req = client.request({
":method": "POST",
":path": "/3/device/DEVICE_PUSH_TOKEN",
"authorization": "bearer " + token,
"apns-push-type": "alert",
"apns-topic": "com.example.app",
"apns-priority": "10"
})
req.end(payload)
req.on("response", (headers) => {
if (headers[":status"] === 200) {
console.log("Push sent successfully")
}
})
After sending, APNS returns HTTP status 200 on successful delivery or an error code with description in the response body. It is important to handle token-unregistered errors (410) — such tokens should be removed from the server, as the app has been deleted from the device.
APNS returns HTTP status codes for each send request. Successful delivery returns status 200. Errors require different handling strategies. BadDeviceToken (400) or Unregistered (410) — the device token is outdated and should be removed from the server. PayloadTooLarge (413) — the 4 KB limit has been exceeded, reduce the payload.
TooManyRequests (429) — request limit exceeded. APNS sets a quota on the number of sends per second. When receiving 429, implement exponential backoff and retry the send. It is recommended not to exceed 100 requests per second per HTTP/2 connection.
APNS-side errors — 500 and 503 (Internal Server Error / Service Unavailable). These are temporary Apple infrastructure failures. In such cases, retry with a 1–5 second delay, no more than 3 attempts. Persistent 5xx errors with a fully operational server are rare and usually related to TLS connection issues.
For Production environments, be sure to implement logging of all APNS errors with the token, error code, and time. This will help quickly identify problems with certificates, quotas, or specific device tokens. Regularly check certificate expiration dates if using Certificate-based authentication.
Frequently Asked Questions
APNS works through TCP 443 (HTTPS) for the HTTP/2 API. Previously, ports 2195 and 2196 were used for the binary protocol. Since June 2020, Apple requires the exclusive use of HTTP/2 on port 443. Make sure your server has access to api.push.apple.com.
Sandbox is the APNS testing environment for debugging push notifications. Production is the live environment for real users. With Token-based authentication, one key works for both environments — the endpoint differs: api.sandbox.push.apple.com or api.push.apple.com.
The push token can change when: restoring the app from backup, reinstalling the app, updating the OS, resetting network settings. The token does not change during regular app updates through the App Store. The server should handle the BadDeviceToken (400) error as a signal to remove the token.
4 KB (4096 bytes) for regular alert/background notifications. For VOIP notifications via PushKit — 5 KB (5120 bytes). Exceeding the size returns a PayloadTooLarge error (413). It is recommended to keep the payload minimal and load additional data via the server.
APNS cannot deliver a notification to a device without an internet connection. If the device is offline, APNS stores the most recent message (per app per device) for up to 28 days. When the connection is restored, the message is delivered immediately. Older messages are not preserved.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also