Probabilmente sei arrivato al punto in cui l'app funziona, gli utenti hanno effettuato l'accesso e il product team ora vuole flussi di re-engagement che sembrino nativi. Promemoria del carrello. Prompt per le recensioni. Alert per nuovi messaggi. Annunci di rilascio. L'istinto iniziale è spesso quello di "collegare le push e via", ma una settimana dopo ti ritrovi a fare debugging sul perché un dispositivo riceve gli alert, il simulatore sembra registrare correttamente e nessuno sa spiegare perché i tap non aprono la schermata giusta.
È qui che le notifiche push di Expo risultano o piacevolmente semplici o sorprendentemente fragili.
Expo offre ai team React Native uno strato pratico sopra APNs e FCM, ed è proprio per questo che così tanti team lo usano. Ma il divario tra una demo e un'implementazione pronta per la produzione è reale. Il ciclo di vita dei token, il timing dei permessi, il setup dei listener, il design del payload e la pulizia del backend sono tutti fondamentali. Se rilasci anche frequenti modifiche alla logica dell'app, la necessità di disciplina operativa diventa ancora più critica, specialmente se il tuo lavoro di retention dipende da messaggistica affidabile e velocità di rilascio. La consegna è utile solo se l'esperienza utente che la circonda è prevedibile.
Indice dei contenuti
- Le basi per coinvolgere gli utenti con le notifiche push di Expo
- Setup iniziale e configurazione del progetto
- Richiesta dei permessi e cattura dei Push Token
- Inviare notifiche dal tuo server
- Gestire le notifiche in arrivo nella tua app
- Best practice per la produzione ed errori comuni
Le basi per coinvolgere gli utenti con Expo Push Notifications
Un Notifiche push di Expo il setup è molto attraente per un motivo principale. Elimina gran parte della complessità nativa della messaggistica che i team non vogliono gestire fin dal primo giorno. Invece di costruire subito l'infrastruttura APNs e FCM, puoi usare il gateway di Expo e concentrarti sul comportamento del prodotto, sul routing, sulla UX dei permessi e sulla logica dei messaggi backend.
Questa astrazione non rende le notifiche push "meno reali". Cambia solo dove viene investito il tuo sforzo ingegneristico.
Il servizio è anche così veloce che le performance di solito non sono la prima preoccupazione. Dal 14 marzo 2023 al 12 giugno 2023, il API delle notifiche push di Expo ha mostrato un tempo di risposta mediano di 42 millisecondi, una latenza p99 di 273 millisecondi, e un tasso di errore giornaliero medio dello 0,17% su decine di milioni di messaggi giornalieri, according to l'analisi benchmark di Knock sul API di Expo. Questo dovrebbe rassicurare i team che temono che Expo sia adatto solo ai prototipi.
Cosa nasconde realmente Expo
Quando i team parlano di “Expo push”, spesso intendono diversi concetti distinti raggruppati insieme:
- Routing del provider: Expo inoltra i messaggi a APNs per iOS e FCM per Android.
- Formato del token: Il tuo server salva e invia un Expo Push Token invece di gestire direttamente i token specifici della piattaforma.
- Contratto della richiesta: Inviate un payload tramite POST all'API di Expo, invece di integrare direttamente le API dei provider nativi.
È un approccio utile, ma crea anche un malinteso comune. Spesso i team pensano che ogni problema di consegna dipenda da Expo. In realtà, molti fallimenti derivano da code dell'app, token scaduti, payload malformati o una gestione errata dei permessi.
Regola pratica: Considerate Expo come un reliable transport layer, non come un sostituto di un buon design client e backend.
Cosa significa davvero essere pronti per la produzione
Una demo funzionante dimostra solo che un dispositivo ha ricevuto un payload una volta. La prontezza per la produzione significa altro:
| Preoccupazione | Mentalità da demo | Mentalità da produzione |
|---|---|---|
| Permessi | Chiedi subito | Chiedi all'IA, dopo aver compreso il valore per l'utente |
| Token | Save once | Refresh, deduplicazione, scadenza e riconciliazione |
| Payload | Inserisci tutto qui data |
Mantieni i payload piccoli e orientati all'azione |
| Comportamento dell'app | Mostra un alert | Naviga correttamente e gestisci lo stato in foreground |
| Operazioni | Test manuali | Receipt, cleanup, logs e gestione incidenti |
Questa è la differenza tra "inviare notifiche" e "gestire le notifiche in un vero workflow di prodotto".
Configurazione e setup iniziale del progetto
Molti problemi con le notifiche Expo iniziano prima del primo prompt di autorizzazione. Se la configurazione del progetto è approssimativa, il client code può sembrare corretto, ma l'app potrebbe comportarsi in modo inconsistente tra i vari build.

