Firestore Real-Time Listeners — Live Data Updates with onSnapshot
In this tutorial, you will learn about Firestore Real. We cover key concepts, practical examples, and best practices to help you master this topic.
Firestore real-time listeners use onSnapshot to subscribe to document or query changes, receiving immediate updates when data changes without polling the server.
What You'll Learn
- Setting up onSnapshot listeners for documents and collections
- Handling document changes, metadata, and errors
- Detaching listeners and managing subscriptions
Why It Matters
Real-time updates power collaborative and live-data applications. Without onSnapshot, you would need constant polling. DodaTech's real-time threat monitoring dashboard uses Firestore listeners for instant alert display.
sequenceDiagram
Client->>Firestore: onSnapshot subscription
Firestore-->>Client: Initial snapshot
Note over Client: Display initial data
Client->>Firestore: User makes change
Firestore-->>Client: Updated snapshot
Note over Client: Update UI immediately
Client->>Firestore: Detach listener
Firestore-->>Client: Subscription ended
Code Examples
// Document listener
import { doc, onSnapshot } from 'firebase/firestore';
const unsubscribe = onSnapshot(
doc(db, 'users', 'alice@example.com'),
(doc) => {
if (doc.exists()) {
console.log('User data:', doc.data());
} else {
console.log('User document deleted');
}
},
(error) => {
console.error('Listener error:', error);
}
);
// Later: detach the listener
unsubscribe();
// Collection query listener
import { collection, query, where, onSnapshot } from 'firebase/firestore';
const q = query(
collection(db, 'alerts'),
where('severity', '==', 'critical'),
where('resolved', '==', false)
);
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') {
console.log('New alert:', change.doc.data());
showNotification(change.doc.data());
}
if (change.type === 'modified') {
console.log('Alert updated:', change.doc.data());
updateAlertInUI(change.doc.id, change.doc.data());
}
if (change.type === 'removed') {
console.log('Alert removed:', change.doc.data());
removeAlertFromUI(change.doc.id);
}
});
});
// Include metadata
onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
const isFromCache = snapshot.metadata.fromCache;
const hasPending = snapshot.metadata.hasPendingWrites;
console.log('Source:', isFromCache ? 'cache' : 'server');
console.log('Pending writes:', hasPending);
});
# Python Firestore listener
from google.cloud import firestore
db = firestore.Client()
doc_ref = db.collection('alerts').document('alert-123')
# Watch a document
watcher = doc_ref.on_snapshot(
lambda docs, changes, read_time: print(
f'Document changed: {[d.to_dict() for d in docs]}'
)
)
# Watch a query
query = (
db.collection('alerts')
.where('severity', '==', 'critical')
.where('resolved', '==', False)
)
query_watcher = query.on_snapshot(
lambda docs, changes, read_time: print(
f'Query changed: {len(changes)} changes'
)
)
Common Mistakes
1. Not Detaching Listeners When Component Unmounts
Undetached listeners cause memory leaks and unnecessary read charges.
2. Ignoring the Error Callback
Network errors or permission changes can cause listeners to fail silently.
3. Using Too Many Listeners
Each listener counts as a read. Combine queries when possible.
4. Not Handling Metadata Changes
IncludeMetadataChanges prevents UI flicker during cache vs server transitions.
5. Mutating State Directly in Listener Callbacks
Always create copies of document data before updating application state.
Practice Questions
- How do you subscribe to real-time changes on a Firestore document?
- How do you detach a Firestore listener?
- What does docChanges() return?
- Why include metadata changes?
- What happens when a listener encounters a permission error?
Answers:
- Call onSnapshot() with the document reference and a callback function.
- Call the unsubscribe function returned by onSnapshot().
- An array of change objects with type (added/modified/removed) and the document data.
- To detect when data comes from cache vs server and when there are pending local writes.
- The error callback fires with a FirestoreError. The listener is not automatically detached.
Challenge: Build a real-time collaborative todo list where multiple users can add, complete, and delete tasks. Use onSnapshot for instant updates across all clients. Handle offline changes and Conflict Resolution.
FAQ
Mini Project
Build a real-time monitoring dashboard that displays Firestore document changes as they happen. Show added, modified, and removed documents with color-coded indicators. Include a log panel showing each change event and a filter for specific document types.
What's Next
Learn about batch writes for efficient bulk operations, then explore Firestore transactions for atomic data updates.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro