Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Build a Custom Notification Center in FlutterFlow

Build an in-app notification center using a Firestore subcollection per user — users/{uid}/notifications with fields title, body, type, isRead, timestamp, and actionUrl. Display notifications in a reversed-order ListView with bold text and a blue dot for unread items. Add a bell icon in the AppBar with a badge showing unread count from a Firestore count query. Tap a notification to mark it read and navigate to the page specified in actionUrl. Swipe-to-dismiss requires a Custom Widget wrapping each item in Dismissible.

What you'll learn

  • How to design the Firestore notifications subcollection data model
  • How to show an unread count badge on the AppBar bell icon
  • How to style notification rows with read/unread conditional formatting
  • How to implement tap-to-navigate and mark-all-read actions
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read20-30 minFlutterFlow Free+ (Custom Widget needed for swipe-to-dismiss)March 2026RapidDev Engineering Team
TL;DR

Build an in-app notification center using a Firestore subcollection per user — users/{uid}/notifications with fields title, body, type, isRead, timestamp, and actionUrl. Display notifications in a reversed-order ListView with bold text and a blue dot for unread items. Add a bell icon in the AppBar with a badge showing unread count from a Firestore count query. Tap a notification to mark it read and navigate to the page specified in actionUrl. Swipe-to-dismiss requires a Custom Widget wrapping each item in Dismissible.

In-app notification center with Firestore and real-time badges

Push notifications bring users back to your app, but they need an in-app notification center to review past alerts. This tutorial builds one: a Firestore subcollection stores notifications per user, a bell icon in the AppBar shows the unread count as a red badge, and a dedicated page lists all notifications with read/unread styling, tap-to-navigate, and swipe-to-dismiss. The unread count query runs in real-time so the badge updates instantly when new notifications arrive.

Prerequisites

  • A FlutterFlow project with Firebase/Firestore connected
  • Firebase Authentication enabled with users already signing in
  • Basic understanding of Backend Queries and Conditional Visibility
  • For swipe-to-dismiss: FlutterFlow Pro plan (Custom Widget required)

Step-by-step guide

1

Create the Firestore notifications subcollection

In Firestore, each user gets their own notifications subcollection at users/{uid}/notifications. Create fields: title (String), body (String), type (String — 'order', 'message', 'system', 'promo'), isRead (Boolean, default false), timestamp (Timestamp), and actionUrl (String — in-app route like '/orders/abc123'). Set Firestore rules: match /users/{uid}/notifications/{notifId} { allow read, update: if request.auth.uid == uid; }. Only Cloud Functions should create notifications (admin SDK bypasses rules).

Expected result: Each user has a notifications subcollection with proper security rules.

2

Add the bell icon with unread count badge in the AppBar

In your main page's AppBar, place a Stack widget in the actions area. Bottom layer: IconButton with Icons.notifications_outlined, On Tap navigates to NotificationsPage. Top layer: a Positioned Container (18×18, circular, red background) in the top-right corner containing a Text widget with the unread count. Bind the count via a Backend Query on users/{currentUser.uid}/notifications where isRead == false, using the query result count. Wrap the badge in Conditional Visibility: hide when count == 0. Set Single Time Query to OFF for real-time updates.

Expected result: A bell icon with a red badge showing the unread count appears in the AppBar. Badge hides when all are read.

3

Build the notifications ListView with read/unread conditional styling

