---
term: 'Presenza (stato online)'
seoTitle: 'Sistemi di presenza: stato online, heartbeat e ultimo accesso'
headline: 'Che cos''è la presenza (stato online)?'
slug: presenza-stato-online
category: api-realtime
shortDefinition: 'La presenza è un segnale in tempo reale che indica se un utente è online, assente o offline, tenuto aggiornato da connessioni e heartbeat.'
relatedTerms:
  - real-time-live-queries
  - websockets-real-time-sync
  - pub-sub-pattern
  - sse-vs-websockets-vs-polling
contrastsWith:
  - push-notifications-apns-fcm
aboutTerms:
  - 'Online Status'
  - 'Last Seen'
  - 'Heartbeat'
  - 'Typing Indicators'
faq:
  - question: 'Che cos''è un sistema di presenza?'
    answer: 'Un servizio che tiene traccia se ogni utente è al momento online, assente o offline e trasmette i cambiamenti, in tempo reale, agli utenti autorizzati a vederli. Sotto il cofano: connessioni persistenti o heartbeat periodici che scrivono su un archivio veloce in memoria, con i cambi di stato distribuiti in fan-out via pub/sub.'
  - question: 'Come funziona l''"ultimo accesso"?'
    answer: 'Il server registra un timestamp a ogni heartbeat e a ogni disconnessione. Finché l''utente è online viene servito lo stato in diretta; quando va offline, risponde al suo posto l''ultimo timestamp registrato. È l''unico pezzo durevole di un sistema altrimenti effimero – lo stato scade, l''ultimo accesso persiste.'
  - question: 'Quale intervallo di heartbeat dovrebbe usare la presenza?'
    answer: 'Trenta secondi è il valore predefinito comune in produzione, con il timeout di offline a due-tre volte l''intervallo (60–90 secondi). Intervalli più brevi riducono il ritardo di rilevamento ma moltiplicano il carico di scrittura in modo lineare con la popolazione online; l''intervallo deve inoltre restare sotto gli idle timeout dell''infrastruttura, altrimenti i proxy chiudono per primi le connessioni silenziose.'
  - question: 'Rilevamento basato sulla connessione o sull''heartbeat: qual è meglio?'
    answer: 'Entrambi, per guasti diversi. Gli eventi di connessione (apertura/chiusura) danno transizioni istantanee ma non rilevano le morti silenziose – un dispositivo che resta senza batteria non invia alcun frame di chiusura e lascia una connessione zombie. La scadenza dell''heartbeat limita quell''obsolescenza al prezzo di un ritardo di rilevamento. I sistemi in produzione usano gli eventi di connessione come percorso rapido e il TTL dell''heartbeat come fonte di verità.'
  - question: 'Come si evita che lo stato online sfarfalli?'
    answer: 'Applicando un debounce alla transizione verso offline: alla disconnessione parte un timer di grazia – in genere da 30 a 60 secondi – che viene annullato se l''utente si riconnette, e "offline" si pubblica solo quando il timer scatta. Gli utenti in ascensore o in galleria si riconnettono di continuo; senza periodo di grazia, ogni lista di contatti in cui compaiono sfarfalla insieme a loro.'
  - question: 'Come scala la presenza a milioni di utenti?'
    answer: 'Rispettando la matematica del fan-out: ogni cambio di stato deve raggiungere ogni osservatore, quindi N contatti per M transizioni esplode in fretta. Le leve sono un archivio in memoria con TTL per lo stato, la sottoscrizione ai soli utenti visibili (la lista di chat aperta, non l''intera rubrica), il recupero dell''ultimo accesso a richiesta invece del push, e un tetto alla trasmissione dello stato nei gruppi grandi.'
  - question: 'Come funziona la presenza multi-dispositivo?'
    answer: 'Tracciando una connessione o un heartbeat per dispositivo e unendoli: l''utente è online finché lo è almeno un dispositivo, offline solo quando anche l''ultimo tace. La politica di unione abituale è "vince il più disponibile" – online sul telefono batte inattivo sul desktop – con l''ultimo accesso preso dal dispositivo più recente.'
  - question: 'Gli utenti possono nascondere il proprio stato online?'
    answer: 'Dovrebbero poterlo fare – la visibilità è una feature di prodotto, non un ripensamento: regole come tutti, solo i contatti o nessuno, di solito con reciprocità (chi nasconde il proprio stato non vede quello degli altri). I dati di presenza sono dati comportamentali; chi può osservare chi va delimitato nel modello dei permessi, non nell''interfaccia.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'RFC 6121 — XMPP: Instant Messaging and Presence'
    url: 'https://datatracker.ietf.org/doc/html/rfc6121'
  - name: 'RFC 6455 — The WebSocket Protocol (ping/pong, close codes)'
    url: 'https://datatracker.ietf.org/doc/html/rfc6455'
  - name: 'Page Visibility API — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API'
  - name: 'Beacon API — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API'
  - name: 'Presence information — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Presence_information'
