Ce que vous saurez faire à la fin
- Configurer Firebase Cloud Messaging (FCM) pour envoyer des notifications push gratuites à des utilisateurs Android, iOS et web depuis un dashboard ou une API.
- Mettre en place OneSignal en alternative ou complément, avec segmentation, A/B testing et campagnes automatisées.
- Gérer les permissions notifications iOS et Android avec un onboarding qui maximise l’opt-in (taux supérieur à 65%).
- Implémenter les notifications transactionnelles (commande livrée, paiement reçu) et marketing (promos, abandons panier) sans spammer.
- Mesurer le taux d’ouverture, de clic et de conversion par campagne, et respecter le RGPD et la loi sénégalaise sur la protection des données.
Durée : 5h. Pré-requis : app Android et/ou iOS publiée ou en cours de dev (React Native, Flutter, Swift, Kotlin), compte Firebase gratuit, optionnel compte Apple Developer pour iOS (99 USD/an), Node.js 20 si backend custom, budget 0 à 25 000 FCFA pour démarrer.
Étape 1 — Pourquoi les push notifications restent essentielles
Pour une PME sénégalaise, les push notifications sont le canal de marketing direct le moins cher et le plus efficace : 0 FCFA d’envoi, 90% de réception (vs 18% en email), 7% à 10% de clic moyen. Une boutique de Pikine qui envoie 1 push « Nouveau lot Boubous arrivé » génère typiquement 30 commandes en 4 heures, contre 2 commandes via une promo Facebook payante à 15 000 FCFA.
FCM (Firebase Cloud Messaging) est le service Google gratuit illimité qui domine le marché : 90% des notifications Android transitent par lui. OneSignal est l’alternative tout-en-un avec UI intuitive pour marketers non développeurs. La plupart des PME utilisent les 2 selon le besoin.
Étape 2 — Créer le projet Firebase et activer FCM
# Aller sur https://console.firebase.google.com
# Créer un nouveau projet "ma-pme-app"
# Désactiver Google Analytics si non nécessaire (plus simple)
# Dans le projet créé :
# 1. Project Settings > Cloud Messaging
# 2. Vérifier que "Cloud Messaging API (V1)" est activée
# 3. L'ancienne API "Cloud Messaging API (Legacy)" est dépréciée depuis juin 2024
# Récupérer le Server Key pour appels API :
# Project Settings > Cloud Messaging > Cloud Messaging API (V1)
# Cliquer "Manage Service Accounts in Google Cloud"
# Créer une clé JSON pour service account et la télécharger
# Le fichier service-account.json contient les credentials
# JAMAIS commiter ce fichier dans Git !
echo "service-account.json" >> .gitignore
L’API FCM v1 utilise OAuth2 avec service account, plus sécurisée que l’ancienne avec Server Key statique. Toutes les nouvelles intégrations en 2026 doivent utiliser v1.
Étape 3 — Configurer FCM côté Android (React Native)
# Installer le SDK officiel React Native Firebase :
npm install @react-native-firebase/app @react-native-firebase/messaging
# Pour iOS :
cd ios && pod install && cd ..
# Configuration Android :
# 1. Sur Firebase Console > Add app > Android
# Package name : com.mapmeapp (identique à AndroidManifest.xml)
# 2. Télécharger google-services.json
# 3. Placer dans android/app/google-services.json
# Modifier android/build.gradle (level projet) :
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
# Modifier android/app/build.gradle (level app) :
apply plugin: 'com.google.gms.google-services'
# Pour Android 13+, ajouter dans AndroidManifest.xml :
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
# Définir une icône notif custom dans AndroidManifest.xml :
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/notification_color" />
Sans icône custom, Android affiche un carré blanc opaque depuis Android 5. L’icône doit être en blanc transparent (alpha) avec format vectoriel ou PNG 96×96 dans drawable-xxxhdpi.
Étape 4 — Demander la permission utilisateur
// services/notifications.ts (React Native)
import messaging from '@react-native-firebase/messaging';
import { Platform, PermissionsAndroid } from 'react-native';
export async function requestNotificationPermission(): Promise<boolean> {
// Android 13+ exige une permission runtime explicite
if (Platform.OS === 'android' && Platform.Version >= 33) {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
{
title: 'Activer les notifications ?',
message: 'Recevez vos confirmations de commande et nos promos exclusives.',
buttonPositive: 'Activer',
buttonNegative: 'Plus tard',
}
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
}
// iOS : APIs natives via firebase/messaging
const authStatus = await messaging().requestPermission({
alert: true,
badge: true,
sound: true,
provisional: false,
});
return authStatus === messaging.AuthorizationStatus.AUTHORIZED
|| authStatus === messaging.AuthorizationStatus.PROVISIONAL;
}
// Récupérer le token FCM (à stocker en base) :
export async function getFCMToken(): Promise<string | null> {
try {
const token = await messaging().getToken();
console.log('FCM Token:', token);
return token;
} catch (e) {
console.error('Erreur token FCM', e);
return null;
}
}
Demander la permission au premier lancement = 30% d’opt-in. Demander après une action positive (signup réussi, première commande) = 65% à 75% d’opt-in. La psychologie compte plus que la technique.
Étape 5 — Recevoir les notifications dans l’app
// App.tsx ou index.js
import messaging from '@react-native-firebase/messaging';
import { useEffect } from 'react';
// Handler en background (app fermée ou minimisée)
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Message reçu en background', remoteMessage);
});
export default function App() {
useEffect(() => {
// Foreground : app ouverte
const unsubscribe = messaging().onMessage(async (remoteMessage) => {
console.log('Foreground notif', remoteMessage);
// Afficher une notif locale ou une bannière in-app
Alert.alert(
remoteMessage.notification?.title ?? 'Notification',
remoteMessage.notification?.body ?? ''
);
});
// Notification cliquée (app était en background)
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log('Notification ouverte (background)', remoteMessage);
// Navigation vers l'écran concerné
if (remoteMessage.data?.screen === 'order') {
navigation.navigate('OrderScreen', { id: remoteMessage.data.orderId });
}
});
// Notification cliquée alors que l'app était totalement fermée
messaging().getInitialNotification().then((remoteMessage) => {
if (remoteMessage) {
console.log('App ouverte par notif (cold start)', remoteMessage);
}
});
return unsubscribe;
}, []);
return <RootNavigator />;
}
3 états à gérer obligatoirement : foreground (app ouverte), background (app minimisée), cold start (app fermée). Les utilisateurs jugent la qualité de votre app sur la fluidité du deep linking depuis une notif.
Étape 6 — Envoyer une notification depuis Node.js
// backend/sendNotification.js
const admin = require('firebase-admin');
const serviceAccount = require('./service-account.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
async function sendToDevice(token, title, body, data = {}) {
const message = {
token: token,
notification: { title, body },
data: data, // payload custom (max 4 Ko)
android: {
notification: {
channelId: 'orders',
priority: 'high',
sound: 'default',
color: '#FF6B00',
},
},
apns: {
payload: {
aps: {
sound: 'default',
badge: 1,
'mutable-content': 1,
},
},
},
};
try {
const response = await admin.messaging().send(message);
console.log('Envoyé', response);
return { success: true, messageId: response };
} catch (error) {
console.error('Erreur envoi', error);
if (error.code === 'messaging/registration-token-not-registered') {
// Token invalidé : supprimer de la base
}
return { success: false, error: error.message };
}
}
// Envoyer à plusieurs devices (batch jusqu'à 500) :
async function sendMulticast(tokens, title, body) {
const message = { tokens, notification: { title, body } };
const response = await admin.messaging().sendEachForMulticast(message);
return {
success: response.successCount,
failed: response.failureCount,
};
}
// Envoyer à un topic (tous les utilisateurs abonnés) :
async function sendToTopic(topic, title, body) {
return admin.messaging().send({
topic: topic,
notification: { title, body },
});
}
Les topics permettent d’envoyer à des segments sans gérer les tokens individuellement. Exemple : abonner tous les clients de Saint-Louis au topic « promo_saint_louis », puis envoyer à ce topic. Limite : 2 000 abonnements simultanés par device.
Étape 7 — Configurer FCM côté iOS (APNs)
# iOS exige Apple Push Notification service (APNs) en plus de FCM
# Coût : Apple Developer Account 99 USD/an
# Étapes :
# 1. Aller sur https://developer.apple.com/account
# 2. Certificates, Identifiers & Profiles > Keys
# 3. Cliquer "+" > APNs (cocher Apple Push Notifications service)
# 4. Télécharger le fichier .p8 (JAMAIS le perdre, on ne peut pas le re-télécharger)
# 5. Noter le Key ID (10 caractères) et Team ID (10 caractères)
# Sur Firebase Console :
# Project Settings > Cloud Messaging > Apple app configuration
# Uploader le .p8, saisir Key ID et Team ID
# Dans Xcode :
# 1. Sélectionner votre app > Signing & Capabilities
# 2. + Capability > Push Notifications
# 3. + Capability > Background Modes > cocher "Remote notifications"
# AppDelegate.m ou AppDelegate.swift :
# Activer le bridge Firebase pour les notifications
Sur iOS, l’app DOIT être en mode Production (TestFlight ou App Store) pour recevoir les push réels. Les push en mode Debug (depuis Xcode local) sont envoyés via le sandbox APNs et n’arrivent pas via la prod.
Étape 8 — OneSignal en 15 minutes (alternative no-code)
# Créer un compte sur https://onesignal.com (gratuit jusqu'à 10k abonnés)
# Sur le dashboard :
# 1. New App or Website
# 2. Choisir Mobile App + plateforme (Android/iOS)
# 3. Pour Android : uploader google-services.json
# 4. Pour iOS : uploader le .p8 + Key ID + Team ID
# Récupérer 2 valeurs :
# - One Signal App ID
# - REST API Key
# Installer le SDK React Native OneSignal :
npm install react-native-onesignal
# Pour iOS :
cd ios && pod install && cd ..
# Initialisation dans App.tsx :
import OneSignal from 'react-native-onesignal';
OneSignal.initialize('VOTRE_APP_ID');
// Demander permission iOS :
OneSignal.Notifications.requestPermission(true);
// Récupérer player ID (équivalent du token FCM) :
const playerId = await OneSignal.User.getOnesignalId();
console.log('OneSignal Player ID:', playerId);
// Envoyer un tag pour segmentation :
OneSignal.User.addTag('city', 'dakar');
OneSignal.User.addTag('plan', 'premium');
OneSignal facture 9 USD/mois au-delà de 10 000 abonnés. Pour une PME, c’est rentable car le marketer peut envoyer des campagnes sans dev. Le ROI mensuel d’une push bien faite dépasse largement les 9 USD.
Étape 9 — Envoyer une campagne depuis OneSignal
Workflow dashboard OneSignal :
1. Messages > Push Notifications > New Push
2. Audience :
- All Users (tous)
- Segments (créés via tags : "city = dakar AND plan = premium")
- Subscriptions (sélection manuelle)
3. Message :
- Title : "Promo Tabaski : -20%"
- Subtitle : "Sur tous les boubous"
- Message : "Code TABASKI20 valable 48h. Livraison gratuite."
- Image : URL d'une image 512x256
- Launch URL : https://ma-boutique.sn/tabaski
4. Options avancées :
- Send To : Subscribed Users
- Schedule : Now ou planifié
- Delivery : Immediate ou par fuseau horaire local
- Time To Live : 24 heures
- Frequency Capping : max 3 push/jour/utilisateur
5. Confirm and Send
API REST équivalente :
POST https://onesignal.com/api/v1/notifications
Headers: Authorization: Basic VOTRE_API_KEY
Body JSON :
{
"app_id": "VOTRE_APP_ID",
"include_player_ids": ["abc-123-..."],
"headings": {"fr": "Promo Tabaski"},
"contents": {"fr": "-20% sur tous les boubous"},
"data": {"campaign": "tabaski_2026"}
}
L’envoi par fuseau horaire local (Delayed Delivery) augmente le taux d’ouverture de 25%. Une notif arrive à 10h heure locale du destinataire au lieu de tomber à 3h du matin pour les expatriés.
Étape 10 — Notifications transactionnelles vs marketing
Catégorie 1 : Transactionnelles (toujours opt-in implicite)
- Confirmation de commande
- Paiement reçu (Wave, Orange Money)
- Commande expédiée / livrée
- Code OTP
- Mot de passe modifié
Caractéristiques :
- Envoi immédiat
- Sans frequency capping
- Action claire (deep link vers le détail)
- Taux ouverture > 80%
- Légalement autorisées même sans opt-in marketing
Catégorie 2 : Marketing (opt-in explicite obligatoire)
- Promotions
- Nouveaux produits
- Réductions limitées
- Newsletter mensuelle
- Réactivation utilisateurs inactifs
Caractéristiques :
- Maximum 3 par semaine recommandé
- Toujours avec lien désabonnement
- Segmenté par préférences
- Personnalisé (prénom, historique d'achat)
- Soumis à RGPD et loi 2008-12 (Sénégal)
Code Cloud Function pour transactionnel automatique :
exports.notifyOrderShipped = functions.firestore
.document('orders/{orderId}')
.onUpdate(async (change, context) => {
const before = change.before.data();
const after = change.after.data();
if (before.status !== 'shipped' && after.status === 'shipped') {
const userToken = await getUserToken(after.userId);
await sendToDevice(userToken,
'Commande expédiée',
`Votre commande ${context.params.orderId} arrive demain.`);
}
});
Mélanger transactionnel et marketing dans le même canal de notif tue les taux d’ouverture. Toujours utiliser des Notification Channels Android distincts (« orders », « promos », « system ») pour que l’utilisateur puisse couper l’un sans l’autre.
Étape 11 — Notification riche : image et boutons d’action
// Envoyer une push avec image et 2 actions (Node.js)
const message = {
token: deviceToken,
notification: {
title: 'Nouveau modèle Boubou Wax',
body: 'Disponible en 5 tailles, livraison Dakar gratuite',
imageUrl: 'https://ma-boutique.sn/boubou-2026.jpg',
},
android: {
notification: {
imageUrl: 'https://ma-boutique.sn/boubou-2026.jpg',
clickAction: 'FLUTTER_NOTIFICATION_CLICK',
},
},
apns: {
payload: {
aps: {
'mutable-content': 1,
category: 'PRODUCT_VIEW',
},
},
fcmOptions: {
imageUrl: 'https://ma-boutique.sn/boubou-2026.jpg',
},
},
data: {
type: 'product',
productId: '12345',
actions: JSON.stringify([
{ id: 'view', title: 'Voir le produit' },
{ id: 'cart', title: 'Ajouter au panier' },
]),
},
};
await admin.messaging().send(message);
// iOS : créer une Notification Service Extension dans Xcode
// pour télécharger et afficher l'image
// Android : géré nativement par FCM si imageUrl est dans android.notification
Une push avec image augmente le taux de clic de 56% en moyenne (étude Airship 2024). L’image doit faire moins de 1 Mo et un ratio 2:1 pour s’afficher correctement sur Android et iOS.
Étape 12 — Tracking ouverture, clic, conversion
// Au moment où la notification est cliquée, logger un event :
import analytics from '@react-native-firebase/analytics';
messaging().onNotificationOpenedApp(async (remoteMessage) => {
await analytics().logEvent('notification_opened', {
campaign_id: remoteMessage.data?.campaign_id,
notification_type: remoteMessage.data?.type,
sent_at: remoteMessage.data?.sent_at,
});
// Naviguer vers la cible
navigation.navigate(remoteMessage.data?.screen, remoteMessage.data?.params);
});
// Si l'utilisateur achète après avoir cliqué, attribuer la conversion :
await analytics().logEvent('purchase', {
campaign_attribution: 'tabaski_2026',
value: 25000,
currency: 'XOF', // FCFA
});
// Dans Firebase Analytics, créer un funnel :
// notification_opened > product_viewed > add_to_cart > purchase
// KPIs à suivre par campagne :
// - Delivery rate : envoyées / reçues (vise > 85%)
// - Open rate : ouvertes / reçues (vise > 8% Android, > 4% iOS)
// - Click rate : cliquées / ouvertes (vise > 60%)
// - Conversion rate : achats / cliquées (vise > 3%)
// - Unsubscribe rate (vise < 0,5%)
OneSignal et Braze fournissent ces analytics out-of-the-box. Avec FCM seul, vous devez tout instrumenter via Firebase Analytics ou un outil tiers comme Mixpanel.
Étape 13 — Respect RGPD et loi sénégalaise 2008-12
Obligations légales pour push marketing au Sénégal et UE :
1. Consentement explicite et préalable (opt-in actif)
- Pas de cases pré-cochées
- Permission séparée pour transactionnel vs marketing
- Texte clair sur les types de notif envoyés
2. Possibilité de retirer le consentement à tout moment
- Bouton "Désactiver les notifications" dans les paramètres
- Lien dans chaque notification pour gérer les préférences
- Désinscription en 1 clic, pas de "êtes-vous sûr ?"
3. Conservation limitée des données
- Tokens FCM/OneSignal supprimés après 6 mois d'inactivité
- Pas de stockage de l'historique des notifs au-delà de 12 mois
- Anonymisation des analytics au-delà de 26 mois
4. Information transparente (CGU + politique de confidentialité)
- Quels types de notif vont être envoyés
- À quelle fréquence
- Sur quelles bases (préférences, historique d'achat)
- Avec quels tiers (Firebase = Google = transfert UE-USA)
5. Registre des traitements (article 33 RGPD)
- Documenter le traitement "Notifications push"
- Finalité, données collectées, durée de conservation
- Mesures de sécurité (chiffrement, accès restreint)
Sanction CDP Sénégal : jusqu'à 100 000 000 FCFA (lourde)
Sanction CNIL France : jusqu'à 4% du CA mondial
Une PME qui spam ses clients avec 5 push/jour de promo finit blacklistée par les utilisateurs (désinstall) et risque une plainte CDP qui peut coûter cher. La modération est aussi un acte de marketing intelligent.
Étape 14 — Architecture complète pour PME
Stack recommandée pour 0 à 50 000 utilisateurs :
Backend :
- Firebase Cloud Functions (Node.js)
- Firestore pour stocker tokens + préférences notif
- Cloud Tasks pour envois différés et planifiés
Apps mobile :
- React Native + react-native-firebase
- OU Flutter + firebase_messaging
- OU OneSignal SDK (plus simple, marketer-friendly)
Web :
- Service Worker + Push API + VAPID keys
- Firebase Cloud Messaging Web SDK
Dashboard interne (admin) :
- Page "Envoyer notification" avec :
* Sélection segment (tous, ville, statut commande)
* Édition titre + corps + image + deep link
* Aperçu Android et iOS
* Bouton "Envoyer maintenant" ou "Planifier"
* Historique des envois et stats
Coûts mensuels typiques (PME 5 000 abonnés) :
- FCM : 0 FCFA (illimité)
- OneSignal : 0 FCFA (gratuit jusqu'à 10k)
- Cloud Functions : ~3 000 FCFA si 50k push/mois
- Firestore : ~2 000 FCFA pour stockage tokens
Total mensuel : moins de 10 000 FCFA pour atteindre 5 000 personnes
ROI typique d'une campagne : x10 à x40 sur le coût
L’erreur classique : sur-investir dans une stack sophistiquée (Braze, Iterable, Klaviyo) qui coûte 200 USD/mois quand FCM gratuit + un dashboard custom de 2 jours suffit. Commencer simple, complexifier seulement si croissance le justifie.
Erreurs classiques à éviter
- Ignorer Android 13+ POST_NOTIFICATIONS : votre app ne reçoit aucune notif sur les téléphones récents si la permission n’est pas demandée explicitement.
- Push à 3h du matin : l’envoi global UTC réveille tout le monde et fait désinstaller l’app. Toujours utiliser delayed delivery par fuseau horaire local.
- Token FCM stocké sans refresh : les tokens expirent, changent au reset téléphone. Réécouter onTokenRefresh et mettre à jour la base à chaque app launch.
- Notifications identiques pour tous : 0% de personnalisation = 1% d’opt-in après 1 mois. Segmenter au minimum par ville et par historique d’achat.
- Tester en simulateur iOS : le simulateur n’a JAMAIS reçu de push iOS. Toujours tester sur iPhone physique avec build TestFlight.
- Promo sur transactionnel : mélanger une promo dans la notif « Commande livrée » tue la confiance. Garder les canaux séparés et purs.
Checklist push notifications PME
✓ Projet Firebase créé avec FCM activé en API v1
✓ google-services.json (Android) et GoogleService-Info.plist (iOS) intégrés
✓ APNs Key .p8 uploadée sur Firebase pour iOS
✓ Permission POST_NOTIFICATIONS Android 13+ demandée
✓ Permission iOS demandée après onboarding (pas au cold start)
✓ Tokens FCM stockés en base avec refresh automatique
✓ Handler foreground, background et cold start implémentés
✓ Deep linking testé sur les 3 états d'app
✓ Notification Channels Android distincts (orders, promos)
✓ Image et boutons d'action testés sur Android et iOS
✓ Backend Node.js ou Cloud Functions pour envoi
✓ Dashboard admin pour campagnes marketing
✓ Tracking ouverture, clic, conversion en place (Firebase Analytics)
✓ Conformité RGPD et loi sénégalaise 2008-12 documentée
✓ Frequency capping configuré (max 3 push/semaine en marketing)