Device Token is a unique identifier that APNS assigns to each iOS device for routing push notifications. The token is generated by the system when the app registers to receive notifications and must be sent to the server to send push notifications specifically to this device. According to Apple Developer Documentation, 2026, the Device Token may change when reinstalling the app, restoring a device from backup, or updating iOS, so the server must regularly update tokens to ensure delivery.
Key Takeaways
Device Token (device token) is a unique identifier in the form of a hex string that APNS (Apple Push Notification Service) generates for each app on an iOS device. The token is the key by which the server sends push notifications to a specific device. Without a valid Device Token, the server cannot deliver push notifications — APNS rejects the request with a 400 BadRequest error.
The Device Token is created by the iOS system when the app first contacts APNS after installation. The generation process involves cryptographic binding to the app's bundle ID and the device's unique identifier (UID), after which APNS returns a 32-byte token in hex format (64 characters) to the app. The token is not permanent — the system may generate a new one under certain conditions.
When the server sends a push notification, it includes the Device Token in the HTTP/2 request to APNS. APNS validates the token: if the token belongs to a different environment (sandbox instead of production), has expired, or has been revoked, the Apple server returns a 410 Gone or 400 BadRequest error. Only after successful token validation does APNS begin delivering the notification to the device.
Device Token should not be confused with IDFA (Identifier for Advertisers), IDFV (Identifier for Vendor), or UID (Unique Device Identifier). IDFA and IDFV are used for advertising and analytics, UID is a hardware serial number. The Device Token exists exclusively for push notifications and does not reveal information about the user or device outside of APNS.
| Identifier | Purpose | Persistence |
|---|---|---|
| Device Token | APNS push notification routing | May change |
| IDFA | Advertising and tracking | Can be reset by the user |
| IDFV | Vendor identification (analytics) | Persistent for apps from the same developer |
| Bundle ID | Unique app identifier | Persistent |
The process of obtaining a Device Token consists of several mandatory steps, starting from requesting user permission and ending with sending the token to the server. Each step is critical — skipping any of them results in the inability to send push notifications to the device.
The first step is for the app to request user permission to send notifications via UNUserNotificationCenter.current().requestAuthorization. The user can agree, deny, or select optional options (alert, badge, sound). Without explicit user consent, the system will not issue a Device Token, even if the app calls registerForRemoteNotifications. After obtaining permission, the app calls UIApplication.shared.registerForRemoteNotifications(), which initiates the registration process with APNS.
After registration, APNS returns the token through the AppDelegate: application(_:didRegisterForRemoteNotificationsWithDeviceToken:). A successful call contains a Data object with the token, which must be converted to a hex string for transmission to the server. In case of an error, the system calls application(_:didFailToRegisterForRemoteNotificationsWithError:) with a description of the problem: incorrect certificate configuration, network unavailability, or incorrect project configuration.
After receiving the token, the app should immediately send it to its server for storage in the database. The API request includes the token, device identifier (for mapping), environment (sandbox/production), and optionally additional data: OS version, device model, language. It is recommended to resend the token on every app launch so that the server always has an up-to-date token.
// Request permission and register with APNS
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
guard granted else {
print("Permission not granted")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
// Obtain Device Token from APNS
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenString = deviceToken
.map { String(format: "%02.2hhx", $0) }
.joined()
print("Device Token: \(tokenString)")
// Send token to server
PushTokenService.shared
.sendTokenToServer(tokenString) { success in
if success {
UserDefaults.standard.set(tokenString,
forKey: "lastDeviceToken")
}
}
}
The server side of the push system must store the Device Token in the database, associated with the user and environment. When sending a notification, the server forms a request to APNS, including the token in the URL and a JWT token (or certificate) for authorization. Proper token management critically affects the push notification delivery rate.
The token table on the server should contain at least: Device Token (unique), user ID, environment (sandbox/production), last update date, and status (active/inactive). It is recommended to add an index on the token for fast lookup when sending and on the user to retrieve the list of all devices for a user. Many apps allow one user to have multiple devices — each with its own token.
To send a push notification, the server must authorize the request to APNS in two ways. Certificate-based uses an SSL certificate generated in the Apple Developer Console. Token-based uses a JWT (JSON Web Token) with a .p8 key that is valid for up to 30 days without needing to renew the certificate. Token-based authorization is considered more modern and is recommended by Apple for new projects.
The request to APNS includes the HTTP/2 POST method, URL with the path /3/device/{device_token}, authorization headers, and a JSON body with the payload. The apns-topic header must contain the app's bundle ID. apns-priority indicates delivery priority (5 — immediately, 10 — power-efficient). apns-expiration sets the time in seconds since epoch until which APNS will attempt to deliver the notification.
// Example of sending push on Node.js via APNS HTTP/2
const http2 = require('http2');
const client = http2.connect('https://api.push.apple.com');
const deviceToken = 'abcdef0123456789...';
const payload = JSON.stringify({
"aps": { "alert": "Hello!", "sound": "default" }
});
const req = client.request({
':method': 'POST',
':path': `/3/device/${deviceToken}`,
'apns-topic': 'com.example.app',
'apns-priority': '10',
'apns-expiration': '0',
'authorization': `bearer ${jwtToken}`
});
req.write(payload);
req.end();
req.on('response', (headers) => {
if (headers[':status'] === '200') {
console.log('Push sent successfully');
}
});
When sending push notifications to a large number of devices, use batch sending with rate control. APNS recommends not exceeding 1500 requests per second per connection. If the limit is exceeded, the Apple server returns a 429 Too Many Requests error. For large-scale campaigns, use multiple connections and distribute the load evenly across devices.
Device Token is not permanent and may change in several scenarios, requiring an update mechanism on the server. If the server continues to send push notifications to an outdated token, APNS returns a 410 Gone error, indicating that the token is no longer valid for the given environment.
Apple documents several scenarios in which the Device Token changes: the user reinstalls the app, restores the device from an iCloud backup, installs a new iOS version, or resets network or privacy settings. In each case, the app will receive a new token from APNS on its next launch. The server must update the token in the database, removing the old one and saving the new one.
When the server sends a push to an outdated token, APNS returns HTTP 410 with the apns-unless-timestamp header. This header indicates the time after which the token became invalid. The server must immediately delete or deactivate this token in the database to avoid sending to it again. Ignoring the 410 error wastes resources and reduces the deliverability rate.
To keep the token database up to date, it is recommended to run periodic cleanup. The cleanup script analyzes APNS logs from the last N days, finds all tokens that received a 410 error, and deactivates them in the database. Additionally, tokens with no user activity for more than 90 days can be removed — these are useless records that only increase the database size.
Before mass sending of push notifications (newsletters, promo campaigns), it is recommended to pre-validate the tokens. APNS does not provide a direct API for batch token validation, so the strategy is to send a test push with low priority and analyze errors. Tokens that return a 410 error are excluded from the main send.
Let us walk through the full cycle of obtaining a Device Token in Swift, including error handling and sending to the server. The code covers requesting permission, registering with APNS, converting Data to a hex string, handling errors, and sending the token to your own server with retry attempts on failure.
import UIKit
import UserNotifications
final class PushNotificationManager: NSObject {
static let shared = PushNotificationManager()
private let apiClient = APIClient()
private var currentToken: String?
func register() {
UNUserNotificationCenter.current()
.requestAuthorization(
options: [.alert, .badge, .sound]) {
[weak self] granted, error in
guard granted else {
Analytics.log(
"Push permission denied")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
func handleDeviceToken(_ tokenData: Data) {
let token = tokenData
.map { String(format: "%02.2hhx", $0) }
.joined()
guard token != currentToken else { return }
currentToken = token
sendTokenToServer(token)
}
func handleRegistrationError(_ error: Error) {
Analytics.log(
"Push registration failed: \(error)")
// Retry after delay on network errors
if let urlError = error as? URLError,
urlError.code == .notConnectedToInternet {
DispatchQueue.main.asyncAfter(
deadline: .now() + 10) { [weak self] in
self?.register()
}
}
}
private func sendTokenToServer(_ token: String) {
let body = PushTokenRequest(
token: token,
environment: Environment.current == .debug
? "sandbox" : "production",
osVersion: UIDevice.current.systemVersion,
locale: Locale.current.identifier
)
apiClient.sendToken(body) { [weak self] result in
if case .success = result {
self?.currentToken = token
}
}
}
}
Errors during APNS registration can be caused by various reasons. The most common include network unavailability, incorrect certificate configuration in Xcode (e.g., the Push Notifications capability is disabled), using a simulator (which does not support push), or an incorrect provisioning profile. In production, it is important to log errors and, if possible, retry registration on the next app launch.
iOS Simulator does not support receiving a real Device Token. For testing registration on the simulator, use i386 architecture checks: in a debug build, you can simulate token retrieval or use UI tests with mock objects. Real push notification testing is always done on a physical device connected to Xcode.
Frequently Asked Questions
Yes, the Device Token can change when reinstalling the app, restoring the device from backup, or updating iOS. The server must handle token updates: when a new token is received from a known device, replace the old one; when a 410 error occurs, remove the token from the database.
A Device Token is a 32-byte hex string of 64 characters in lowercase (0–9, a–f). Example: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2". The token is passed as Data from APNS and converted to a string on the app side.
A sandbox token is issued for apps built with a development provisioning profile and works only with api.sandbox.push.apple.com. A production token is for App Store and TestFlight and works with api.push.apple.com. The server must distinguish between environments and send push notifications to the appropriate APNS endpoint.
A 410 Gone error means the Device Token is invalid. The server must immediately remove this token from the database and stop attempting to send to it. The apns-unless-timestamp header in the response indicates when the token stopped working.
Check the delegate method application(_:didRegisterForRemoteNotificationsWithDeviceToken:) in AppDelegate. If the method is called, the token has been received. Use debugging logs or OSLog to output the token to the Xcode console. On a physical device, verify that the token is being sent to the server using Network Link Conditioner.
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