cta:
  title: 'Pallini verdi senza l''infrastruttura'
  text: 'Costruisci la presenza su Back4app con ciò che la piattaforma già esegue: una classe Presence, salvataggi di heartbeat, una sottoscrizione Live Query per la tua lista di contatti e una scansione pianificata per i timeout – permessi inclusi.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-23'
translationKey: presence-online-status
---

**La presenza è un segnale in tempo reale che indica se un utente è online, assente o offline, tenuto aggiornato da connessioni e heartbeat.** Il pallino verde è un'interfaccia ingannevolmente semplice sopra un problema distribuito davvero difficile: il server deve *dedurre* l'assenza – i dispositivi raramente annunciano la propria morte – e poi trasmettere ogni deduzione a chiunque stia guardando, alla scala di una lista di contatti. Standardizzato ben prima delle chat moderne, nelle [stanza di presenza](https://datatracker.ietf.org/doc/html/rfc6121) di XMPP, il pattern non ha più cambiato i propri fondamenti.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| Gli stati | online · assente/inattivo · offline – più gli override impostati dall'utente (non disturbare) |
| Il meccanismo | Scritture di heartbeat + scadenza TTL; eventi di connessione come percorso rapido |
| I numeri | heartbeat ogni ~30 s · timeout di offline a 2–3× l'intervallo · 30–60 s di grazia anti-sfarfallio |
| Il compagno | Ultimo accesso – il timestamp durevole dietro il pallino effimero |
| La parte difficile | Fan-out: N osservatori × M cambi di stato, moltiplicati per il successo del prodotto |

## Il contratto dell'heartbeat

L'intero pattern sta in un solo scambio:

```text
client        ogni 30 s:  save { status: "online", lastActiveAt: now }
server        ogni 60 s:  sweep – lastActiveAt più vecchio di 90 s?  → status: "offline"
                          (TTL = 2–3 × intervallo di heartbeat)
osservatore   status = "online"   → pallino verde
              status = "offline"  → "ultimo accesso 12:41"  ← lastActiveAt, la parte durevole
```

Lo stesso contratto come codice SDK – heartbeat in uscita, sottoscrizione in entrata:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Presence: heartbeat your own status, subscribe to your contacts'
const heartbeat = () =>
  myPresence.save({ status: 'online', lastActiveAt: new Date() });
await heartbeat();
setInterval(heartbeat, 30_000); // server sweeps offline at 2–3× this

const contacts = new Parse.Query('Presence');
contacts.containedIn('user', myContactIds);
const sub = await contacts.subscribe();
sub.on('update', (p) => setStatus(p.get('user'), p.get('status')));
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Presence: heartbeat your own status, subscribe to your contacts'
Future<void> heartbeat() async {
  myPresence
    ..set('status', 'online')
    ..set('lastActiveAt', DateTime.now());
  await myPresence.save();
}
Timer.periodic(const Duration(seconds: 30), (_) => heartbeat());

final contacts = QueryBuilder<ParseObject>(ParseObject('Presence'))
  ..whereContainedIn('user', myContactIds);
final sub = await LiveQuery().client.subscribe(contacts);
sub.on(LiveQueryEvent.update, (p) => setStatus(p.get('user'), p.get('status')));
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Presence: heartbeat your own status, subscribe to your contacts'
func heartbeat() async throws {
    myPresence.status = "online"
    myPresence.lastActiveAt = Date()
    _ = try await myPresence.save()
}
// Fire every 30 s — the server sweeps offline at 2–3× this

let contacts = Presence.query(containedIn(key: "user", array: myContactIds))
let sub = try await contacts.subscribe()
sub.handleEvent { _, e in
    if case .updated(let p) = e { setStatus(p.user, p.status) }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Presence: heartbeat your own status, subscribe to your contacts'
fun heartbeat() {
    myPresence.put("status", "online")
    myPresence.put("lastActiveAt", Date())
    myPresence.saveInBackground()
}
timer.scheduleAtFixedRate(0, 30_000) { heartbeat() } // sweep at 2–3× this

val contacts = ParseQuery.getQuery<ParseObject>("Presence")
contacts.whereContainedIn("user", myContactIds)
val sub = ParseLiveQueryClient.Factory.getClient().subscribe(contacts)
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, p ->
    setStatus(p.getString("user"), p.getString("status"))
}
```

## Eventi di connessione vs. TTL dell'heartbeat

I due modelli di rilevamento, confrontati onestamente – nessuna pagina di classifica lo fa in una sola tabella:

| | Ciclo di vita della connessione | Heartbeat + TTL |
| --- | --- | --- |
| Segnale di online | Socket aperto | Heartbeat fresco entro la finestra |
| Segnale di offline | Evento di chiusura / frame di chiusura | Scadenza del TTL – nessun heartbeat per 2–3 intervalli |
| Velocità di rilevamento | Istantanea su chiusura pulita | Ritardo limitato (fino al timeout) |
| Guasti silenziosi | **Persi** – la perdita di alimentazione non invia alcun frame di chiusura | Catturati – il silenzio è il segnale |
| Stato sul server | Tracciamento per connessione | Scritture stateless su un archivio con TTL |
| Come fallisce | Utenti zombie "online" | Breve falso "offline" su heartbeat persi |

Il [protocollo WebSocket](https://datatracker.ietf.org/doc/html/rfc6455) stesso insegna la lezione: include i frame di controllo ping/pong proprio perché TCP non rivela un peer scomparso, e la sua tassonomia dei codici di chiusura riserva il 1006 alla "chiusura anomala – nessun frame di chiusura ricevuto", cioè il caso zombie. La presenza in produzione stratifica quindi entrambi i modelli: eventi di connessione per le transizioni istantanee, scadenza dell'heartbeat come verità che cattura ciò che gli eventi perdono.

## La macchina a stati

```mermaid
flowchart LR
  accTitle: Macchina a stati della presenza con periodo di grazia
  accDescr: Un utente passa da offline a online alla connessione o a un heartbeat, da online ad assente quando l'app va in background o l'input resta inattivo, e verso offline attraverso un periodo di grazia che parte alla disconnessione o ai battiti persi e viene annullato se l'utente si riconnette prima che scada.
  OFF["offline<br/>(serve l'ultimo accesso)"] -->|"connessione / heartbeat"| ON["online"]
  ON -->|"scheda nascosta · input inattivo"| AW["assente"]
  AW -->|"l'attività riprende"| ON
  ON -->|"disconnessione o battiti persi"| GR["periodo di grazia<br/>30–60 s"]
  AW -->|"disconnessione o battiti persi"| GR
  GR -->|"si riconnette in tempo"| ON
  GR -->|"il timer scatta → pubblica"| OFF
```

Due raffinamenti distinguono le implementazioni curate. **L'assenza si rileva sul client:** il server non può vedere una scheda in background, ma il browser sì – la [Page Visibility API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API) segnala le schede nascoste, i listener di input segnalano l'inattività, e un segnale di offline best-effort alla chiusura della scheda viaggia sulla [Beacon API](https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API). **L'offline ha un debounce:** lo stato di grazia esiste perché le connessioni mobili oscillano – pubblicando "offline" a ogni galleria e a ogni ascensore, la lista di contatti di ogni osservatore sfarfalla di riflesso. Ritardare l'annuncio, annullarlo alla riconnessione, e l'oscillazione si riduce a immobilità. Un'altra distinzione da rubare al protocollo che ha formalizzato la presenza: presenza *calcolata* (online, per connessione) contro stato *impostato dall'utente* (non disturbare) – nell'unione vince sempre il secondo.

## Effimera per progetto

La presenza è una cache della realtà, non un registro: uno stato che arriva in ritardo è peggio di nessuno stato – l'"online" di ieri oggi è una bugia. Quel principio guida le scelte implementative: gli stati vivono in archivi veloci con TTL anziché in tabelle durevoli, non vengono mai messi in coda per la consegna offline, e sono i primi dati scartati sotto backpressure. Solo `lastActiveAt` merita la persistenza. Gli **indicatori di digitazione** sono il principio portato all'estremo – micro-presenza limitata a una conversazione, che scade in secondi, con debounce sul mittente e scartata invece che ritentata; se "Ada sta scrivendo…" non può arrivare adesso, non dovrebbe arrivare mai.

## Il problema del fan-out

Il muro di scalabilità della presenza è la moltiplicazione, non l'archiviazione. Un esempio con i numeri: 100.000 utenti simultanei, ciascuno visibile a 50 contatti, ciascuno con un modesto cambio di stato 20 volte l'ora – fanno 100.000 × 50 × 20 = **100 milioni di eventi di presenza all'ora** da consegnare, per una feature che memorizza una piccola riga per utente. Le leve, nell'ordine in cui tirarle: **sottoscrivere in modo ristretto** – osservare gli utenti a schermo (la lista di conversazioni aperta), non l'intero grafo dei contatti; **pull, non push, per la coda lunga** – recuperare l'ultimo accesso all'apertura di un profilo invece di trasmetterlo in streaming; **limitare la trasmissione nei gruppi** – oltre qualche centinaio di membri, mostrare la presenza all'interazione, non per l'intero elenco; e **raggruppare le transizioni**, così un utente che oscilla costa un solo evento con debounce, non trenta. Il fan-out in sé viaggia sulla consueta meccanica [pub/sub](/glossary/it/pattern-pub-sub/) – la presenza è il caso limite at-most-once di quel pattern, dove scartare un evento obsoleto è una feature.

## Multi-dispositivo e privacy

Un utente, tre dispositivi, un pallino – la presenza per *utente* è un'unione della presenza per *dispositivo*. Si traccia separatamente l'heartbeat di ogni dispositivo; l'utente è online finché lo è almeno uno, e la politica di unione è "vince il più disponibile": online sul telefono batte inattivo sul desktop, e il non disturbare di un qualsiasi dispositivo prevale sugli altri. L'ultimo accesso riporta il dispositivo più recente. La privacy è l'altra metà del progetto, quella che i blog di ingegneria saltano nonostante sia ciò che gli utenti chiedono di più: regole di visibilità (tutti / contatti / nessuno), reciprocità (chi nasconde il proprio stato perde di vista quello degli altri) e ultimo accesso a grana grossa ("di recente" invece di un timestamp). Le regole vanno applicate nei permessi del livello dati – la presenza è un dato comportamentale, e un "online alle 3 di notte" trapelato è una vera fuga di informazioni.

## Casi d'uso comuni

- **Chat e messaggistica** – il canonico pallino verde, l'ultimo accesso e gli indicatori di digitazione.
- **Strumenti di collaborazione** – chi è nel documento, presenza dei cursori, barre laterali "attivi adesso".
- **Supporto e marketplace** – instradamento in base alla disponibilità degli operatori, segnali di fiducia "il venditore è online".
- **Multiplayer e social** – lobby, liste di amici, inviti a raggiungere un amico.
- **Strumenti per la forza lavoro** – stati di disponibilità che alimentano instradamento e dashboard di stato.

## Come costruire la presenza? Matrice decisionale

| Feature | Meccanismo |
| --- | --- |
| Pallino verde sui contatti | Heartbeat + archivio con TTL, sottoscrizione live query sugli utenti visibili |
| Transizioni istantanee in una chat aperta | Eventi di connessione come percorso rapido sul socket |
| Ultimo accesso | Timestamp a ogni heartbeat; recupero a richiesta |
| Rilevamento dell'assenza | Lato client: listener di visibilità e inattività, riportati nell'heartbeat |
| Indicatore di digitazione | Micro-eventi per conversazione, TTL di pochi secondi, mai persistiti |
| Presenza in un gruppo da 5.000 membri | Niente trasmissione – mostrare all'interazione, limitare l'elenco |

## Limiti e trade-off

- **La presenza è probabilistica.** Fra un heartbeat e l'altro il pallino è una congettura; i sistemi onesti accettano un'obsolescenza limitata invece di fingere una verità istantanea.
- **La freschezza costa scritture.** Dimezzare l'intervallo di heartbeat raddoppia il carico di scrittura su ogni utente online – la velocità di rilevamento si compra in throughput.
- **Il fan-out scala con il successo.** La feature è economica a 1.000 utenti e un progetto di architettura a 10 milioni; l'ambito delle sottoscrizioni va progettato prima che la crescita lo imponga.
- **L'oscillazione è intrinseca.** Le reti mobili garantiscono un continuo via vai di riconnessioni; senza debounce, la presenza amplifica il rumore di rete in rumore di interfaccia.
- **Ha la forma della sorveglianza.** Gli schemi di presenza rivelano sonno, lavoro e abitudini; controlli di visibilità e applicazione nel livello dei permessi sono requisiti, non miglioramenti.

## La presenza su Back4app

Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. I mattoni qui sopra si mappano uno a uno: una classe `Presence` contiene `status` e `lastActiveAt`; l'heartbeat è un salvataggio periodico (le schede di codice); gli osservatori tengono una sottoscrizione [Live Query](/glossary/it/live-queries-tempo-reale/) sui contatti al momento a schermo e ricevono gli aggiornamenti in push sulla flotta di [WebSocket](/glossary/it/websockets/) gestita dalla piattaforma; un job Cloud Code pianificato è la scansione del TTL, che porta a offline le righe obsolete e fa scattare il debounce; e i permessi di classe più le ACL implementano le regole di visibilità nel livello dati, dove devono stare. Nulla di artigianale da gestire – la presenza diventa un esercizio di modellazione dei dati sopra un'infrastruttura che il backend già esegue.