Inizia con le librerie giuste installate e un ambiente di sviluppo coerente con il tuo percorso di build. Se lavori oltre Expo Go, ti conviene allineare il tuo workflow di rilascio con la guida di Capgo sull'alternativa a Expo EAS, poiché il comportamento delle notifiche va spesso validato in un build che rispecchi la produzione più fedelmente rispetto a un rapido test in sandbox.
Installa i pacchetti per le notifiche
Al minimo, di solito avrai bisogno di:
expo-notificationsper richieste di permessi, recupero token, listener e visualizzazione delle notifiche.expo-deviceperché dovresti proteggere il recupero del token conDevice.isDevice.
I comandi di installazione tipici dipendono dal tuo package manager, ma la chiave è l'allineamento delle versioni con il tuo SDK di Expo. Non mischiare versioni arbitrarie dei pacchetti. Lascia che sia Expo a risolvere quelle compatibili.
Aggiungi la configurazione a livello di progetto
Mantieni la config esplicita. Un setup app.json o app.config.js deve riflettere che le notifiche sono parte del contratto della tua app, non un'aggiunta postuma.
{
"expo": {
"name": "MyApp",
"slug": "my-app",
"plugins": ["expo-notifications"],
"ios": {
"bundleIdentifier": "com.example.myapp"
},
"android": {
"package": "com.example.myapp"
},
"extra": {
"eas": {
"projectId": "your-project-id"
}
}
}
}
Alcuni dettagli sono fondamentali:
- Bundle identifier e package name devono corrispondere all'app che pubblichi effettivamente.
- Il plugin delle notifiche assicura che il progetto nativo riceva il setup necessario durante il build.
- L'EAS project ID è importante quando il recupero del token richiede che l'app sia associata al corretto progetto Expo.
Imposta un notification handler subito
Molti tutorial base aspettano troppo per definire il comportamento delle notifiche. Non farlo. Configurale all'avvio dell'app per rendere prevedibile il comportamento in foreground.
import * as Notifications from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: true,
}),
});
I team decidono se le notifiche in foreground debbano mostrare un alert, riprodurre un suono o aggiornare i badge. Il comportamento esatto dipende dal prodotto: un'app di chat e una di pagamenti non faranno le stesse scelte.
Se non definisci intenzionalmente il comportamento in foreground, il team finirà per debuggare notifiche "mancanti" che in realtà sono state ricevute, ma mai mostrate come previsto dal prodotto.
Android richiede la configurazione dei canali
Nella pratica, i canali di notifica Android non sono opzionali. Se li salti, i tuoi alert potrebbero apparire incoerenti o non rispettare le aspettative dell'utente.
import { Platform } from 'react-native';
import * as Notifications from 'expo-notifications';
export async function configureAndroidNotifications() {
if (Platform.OS !== 'android') return;
await Notifications.setNotificationChannelAsync('default', {
name: 'Default',
importance: Notifications.AndroidImportance.MAX,
});
}
Configura tutto durante l'inizializzazione dell'app. Mantieni gli ID dei canali stabili: cambiarli senza un motivo preciso renderà il comportamento delle notifiche difficile da gestire in seguito.
Richiesta dei permessi e cattura dei Push Token
Questa è la parte che molti team copiano da uno snippet, per poi pentirsene in seguito.
Le richieste di permesso richiedono tempismo, consapevolezza della piattaforma e una gestione asincrona disciplinata. La cattura del token deve avvenire solo su un dispositivo fisico, solo dopo la risoluzione dei permessi e solo se sei pronto a salvare il risultato sul tuo backend immediatamente.

La funzione client che dovrebbe essere il tuo baseline
Usa una funzione come questa come punto di partenza:
import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
import { Platform } from 'react-native';
type RegisterResult =
| { ok: true; token: string }
| { ok: false; reason: string };
export async function registerForExpoPushNotificationsAsync(): Promise<RegisterResult> {
if (!Device.isDevice) {
return { ok: false, reason: 'Push notifications require a physical device.' };
}
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('default', {
name: 'Default',
importance: Notifications.AndroidImportance.MAX,
});
}
const permissions = await Notifications.getPermissionsAsync();
let finalStatus = permissions.status;
if (finalStatus !== 'granted') {
const request = await Notifications.requestPermissionsAsync();
finalStatus = request.status;
}
if (finalStatus !== 'granted') {
return { ok: false, reason: 'Notification permission was not granted.' };
}
const projectId =
Constants.expoConfig?.extra?.eas?.projectId ??
Constants.easConfig?.projectId;
if (!projectId) {
return { ok: false, reason: 'Missing EAS project ID configuration.' };
}
const tokenResponse = await Notifications.getExpoPushTokenAsync({ projectId });
return { ok: true, token: tokenResponse.data };
}
L'ordine è fondamentale. Prima controlli il tipo di dispositivo, imposti il comportamento del canale Android, risolvi i permessi, validi la configurazione del progetto e infine richiedi il token Expo.
Perché Device.isDevice non è opzionale
Questo è uno dei pochi errori che genera un sacco di rumore pur sembrando innocuo. I team esperti richiedono i permessi condizionalmente solo quando Device.isDevice è vero, ed un errore comune è saltare questo controllo, portando gli sviluppatori a inviare notifiche a token di simulatori non validi e a incolpare Expo, quando il problema è la configurazione dell'app, come descritto in Note di Eagerworks sull'implementazione delle notifiche Expo.
Ecco perché il controllo si trova all'inizio della funzione. Non nasconderlo dietro un helper. Rendilo esplicito.
I risultati del simulatore sono utili per i test della UI. Non sono affidabili per validare la registrazione del push token.
Chiedi il permesso al momento giusto
Non chiederli nella splash screen. Non chiederli prima che l'utente ne capisca il valore. Il momento migliore è solitamente dopo un'azione dell'utente che renda concreti i vantaggi delle notifiche, come attivare gli aggiornamenti sulla consegna, unirsi a una conversazione o salvare un elemento.
Una buona implementazione segue solitamente questo flusso:
- L'utente raggiunge un punto chiave della funzionalità.
- L'app spiega il valore delle notifiche nella propria UI.
- L'app richiede il permesso di sistema.
- Se il permesso è concesso, l'app salva subito il token sul backend.
È proprio in questo passaggio finale che molte app falliscono. Recuperano il token, lo loggano localmente e rimandano la registrazione al backend. In seguito, il supporto non saprà quale dispositivo avesse quale token in un dato momento.
Ecco un semplice esempio di come salvare il token dopo la registrazione:
export async function enablePushForCurrentUser(userId: string) {
const result = await registerForExpoPushNotificationsAsync();
if (!result.ok) {
return result;
}
await fetch('https://api.example.com/push-tokens', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer user-session-token',
},
body: JSON.stringify({
userId,
token: result.token,
platform: Platform.OS,
}),
});
return result;
}
Più avanti nel workflow, questa guida è un utile riferimento visivo:
Per i team che gestiscono app con rilasci frequenti, è utile considerare la registrazione del token come parte dello stato operativo dell'app, non solo dell'onboarding. Questo approccio si sposa bene con i più ampi workflow di distribuzione delle app Expo, dove il comportamento dell'app può cambiare spesso e lo stato del backend deve restare sincronizzato.
Inviare notifiche dal proprio server
Una volta che il backend ha un Expo Push Token valido, inviare una notifica è semplicissimo. La parte difficile non è la richiesta in sé, ma decidere cosa includere nel payload e quanta fiducia riporre nello stato del client.
Ecco un esempio minimale in stile Node usando fetch:
type ExpoPushMessage = {
to: string;
title: string;
body: string;
sound?: 'default' | null;
data?: Record<string, unknown>;
};
export async function sendExpoPushNotification(token: string) {
const message: ExpoPushMessage = {
to: token,
title: 'New review received',
body: 'Tap to open the order details.',
sound: 'default',
data: {
type: 'new_review',
orderId: 'ord_123',
screen: 'OrderDetails',
},
};
const response = await fetch('https://exp.host/--/api/v2/push/send', {
method: 'POST',
headers: {
Accept: 'application/json',
'Accept-encoding': 'gzip, deflate',
'Content-Type': 'application/json',
},
body: JSON.stringify(message),
});
const result = await response.json();
return result;
}
Cosa deve fare ogni campo del payload
Non usare il payload come un cestino. Ogni campo deve avere uno scopo preciso.
| Campo | Scopo | Consigli pratici |
|---|---|---|
to |
Punta all'Expo Push Token | Verifica che appartenga al record del dispositivo corrente |
title |
Titolo della notifica | Mantienilo breve e leggibile |
body |
Testo principale visibile | Rendi l'azione chiara |
sound |
Comportamento dei suoni di sistema | Usali con moderazione per avvisi critici |
data |
Metadati specifici dell'app | Preferisci ID e hint di routing al contenuto ricco |
L'oggetto data l'oggetto è il punto in cui i workflow di prodotto diventano utili. Puoi passare un tipo e un ID record, lasciando che l'app recuperi i dati più recenti quando l'utente clicca. È più sicuro che inserire blob grandi o sensibili direttamente nel payload.
Mantieni i payload piccoli e semplici
According to la guida di Courier sulle notifiche Expo, gli Expo Push Tokens dovrebbero essere trattati come effimeri; i payload che superano i limiti di circa 4 KB possono essere scartati. Un pattern affidabile è inviare piccoli payload di metadati come { "type": "new_review", "id": 123 } invece di grandi JSON o media inline. È un approccio che funziona nei sistemi reali: i payload piccoli falliscono meno spesso e sono più resilienti ai cambiamenti della logica dell'app.
Invia dati sufficienti per indirizzare l'utente. Recupera il resto dopo l'apertura dell'app.
Buone pratiche lato server
Una funzione di invio base va bene per i test. In produzione, solitamente si aggiungono altre responsabilità:
- Persisti i tentativi di invio: Salva l'intento della notifica con user ID, token, tipo di payload e timestamp.
- Separa la generazione dei contenuti dal trasporto: Costruisci il testo del messaggio in uno strato e la richiesta Expo API in un altro.
- Gestisci il feedback di invalidazione: Se Expo segnala in seguito
DeviceNotRegistered, segna quel token come scaduto e smetti di riprovare alla cieca. - Usa un design ottimizzato per i webhook: Se il tuo sistema emette già eventi, instrada i trigger delle notifiche attraverso lo stesso tipo di pattern di elaborazione dei webhook backend che utilizzi altrove.
Prima di fare il debug dei listener lato client, invia prima un test push manuale. Se un token riceve una notifica semplice con un payload minimo, il percorso di trasporto è probabilmente funzionante. In caso contrario, non iniziare modificando la navigazione code. Inizia validando il token, la struttura del payload e lo stato dei permessi.
Gestire le notifiche in entrata nella tua app
La consegna è solo metà della funzionalità. L'app deve fare qualcosa di coerente quando arriva la notifica e quando l'utente la tocca.
Ciò significa gestire due momenti distinti:
- la notifica arriva mentre l'app è aperta
- l'utente interagisce con la notifica dal tray di sistema o dalla schermata di blocco