Create NotificationsPage with a ListView bound to Backend Query: users/{currentUser.uid}/notifications, ordered by timestamp descending, limit 20, infinite scroll ON. Each item is a Component with a Row: left has a small Container (8×8, circular, blue — Conditional Visibility: isRead == false), then an Icon that varies by type (Icons.shopping_bag for 'order', Icons.message for 'message', Icons.campaign for 'promo', Icons.info for 'system' — use Conditional Value), then a Column with title Text (Conditional Style: fontWeight bold when !isRead, normal when isRead) and body Text in secondaryText color plus a timestamp Text. Set the Row background: light blue tint (#E3F2FD) when !isRead, white when isRead via Conditional Style.

Expected result: Notifications display with bold unread items showing a blue dot and tinted background. Read items appear dimmer.

4

Add tap-to-navigate that marks notification as read

On each notification Component, add an On Tap action trigger. Action Flow: first Update Document → set isRead = true on this notification's document reference. Then navigate using the actionUrl field: add a Conditional Action chain — if type == 'order' Navigate To OrderDetailPage (pass the ID parsed from actionUrl), if type == 'message' Navigate To ChatPage, etc. The unread badge decrements automatically because the real-time count query detects the isRead change. For dynamic routing without conditionals: use a Custom Action with Navigator.pushNamed(context, notification.actionUrl).

Expected result: Tapping a notification marks it read (dot disappears, text unbolds) and navigates to the relevant page.

5

Add Mark All Read button and swipe-to-dismiss

In the NotificationsPage AppBar, add an IconButton (Icons.done_all). On Tap Action Flow: query all notifications where isRead == false for the current user, then loop through results calling Update Document isRead = true on each. For better performance, use a Custom Action with Firestore WriteBatch to update all in a single batch write. For swipe-to-dismiss: create a Custom Widget that wraps each notification Component in Flutter's Dismissible widget with direction: DismissDirection.endToStart, a green background with a checkmark icon, and onDismissed calling an Action Parameter callback that marks isRead = true.

dismissible_notification.dart
1// Custom Widget: DismissibleNotification
2Dismissible(
3 key: Key(widget.notificationId),
4 direction: DismissDirection.endToStart,
5 background: Container(
6 color: Colors.green,
7 alignment: Alignment.centerRight,
8 padding: const EdgeInsets.only(right: 16),
9 child: const Icon(Icons.done, color: Colors.white),
10 ),
11 onDismissed: (_) => widget.onDismiss?.call(widget.notificationId),
12 child: widget.child,
13)

Expected result: Swiping a notification slides it away and marks it read. Mark All Read clears all unread badges at once.

Complete working example

Notification Center Architecture
1Firestore Data Model:
2 users/{uid}/notifications/{notifId}
3 title: String ("Your order shipped")
4 body: String ("Order #1234 is on its way")
5 type: String ("order" | "message" | "system" | "promo")
6 isRead: Boolean (false)
7 timestamp: Timestamp
8 actionUrl: String ("/orders/abc123")
9
10AppBar Bell Icon (any page):
11 Stack
12 IconButton (Icons.notifications_outlined)
13 On Tap Navigate To: NotificationsPage
14 Positioned (top: 0, right: 0)
15 Container (18x18, circular, #FF0000) [Cond. Vis: count > 0]
16 Text (unread count, white, fontSize: 10, fontWeight: bold)
17 Backend Query: notifications where isRead==false (count, real-time)
18
19NotificationsPage:
20 AppBar
21 Title: "Notifications"
22 Action: IconButton (Icons.done_all) batch update isRead=true
23 ListView (query: notifications, orderBy: timestamp DESC, limit: 20)
24 NotificationRow Component (per item)
25 Row (bg: isRead ? #FFFFFF : #E3F2FD)
26 Container (8x8, circular, blue) [Cond. Vis: !isRead]
27 SizedBox (w: 8)
28 Icon (conditional by type field)
29 SizedBox (w: 12)
30 Expanded Column (crossAxis: start)
31 Text (title, bold if !isRead)
32 Text (body, secondaryText, maxLines: 2)
33 Text (relative timestamp, caption)
34 Icon (Icons.chevron_right, gray)
35 On Tap Update isRead=true Navigate by actionUrl

Common mistakes when building a Custom Notification Center in FlutterFlow

Why it's a problem: Querying all notifications without pagination

How to avoid: Set limit to 20 and enable infinite scroll on the Backend Query. Run a scheduled Cloud Function to delete notifications older than 30 days.

Why it's a problem: Using Single Time Query for the badge count

How to avoid: Set Single Time Query to OFF on the bell badge count query. The real-time stream updates the badge instantly when the Cloud Function creates a new notification.

Why it's a problem: Marking all read with individual update calls in a loop

How to avoid: Use a Custom Action with Firestore WriteBatch: batch.update(docRef, {'isRead': true}) for each, then batch.commit() to send all updates in one network round-trip.

Best practices

  • Use a subcollection per user (users/{uid}/notifications) not a global collection with userId filter — better security rules and query performance
  • Keep the badge count query real-time (Single Time Query: OFF) for instant badge updates
  • Include a type field for icon differentiation and routing logic
  • Paginate with limit 20 + infinite scroll — never load unbounded notification lists
  • Archive old notifications (30+ days) via a scheduled Cloud Function to control costs
  • Use Firestore WriteBatch for mark-all-read to batch updates into a single operation
  • Test with 100+ notifications to verify scrolling performance before deploying

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Design a Firestore data model for an in-app notification center where each user has their own notifications subcollection. Include fields for title, body, type, isRead, timestamp, and actionUrl. Give me the security rules and a Cloud Function that creates a notification for a given user.

FlutterFlow Prompt

Create a notifications page with a ListView connected to my Firestore notifications subcollection, ordered by timestamp descending. Each item shows an icon, title in bold for unread, body text, and a relative timestamp. Unread items should have a light blue background.

Frequently asked questions

How do I create notifications from a Cloud Function?

Use admin.firestore().collection('users').doc(recipientUid).collection('notifications').add({title, body, type, isRead: false, timestamp: admin.firestore.Timestamp.now(), actionUrl}). The user's real-time query picks it up instantly and the badge updates.

Can I also send push notifications alongside the in-app center?

Yes. When the Cloud Function creates the Firestore notification document, also call admin.messaging().send({token: userFcmToken, notification: {title, body}}). Push brings users back to the app; the in-app center lets them review history.

How do I show relative timestamps like '5 min ago'?

Create a Custom Function: calculate the difference between now and the notification timestamp. Return 'Just now' for <1 min, 'X min ago' for <60 min, 'X hours ago' for <24 hours, or a formatted date string for older.

Should I keep notifications forever or delete old ones?

Delete notifications older than 30-90 days via a scheduled Cloud Function. Firestore charges per document read — thousands of stale notifications still cost money when queried. Archive to a separate collection if you need an audit trail.

How do I group notifications by date in the list?

Use a Custom Function that compares each notification's date to the previous item. When the date changes, insert a section header ('Today', 'Yesterday', 'March 15'). Implement this by generating items in a Custom Widget that interleaves headers with notification rows.

Can RapidDev help build a full notification system?

Yes. A production notification system with push, email, in-app channels, user preferences, delivery scheduling, and analytics requires Cloud Functions and FCM setup beyond the visual builder. RapidDev can architect the full system.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.