Build a public safety alert system with Firestore-backed alerts categorized by severity (info, warning, critical, emergency). Critical alerts trigger a full-screen interstitial overlay in the app that users must dismiss explicitly. Push notifications are sent via FCM Cloud Functions with high-priority delivery for emergencies. An admin panel lets authorized users create alerts with severity, type, affected area, and expiration, while a public alert feed shows active alerts sorted by severity.
Building a Public Safety Alert System in FlutterFlow
Public safety apps need to deliver urgent information reliably and impossible-to-miss. This tutorial builds a complete alert system with four severity levels, from informational banners to full-screen emergency overlays. Alerts are pushed via FCM with priority settings matched to severity, and an admin panel lets authorized users create and manage alerts with geographic targeting and automatic expiration.
Prerequisites
- A FlutterFlow project on the Pro plan or higher
- Firebase project with Firestore, Cloud Functions, and Cloud Messaging (FCM) enabled
- Push notification permissions configured in FlutterFlow project settings
- Basic familiarity with Conditional Visibility and Action Flows in FlutterFlow
Step-by-step guide
Design the Firestore schema for alerts with severity levels
Design the Firestore schema for alerts with severity levels
Create an `alerts` collection with fields: title (String), body (String), severity (String — info, warning, critical, or emergency), type (String — weather, crime, infrastructure, or health), affectedArea (String — city or region name), isActive (bool), expiresAt (Timestamp), and createdBy (String — admin userId). Also add createdAt (Timestamp) for sorting. Create an Option Set named AlertSeverity with values: info (blue), warning (yellow), critical (orange), emergency (red). This maps severity levels to colors throughout the app. Import the schema into FlutterFlow's Firestore panel.
Expected result: The alerts collection is ready with severity levels mapped to colors via the Option Set.
Build the alert feed page sorted by severity and time
Build the alert feed page sorted by severity and time
Create an Alerts page with a Backend Query on the `alerts` collection filtered by isActive == true, ordered by severity descending (so emergencies appear first) and createdAt descending. Bind the results to a ListView. Each list item is a Container with a left border colored by severity (use Conditional Styling: red for emergency, orange for critical, yellow for warning, blue for info). Inside, display the title (bold), body text, type badge, affected area, and time since posting. Add a ChoiceChips filter above the list for alert types (All, Weather, Crime, Infrastructure, Health) that updates the Backend Query filter.
Expected result: Users see a feed of active alerts prioritized by severity. Emergency alerts always appear at the top with a red border.
Create full-screen emergency overlays and banner alerts
Create full-screen emergency overlays and banner alerts
For critical and emergency alerts, you need impossible-to-miss UI elements. On your main app pages, add an On Page Load Backend Query that checks for active alerts where severity equals 'emergency' or 'critical'. If an emergency alert exists, display a full-screen Container overlay with a red background, a large warning icon, the alert title and body in white bold text, and a Dismiss button. Use Page State `alertDismissed` to track whether the user has acknowledged the alert. For warning-level alerts, show a persistent yellow banner at the top of the page using a Conditional Visibility Container. The banner shows the alert title with a Close IconButton.
Expected result: Emergency alerts block the screen with a red overlay until dismissed. Warnings show as persistent top banners. Info alerts appear only in the feed.
Set up FCM push notifications via Cloud Function on alert creation
Set up FCM push notifications via Cloud Function on alert creation
Create a Cloud Function triggered by Firestore onCreate on the `alerts` collection. When a new alert is created, the function reads the severity and constructs an FCM message. For emergency and critical alerts, set the Android priority to 'high' and the APNs content-available flag to trigger immediate delivery even when the app is backgrounded. Send to the 'all_users' FCM topic (subscribe all app users to this topic on first launch). Include the alert title, body, and severity in the notification payload. For info and warning severity, use normal priority to avoid disturbing users at night.
1// Cloud Function: onAlertCreated2const functions = require('firebase-functions');3const admin = require('firebase-admin');4admin.initializeApp();56exports.onAlertCreated = functions.firestore7 .document('alerts/{alertId}')8 .onCreate(async (snap) => {9 const alert = snap.data();10 const isUrgent = ['emergency', 'critical']11 .includes(alert.severity);1213 const message = {14 topic: 'all_users',15 notification: {16 title: `${alert.severity.toUpperCase()}: ${alert.title}`,17 body: alert.body,18 },19 data: {20 alertId: snap.id,21 severity: alert.severity,22 type: alert.type,23 },24 android: {25 priority: isUrgent ? 'high' : 'normal',26 notification: {27 sound: isUrgent ? 'alarm' : 'default',28 channelId: isUrgent29 ? 'emergency_alerts'30 : 'general_alerts',31 },32 },33 apns: {34 payload: {35 aps: {36 sound: isUrgent ? 'alarm.caf' : 'default',37 'content-available': 1,38 },39 },40 },41 };4243 await admin.messaging().send(message);44 });Expected result: When an admin creates a new alert, all subscribed users receive a push notification with urgency level matching the alert severity.
Build the admin panel for creating and managing alerts
Build the admin panel for creating and managing alerts
Create an AdminAlerts page gated by Conditional Visibility checking the current user's role field equals 'admin'. The page has a Create Alert form with: title TextField, body TextField (multiline), severity DropDown (from AlertSeverity Option Set), type DropDown (weather/crime/infrastructure/health), affectedArea TextField, and expiresAt DateTimePicker. On submit, create a document in the `alerts` collection with all fields plus isActive set to true and createdAt set to now. Below the form, show a ListView of all alerts (active and expired) with toggle Switches for isActive and Delete IconButtons. Add a Cloud Function scheduled to run hourly that sets isActive to false on alerts where expiresAt is in the past.
Expected result: Admins can create new alerts, activate/deactivate existing ones, and alerts automatically expire based on the expiresAt timestamp.
Complete working example
1// Cloud Function: onAlertCreated2// Sends FCM push notification when a new alert is created3// Priority and sound vary by severity level45const functions = require('firebase-functions');6const admin = require('firebase-admin');7admin.initializeApp();89exports.onAlertCreated = functions.firestore10 .document('alerts/{alertId}')11 .onCreate(async (snap) => {12 const alert = snap.data();13 const isUrgent = ['emergency', 'critical']14 .includes(alert.severity);1516 const severityLabel = alert.severity.toUpperCase();17 const title = `${severityLabel}: ${alert.title}`;1819 const message = {20 topic: 'all_users',21 notification: {22 title: title,23 body: alert.body,24 },25 data: {26 alertId: snap.id,27 severity: alert.severity,28 type: alert.type || '',29 affectedArea: alert.affectedArea || '',30 },31 android: {32 priority: isUrgent ? 'high' : 'normal',33 notification: {34 sound: isUrgent ? 'alarm' : 'default',35 channelId: isUrgent36 ? 'emergency_alerts'37 : 'general_alerts',38 },39 },40 apns: {41 headers: {42 'apns-priority': isUrgent ? '10' : '5',43 },44 payload: {45 aps: {46 alert: { title, body: alert.body },47 sound: isUrgent ? 'alarm.caf' : 'default',48 'content-available': 1,49 },50 },51 },52 };5354 await admin.messaging().send(message);55 console.log(`Alert sent: ${title} [${alert.severity}]`);56 });5758// Cloud Function: expireAlerts59// Runs hourly to deactivate expired alerts60exports.expireAlerts = functions.pubsub61 .schedule('every 1 hours')62 .onRun(async () => {63 const now = admin.firestore.Timestamp.now();64 const expired = await admin.firestore()65 .collection('alerts')66 .where('isActive', '==', true)67 .where('expiresAt', '<=', now)68 .get();6970 const batch = admin.firestore().batch();71 expired.docs.forEach((doc) => {72 batch.update(doc.ref, { isActive: false });73 });74 await batch.commit();75 console.log(`Expired ${expired.size} alerts`);76 });Common mistakes
Why it's a problem: Sending critical alerts as regular push notifications that users can easily ignore
How to avoid: For emergency alerts, use high-priority FCM with alarm sound, AND show a full-screen interstitial overlay in the app that requires explicit dismissal. The in-app overlay catches users who are already using the app.
Why it's a problem: Only checking tier on page load for showing alert overlays
How to avoid: Use a real-time Firestore listener (Single Time Query OFF) on the alerts collection filtered by severity emergency and isActive true. New alerts trigger the overlay automatically.
Why it's a problem: Not setting expiration times on alerts, leaving old alerts active indefinitely
How to avoid: Require an expiresAt timestamp on every alert. Run a scheduled Cloud Function hourly to set isActive to false on expired alerts. Also let admins manually deactivate alerts.
Best practices
- Map severity levels to consistent colors throughout the app: red for emergency, orange for critical, yellow for warning, blue for info
- Use high-priority FCM delivery for emergency and critical alerts to ensure they arrive even when the device is in Doze mode
- Subscribe all users to the all_users FCM topic on first app launch to enable broadcast notifications
- Show the time since each alert was posted (e.g., '2 hours ago') so users can assess relevance
- Gate the admin panel behind a role check to prevent unauthorized users from creating fake alerts
- Include an affected area field so users can quickly determine if an alert is relevant to their location
- Log all admin actions (create, activate, deactivate) for audit purposes
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building a public safety alert system in FlutterFlow. I need a Firestore schema with severity levels (info/warning/critical/emergency), an FCM Cloud Function that sends push notifications with priority matching the severity, and a FlutterFlow UI with full-screen overlays for emergencies and banners for warnings. Show me the complete implementation.
Create an alert feed page showing public safety alerts sorted by severity. Emergency alerts should show a full-screen red overlay that blocks the screen. Warning alerts show a yellow banner at the top. Add an admin panel where I can create new alerts with severity, type, and expiration date.
Frequently asked questions
How do I geo-target alerts to users in specific areas?
Store the user's location in their profile document. In the Cloud Function, before sending the FCM notification, query users whose location falls within the alert's affected area. Send individual notifications instead of a topic broadcast for geo-targeted delivery.
Can I play a custom alarm sound for emergency alerts?
Yes. Add the alarm sound file to your Android (res/raw/alarm.mp3) and iOS (alarm.caf) projects. Reference it in the FCM notification sound field. FlutterFlow Pro users can add native assets via Custom Code configuration.
How do I prevent alert fatigue from too many notifications?
Let users set notification preferences per severity level. For example, some users may want push notifications only for critical and emergency alerts, with info and warning alerts shown only in the app feed.
Can I integrate with external alert systems like FEMA IPAWS?
Yes. Create a Cloud Function that polls the IPAWS CAP (Common Alerting Protocol) feed periodically and creates Firestore alert documents from matching entries. The rest of your system works the same.
What happens when an alert expires automatically?
The scheduled Cloud Function sets isActive to false. The alert disappears from the active feed and the emergency overlay dismisses on the next real-time update. Users can still view expired alerts in an archive section.
Can RapidDev help build a production public safety platform?
Yes. RapidDev can implement geo-fenced alert delivery, multi-language alert translation, integration with national alert systems, incident reporting, and real-time crisis mapping dashboards.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation