Notification Payload est une structure JSON que le serveur envoie via APNS à un appareil iOS, définissant le contenu d’une notification push et le comportement lors de sa réception. Le payload comprend des clés obligatoires et optionnelles qui contrôlent le texte, le son, le badge, les pièces jointes multimédias et le traitement en arrière-plan. Selon Apple Developer Documentation, 2026, la taille maximale du payload est de 4096 octets pour les notifications ordinaires et de 5120 octets pour les notifications VoIP, imposant des limites strictes sur la quantité de données transférées.
Points Clés
Notification Payload est un objet JSON que le serveur envoie à APNS (Apple Push Notification Service) pour livraison à un appareil iOS. Le payload contient toutes les données nécessaires au système pour afficher la notification : titre, texte, son, badge et métadonnées pour le traitement en arrière-plan. La structure du payload est strictement réglementée par Apple et comprend des clés obligatoires pour un traitement correct par le système.
Lorsque le serveur envoie une notification push via l’API HTTP/2 d’APNS, la requête contient des en-têtes d’autorisation et un corps JSON — le payload. APNS valide le payload : si le JSON est incorrect ou dépasse la limite de taille, le serveur Apple renvoie une erreur 400 Bad Request. Après validation, APNS livre le payload à l’appareil, où iOS l’analyse et détermine comment traiter la notification — afficher une bannière, exécuter une tâche en arrière-plan ou jouer un son.
Le format du payload APNS a évolué d’un simple payload textuel dans iOS 2 à une structure JSON multi-composants dans les versions modernes. iOS 10 a introduit la prise en charge des pièces jointes multimédias via mutable-content, iOS 12 a ajouté le regroupement des notifications via thread-id, et iOS 15 a introduit supports-live-activities pour les Live Activities. Aujourd’hui, un payload peut contenir jusqu’à 15 clés différentes selon le comportement souhaité de la notification.
L’objet racine du payload contient un dictionnaire aps et des champs personnalisés facultatifs au niveau supérieur. Le dictionnaire aps est le seul élément obligatoire, mais à l’intérieur de celui-ci, diverses combinaisons de clés peuvent apparaître selon le type de notification : alert, badge, sound, content-available, mutable-content, interruption-level, entre autres.
| Clé aps | Type | Fonction |
|---|---|---|
| alert | String ou Dictionary | Texte de la notification ou objet avec title, subtitle, body et localisation |
| badge | Number | Numéro sur l’icône de l’application ; 0 supprime le badge |
| sound | String | Nom du fichier sonore ou default pour le son système |
| content-available | Number (1) | Indicateur d’activation en arrière-plan ; 1 = push silencieux |
| mutable-content | Number (1) | Indicateur d’activation de l’extension de service pour modifier le contenu |
| category | String | Identifiant de catégorie pour les boutons et l’extension de contenu |
| thread-id | String | Identifiant de groupe pour le regroupement des notifications |
| interruption-level | String | Niveau d’interruption : passive, active, time-sensitive, critical |
| relevance-score | Number (0–1) | Priorité de la notification pour le système de classement intelligent |
La clé alert peut être une simple chaîne (qui devient le corps de la notification) ou un dictionnaire avec les champs title, subtitle et body. Le format dictionnaire permet de définir le titre et le sous-titre séparément du texte principal. Pour les notifications localisées, les clés title-loc-key, title-loc-args, loc-key et loc-args sont utilisées, référençant le Localizable.strings de l’application. Cela permet d’envoyer un payload sans texte dans une langue spécifique — l’application substitue la traduction.
À partir d’iOS 15, Apple a introduit le mécanisme Focus Mode, qui oblige le développeur à spécifier le niveau d’interruption de la notification. interruption-level accepte les valeurs : passive (pas de son, pas d’écran allumé), active (comportement standard), time-sensitive (traverse le mode Focus, nécessite une autorisation spéciale) et critical (situations médicales/urgentes). La clé relevance-score (0–1) aide le système Focus à classer les notifications au sein d’une même catégorie.
La clé thread-id regroupe les notifications dans le centre de notifications. Toutes les notifications ayant le même thread-id sont affichées comme un seul groupe que l’utilisateur peut déplier. Ceci est particulièrement utile pour les messageries, où les messages d’un même contact sont regroupés, ou pour les applications qui envoient de nombreuses notifications du même type.
Les champs personnalisés sont toutes les clés en dehors du dictionnaire aps que le développeur ajoute pour transmettre des données supplémentaires à l’appareil. Le serveur les inclut dans l’objet JSON racine du payload, et l’application les récupère via userInfo dans UNNotificationContent. Les champs personnalisés ne doivent pas dupliquer les noms de clés de aps pour éviter les conflits lors de l’analyse.
La limitation principale est que la taille totale du payload ne doit pas dépasser 4096 octets. Les champs personnalisés sont en concurrence avec les clés obligatoires de aps pour cette limite, il est donc important de minimiser la taille des données transmises. Utilisez des noms de clés courts (par exemple, « uid » au lieu de « user-id »), évitez les grandes structures JSON et transmettez uniquement des identifiants plutôt que des objets de données complets.
Les champs personnalisés proviennent du serveur et ne doivent pas être fiabilisés sans vérification. Validez toujours les types et les valeurs des champs personnalisés lors de l’analyse : vérifiez l’existence de la clé via une liaison optionnelle, convertissez avec as ? String/Int/Dictionary vers le type attendu et traitez le cas d’absence de valeur. N’utilisez jamais force unwrap (!) pour les données du payload — le serveur pourrait envoyer des données invalides et l’application planterait.
{
"aps": {
"alert": {
"title": "Nouveau message",
"body": "Bonjour ! Comment allez-vous ?"
},
"badge": 5,
"sound": "default",
"category": "message",
"thread-id": "chat_4521",
"mutable-content": 1
},
"sender-id": "user_789",
"chat-id": "chat_4521",
"message-type": "text",
"image-url": "https://cdn.example.com/img.jpg"
}
Utilisez un style de nommage cohérent pour les champs personnalisés dans tous les payloads du projet. kebab-case (message-type) ou camelCase (messageType) — les deux approches sont acceptables, mais la cohérence au sein du projet est importante. Évitez les noms longs : « uid » au lieu de « user-identifier », « img » au lieu de « profile-image-url ». Chaque caractère dans un nom de clé consomme un octet de la limite de 4096.
Différents scénarios de notifications push nécessitent différentes combinaisons de clés dans le payload. Examinons plusieurs exemples typiques : une notification texte simple, une notification localisée, un Silent Push et une notification enrichie avec pièce jointe multimédia.
Un payload de base avec texte et son — la configuration minimale pour afficher une notification à l’utilisateur. Alert comme chaîne fournit un message court, sound default joue le son système standard. Badge est facultatif et définit le compteur sur l’icône de l’application. category et thread-id sont ajoutés pour le regroupement et l’interactivité.
{
"aps": {
"alert": "Rappel : réunion dans 15 minutes",
"badge": 3,
"sound": "default"
}
}
Pour envoyer des notifications à des appareils de langues différentes, utilisez des clés de localisation au lieu d’un texte codé en dur. title-loc-key référence une clé dans le Localizable.strings de l’application, et title-loc-args fournit les arguments. Cela permet d’envoyer un seul payload à tous les appareils, et l’application affiche le texte dans la langue appropriée.
{
"aps": {
"alert": {
"title-loc-key": "NEW_MESSAGE_TITLE",
"title-loc-args": ["Anna"],
"loc-key": "NEW_MESSAGE_BODY",
"loc-args": ["Bonjour !"]
},
"sound": "message.caf"
}
}
Pour une synchronisation en arrière-plan sans afficher de notification, utilisez content-available : 1 sans alert. Les champs personnalisés spécifient le type d’opération et les données à traiter. Le système active l’application en arrière-plan, appelle didReceiveRemoteNotification avec fetchCompletionHandler, et l’application effectue la synchronisation.
{
"aps": {
"content-available": 1
},
"sync-type": "invalidate-cache",
"timestamp": "2026-07-03T12:00:00Z"
}
Pour afficher une pièce jointe multimédia, mutable-content : 1 est nécessaire pour activer l’extension de service, ainsi qu’une URL d’image dans un champ personnalisé. mutable-content : 1 signale au système de lancer UNNotificationServiceExtension, qui télécharge l’image à partir de l’URL et l’ajoute comme UNNotificationAttachment. La clé category spécifie une catégorie enregistrée pour afficher des boutons d’action.
{
"aps": {
"alert": {
"title": "Nouveau produit",
"body": "Découvrez la nouvelle collection"
},
"category": "product",
"mutable-content": 1
},
"media-url": "https://cdn.example.com/product.jpg"
}
UNNotificationContent.userInfo contient le dictionnaire complet du payload reçu après le traitement par le système. L’application accède au payload dans le délégué UNUserNotificationCenter lors de la réception d’une notification (au premier plan), lors d’un tap sur une notification, ainsi que dans l’extension de service et l’extension de contenu. Une analyse correcte est essentielle pour extraire les données personnalisées et déterminer les actions suivantes.
Lorsque l’utilisateur tape sur une notification, le système appelle la méthode didReceive response dans UNUserNotificationCenterDelegate. response.notification.request.content.userInfo contient le payload complet. Le développeur extrait les champs personnalisés, détermine le type d’action (par exemple, ouvrir un chat, naviguer vers un produit) et déclenche la navigation correspondante dans l’application.
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
let userInfo = response.notification
.request.content.userInfo
guard let chatId = userInfo["chat-id"] as? String
else {
completionHandler()
return
}
let messageType = userInfo["message-type"]
as? String ?? "text"
NavigationRouter.shared.navigate(
to: .chat(chatId: chatId,
messageType: messageType))
completionHandler()
}
L’extension de service reçoit le payload avant que la notification ne soit affichée et peut le modifier. La validation du payload est la première étape dans didReceive : vérifiez les champs personnalisés obligatoires, validez l’URL de la pièce jointe et vérifiez les types de données. Si le payload est invalide, appelez immédiatement le gestionnaire d’achèvement avec le contenu original pour éviter de perdre du temps dans un traitement inutile.
Pour déboguer les notifications push en production, utilisez une journalisation structurée des payloads. OSLog permet de journaliser le payload avec la catégorie « notifications » au niveau debug. Côté serveur, surveillez les réponses APNS : une réponse réussie contient apns-id pour faire correspondre le payload envoyé, tandis qu’une erreur 400 indique un JSON malformé ou un dépassement de taille.
Foire Aux Questions
La taille maximale du payload est de 4096 octets pour les notifications push ordinaires et de 5120 octets pour les notifications VoIP (PushKit). Le dépassement de cette limite entraîne une erreur 400 Bad Request de la part d’APNS. La taille est comptée en octets, pas en caractères — tenez compte de l’encodage UTF-8.
Utilisez les clés loc-key, title-loc-key, loc-args et title-loc-args à l’intérieur de alert. L’application substitue la traduction depuis son Localizable.strings en fonction de la langue de l’appareil. Cela permet d’envoyer un seul payload à tous les appareils, indépendamment de leur langue.
content-available active l’application en arrière-plan pour le traitement des données (push silencieux) sans afficher de notification. mutable-content active l’extension de service pour modifier le contenu avant l’affichage. Les deux clés peuvent être utilisées ensemble pour le traitement en arrière-plan et la modification ultérieure de la notification.
Utilisez APNS Sandbox pour les tests et vérifiez la réponse HTTP du serveur Apple : 200 OK signifie une livraison réussie. Pour la validation de la structure, utilisez des schémas JSON dans votre pipeline CI/CD. Dans Xcode, envoyez des notifications de test via le simulateur avec xcrun simctl push.
apns-id est un identifiant unique de notification push dans le système APNS, renvoyé dans la réponse lors d’une livraison réussie. Il est utilisé pour suivre la livraison via l’API Logs et pour le débogage. Le serveur doit stocker apns-id pour chaque notification envoyée.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi