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

How to Create a Custom Marketing Widget for Your FlutterFlow App

Build a dismissible promotional banner Component at the top of any page using a gradient Container with title Text, CTA Button, and close IconButton. Add a timed popup promo modal that appears after a 5-second delay via On Page Load Wait action. Pull all promo content from a Firestore promotions collection with fields for title, body, ctaUrl, isActive, startDate, endDate, and variant (A/B testing). Persist banner dismissal in App State so it does not reappear for the same promotion.

What you'll learn

  • How to create a Firestore promotions collection with isActive, startDate, endDate, and variant fields
  • How to build a dismissible gradient banner Component with close button and CTA
  • How to trigger a promo popup modal after a 5-second delay using On Page Load Wait action
  • How to persist banner dismissal in App State so dismissed promos stay hidden
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read20-25 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Build a dismissible promotional banner Component at the top of any page using a gradient Container with title Text, CTA Button, and close IconButton. Add a timed popup promo modal that appears after a 5-second delay via On Page Load Wait action. Pull all promo content from a Firestore promotions collection with fields for title, body, ctaUrl, isActive, startDate, endDate, and variant (A/B testing). Persist banner dismissal in App State so it does not reappear for the same promotion.

Building Dismissible Promo Banners and Timed Popup Modals in FlutterFlow

In-app promotions drive engagement and revenue, but they must be manageable without code deploys. This tutorial builds a Firestore-driven banner and popup system where your marketing team controls content, scheduling, and A/B variants from the Firebase console.

Prerequisites

  • A FlutterFlow project with Firestore configured
  • A promotions collection in Firestore with at least one test document
  • Basic familiarity with App State and Conditional Visibility

Step-by-step guide

1

Create the Firestore promotions collection with scheduling and A/B variant fields

In Firestore, create a promotions collection. Each document needs: title (String), body (String), ctaText (String), ctaUrl (String), imageUrl (String, optional), isActive (Boolean), startDate (Timestamp), endDate (Timestamp), variant (String — 'A' or 'B' for A/B testing), type (String — 'banner' or 'popup'). Add a composite index on isActive + startDate for efficient queries. Create one test document with type: 'banner' and one with type: 'popup'.

Expected result: Firestore has a promotions collection with scheduling fields and two test promo documents.

2

Build the PromoBanner Component with gradient Container, CTA Button, and close IconButton

Create a Component named PromoBanner with parameters: title (String), body (String), ctaText (String), ctaUrl (String), promoId (String). The root widget is a Container with gradient background (e.g., primary → secondary), horizontal padding 16, vertical padding 12. Inside, a Row: Expanded Column (title Text in white bold, body Text in white70) + Button (ctaText, white background, primary text color, On Tap → Launch URL ctaUrl) + IconButton (close_rounded, white, On Tap → dismiss logic described in step 4).

Expected result: A gradient banner Component renders with promotional text, a CTA button, and a close button.

3

Query active promotions with date filtering and display the banner conditionally

On the home page, add a Backend Query on promotions where isActive == true AND type == 'banner' AND startDate <= now AND endDate >= now, limit 1. Bind the PromoBanner Component to the query result at the top of the page Column. Wrap the PromoBanner in Conditional Visibility: visible if the query returns a result AND the promoId is NOT in the App State dismissedPromoIds list.

Expected result: The banner appears at the top of the home page only when an active, current-date promotion exists and has not been dismissed.

4

Persist banner dismissal in App State dismissedPromoIds list

Create an App State variable dismissedPromoIds (String List, persisted). On the PromoBanner close IconButton tap: add the current promoId to dismissedPromoIds via Update App State → Add to List. The Conditional Visibility check (promoId NOT in dismissedPromoIds) hides the banner immediately. Because the list is persisted, dismissed banners stay hidden across app restarts.

Expected result: Tapping the close button hides the banner permanently for that specific promotion, even after app restart.

5

Add a timed popup promo modal triggered 5 seconds after page load

On the home page On Page Load action, add: Backend Query promotions where isActive == true AND type == 'popup' AND startDate <= now AND endDate >= now, limit 1. If the query returns a result AND promoId is NOT in dismissedPromoIds: Wait 5000ms → Show Dialog with a PromoPopup Component. The PromoPopup has an Image (promo imageUrl), title Text, body Text, CTA Button (Launch URL), and a close X IconButton. On the close IconButton or CTA tap, add promoId to dismissedPromoIds and close the dialog.

Expected result: Five seconds after page load, a promo popup dialog appears with image, text, and CTA. Dismissing it prevents it from showing again.

Complete working example

FlutterFlow Marketing Widget Setup
1FIRESTORE DATA MODEL:
2 promotions/{promoId}
3 title: String ("Spring Sale — 30% Off")
4 body: String ("Use code SPRING30 at checkout")
5 ctaText: String ("Shop Now")
6 ctaUrl: String ("https://example.com/sale")
7 imageUrl: String (optional, for popup hero image)
8 isActive: Boolean
9 startDate: Timestamp
10 endDate: Timestamp
11 variant: String ("A" | "B")
12 type: String ("banner" | "popup")
13 Index: isActive ASC, startDate ASC
14
15APP STATE:
16 dismissedPromoIds: String List (persisted)
17
18PROMO BANNER COMPONENT:
19 Parameters: title, body, ctaText, ctaUrl, promoId
20 Container (gradient: primary secondary, borderRadius: 8, padding: 12 16)
21 Row
22 Expanded Column
23 Text (title, bodyLarge, white, bold)
24 Text (body, bodySmall, white70)
25 Button (ctaText, white bg, primary text)
26 On Tap Launch URL ctaUrl
27 IconButton (close_rounded, white)
28 On Tap Add promoId to App State dismissedPromoIds
29
30PROMO POPUP COMPONENT:
31 Parameters: title, body, ctaText, ctaUrl, imageUrl, promoId
32 Container (borderRadius: 16, padding: 24, white bg)
33 Column (center)
34 Align (topRight) IconButton (close, grey)
35 On Tap Add promoId to dismissedPromoIds Close Dialog
36 Image (imageUrl, height: 200, fit: cover, borderRadius: 12)
37 SizedBox (height: 16)
38 Text (title, headlineSmall, bold)
39 Text (body, bodyMedium, grey)
40 SizedBox (height: 16)
41 Button (ctaText, full width, primary)
42 On Tap Launch URL ctaUrl Add promoId to dismissedPromoIds Close Dialog
43
44HOME PAGE ON PAGE LOAD:
45 1. Query promotions (isActive, type: banner, date range) show PromoBanner if not dismissed
46 2. Query promotions (isActive, type: popup, date range) if not dismissed Wait 5s Show Dialog PromoPopup

Common mistakes when creating a Custom Marketing Widget for Your FlutterFlow App

Why it's a problem: Not adding startDate and endDate filters to the promotions query

How to avoid: Always filter where startDate <= now AND endDate >= now in the Backend Query so only current promotions display.

Why it's a problem: Storing dismissed state only in Page State instead of persisted App State

How to avoid: Use an App State String List with Persisted enabled. Dismissed promoIds survive page navigation and app restarts.

Why it's a problem: Showing the popup immediately on page load without a delay

How to avoid: Add a Wait action (5000ms) before Show Dialog so users have time to settle into the page before seeing the promotion.

Best practices

  • Store all promo content in Firestore so the marketing team can update without code changes
  • Use startDate and endDate fields for automated scheduling — no manual activation/deactivation needed
  • Add a variant field (A/B) and randomly assign users to test which promo performs better
  • Persist dismissed promo IDs in App State so users are not shown the same promo twice
  • Limit popup frequency to one per session — check a sessionPopupShown Page State before showing
  • Use gradient backgrounds on banners for visual prominence without requiring a designer
  • Include the promo type field (banner vs popup) to control display format from Firestore

Still stuck?

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

ChatGPT Prompt

I want to build a Firestore-driven promotional banner and timed popup in FlutterFlow. Show me the Firestore data model with scheduling fields, the banner Component with dismiss persistence, and the On Page Load popup trigger with a 5-second delay.

FlutterFlow Prompt

Create a gradient banner at the top of the home page with a title, description, action button, and close button. Also create a popup dialog that appears 5 seconds after the page loads with an image, text, and call-to-action button.

Frequently asked questions

How do I implement A/B testing for promotional content?

Add a variant field (A or B) to each promotion document. On the client, randomly assign the user a variant on first launch (store in App State). Filter the promotions query to match the user's variant so they consistently see the same version.

Can the marketing team schedule promotions in advance?

Yes. The startDate and endDate fields on each promotion document control when it appears. Set these dates in the Firebase console. The app query filters by current date automatically.

How do I prevent the popup from showing on every page visit?

When the user dismisses or clicks the CTA, add the promoId to the persisted App State dismissedPromoIds list. The Conditional Visibility check prevents it from appearing again.

Can I show different banners on different pages?

Yes. Add a page field (String) to the promotion document specifying which page it targets. Filter the query on each page to match its own page identifier.

How do I track how many users click the CTA button?

On the CTA tap action, before launching the URL, add a Firestore increment on the promotion document's clickCount field using FieldValue.increment(1) in a Custom Action.

Can RapidDev help build a full in-app marketing and analytics system?

Yes. RapidDev can implement targeted promotions with user segmentation, impression and click analytics, push notification campaigns, and an admin dashboard for managing all marketing content.

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.