La ricezione in foreground e la risposta dell'utente sono eventi diversi
Un setup affidabile include solitamente entrambi i listener:
import { useEffect } from 'react';
import * as Notifications from 'expo-notifications';
export function useNotificationObservers(
onForegroundMessage: (notification: Notifications.Notification) => void,
onNotificationTap: (response: Notifications.NotificationResponse) => void
) {
useEffect(() => {
const receivedSub = Notifications.addNotificationReceivedListener(
(notification) => {
onForegroundMessage(notification);
}
);
const responseSub = Notifications.addNotificationResponseReceivedListener(
(response) => {
onNotificationTap(response);
}
);
return () => {
receivedSub.remove();
responseSub.remove();
};
}, [onForegroundMessage, onNotificationTap]);
}
addNotificationReceivedListener viene eseguito quando l'app è attiva. addNotificationResponseReceivedListener viene eseguito quando l'utente tocca una notifica ricevuta. Non confonderli: servono a percorsi UX differenti.
Leggi il payload dei dati e naviga in modo mirato
Ecco un pattern pratico per gestire il tap:
type NotificationData = {
type?: string;
orderId?: string;
screen?: string;
};
export function handleNotificationTap(
response: Notifications.NotificationResponse,
navigation: any
) {
const data =
response.notification.request.content.data as NotificationData;
if (data.screen === 'OrderDetails' && data.orderId) {
navigation.navigate('OrderDetails', { orderId: data.orderId });
return;
}
if (data.type === 'new_review') {
navigation.navigate('Inbox');
return;
}
navigation.navigate('Home');
}
Questo pattern è resiliente perché il payload contiene suggerimenti di routing, non interi documenti. Se l'ordine è cambiato dall'invio della notifica, l'app può recuperare lo stato attuale dal server dopo la navigazione.
Una notifica cliccata deve portare a una destinazione ovvia. Se il percorso di fallback è vago, l'utente se ne accorgerà subito.
Foreground behavior should match user context
Quando l'app è già aperta, mostrare un alert di sistema può risultare goffo. A volte la scelta migliore è un banner in-app, l'aggiornamento di un badge o un refresh silenzioso. Una schermata della inbox potrebbe non aver bisogno di un alert visibile se l'utente sta già leggendo quella conversazione.
Ecco perché il tuo listener in foreground dovrebbe biforcarsi per rotta e tipo di notifica. Ad esempio:
- Schermata chat aperta: aggiungi il messaggio ed evita un banner ridondante
- Dashboard aperta: mostra un toast in-app leggero
- Evento critico dell'account: usa un elemento UI più marcato
Un approccio semplice è questo:
export function handleForegroundNotification(
notification: Notifications.Notification,
currentRouteName: string
) {
const data = notification.request.content.data as { type?: string };
if (currentRouteName === 'ChatThread' && data.type === 'new_message') {
// refresh local thread state
return;
}
// otherwise show your own in-app UI or update badges
}
Se l'app non distingue questi contesti, gli utenti subiranno più velocemente la notification fatigue, anche se la consegna è tecnicamente corretta.
Best Practice in produzione ed errori comuni
La maggior parte delle configurazioni Expo push notification fallisce non perché Expo sia limitato, ma perché i team assumono che il token sia permanente, che i payload possano contenere qualsiasi cosa e che gli update dell'app non influiscano sulla logica delle notifiche.
Questa assunzione non regge in produzione.

I token sono effimeri, non record di identità
Un Expo Push Token va trattato come un contratto a termine, non come un identificativo del dispositivo a vita. I token possono cambiare dopo una reinstallazione, aggiornamenti dell'OS o altri eventi del ciclo di vita. Se un token ritorna DeviceNotRegistered, il tuo backend dovrebbe smettere di considerarlo attivo.
Un modello backend pratico memorizza:
- ID utente
- piattaforma
- metadati relativi all'installazione
- token corrente
- timestamp dell'ultimo accesso
- stato (es. attivo, scaduto o revocato)
Non limitarti a salvare un campo token nella tabella user. Gli utenti hanno più dispositivi e i dispositivi cambiano stato.
La strategia di refresh conta più di quanto dicano i tutorial
La guida ufficiale dell'ecosistema lascia un vuoto operativo. Spesso i contenuti sulle notifiche push di Expo non spiegano come mantenere la validità del token durante Cicli di revisione App Store e aggiornamenti OTA, aspetto fondamentale per i team che rilasciano modifiche live, poiché l'affidabilità delle notifiche dipende dallo stato del token e dalla sincronizzazione backend, come indicato in Documentazione notifiche Expo.
Questo influisce sul design dei trigger di refresh. I momenti ideali per riconciliare lo stato del token includono:
- Avvio dell'app dopo un aggiornamento
- Accesso dell'utente
- Modifica delle impostazioni dei permessi
- Rotazione delle credenziali nel processo di release
- Flussi di recovery dopo ticket di supporto sulle push
Security e compliance non vanno lasciate alla fine dello sprint
Molti tutorial su Expo si concentrano sulla meccanica e trascurano il rischio operativo. Va bene per app hobbistiche, ma non per prodotti fintech, sanitari o di commercio regolamentato.
L'analisi di Courier sui limiti delle notifiche Expo per le aziende evidenzia la mancanza di linee guida pratiche su consent logging, audit trail e minimizzazione dell'esposizione di payload sensibili. Il takeaway tecnico è semplice:
- Non inserire dati aziendali sensibili nel testo della notifica o nei metadati del payload.
- Logga i cambiamenti di consenso lato server.
- Registra quale intento di notifica è stato inviato a quale token.
- Usa gli ID nei payload e recupera i contenuti protetti dopo l'apertura dell'app.
Per i team che allineano le operazioni di rilascio con compliance degli app store e le pratiche di sicurezza API, le push dovrebbero rientrare nello stesso processo di revisione di auth, analytics e logging degli eventi backend.
Le push notification sono messaggi rivolti all'utente, ma sono anche un problema di sistemi distribuiti. Gestiscile con la stessa cura che riservi allo stato di auth e agli eventi di pagamento.
Cosa funziona e cosa solitamente si rompe
| Solitamente funziona | Solitamente si rompe |
|---|---|
| Richiedere il permesso dopo aver spiegato chiaramente il valore | Mostrare il prompt al primo frame |
| Test su dispositivi reali | Affidarsi alla registrazione dei simulatori |
| Salvare i token con il contesto del device | Un solo token per ogni record utente |
| Inviare piccoli payload di metadati | Inserire blob grandi o sensibili |
| Gestire separatamente eventi in foreground e tap | Assumere che tutte le notifiche seguano un unico percorso |
| Scadenza aggressiva dei token obsoleti | Tentativi infiniti per i token non validi |
Un setup Expo push solido non è complicato. È questione di disciplina.
Se il tuo team rilascia frequenti modifiche alla logica dell'app e ha bisogno di un controllo maggiore su release, rollback e visibilità delle consegne, Capgo merita un'occhiata. Aiuta i team mobile a rilasciare aggiornamenti rapidamente senza attendere la revisione degli store, il che è fondamentale quando flussi di notifica, logiche di routing o fix lato client devono raggiungere subito gli utenti.