Build a CRM with user segmentation by extending a contacts collection with a segment builder that lets admins combine conditions like last activity date, total spend, and category. A Cloud Function evaluates these conditions against all contacts server-side and writes matching contact IDs to a segment members subcollection. Admins can then perform bulk actions on segments like sending targeted emails or updating statuses, with segment sizes auto-refreshed daily.
Building a CRM with Dynamic User Segmentation in FlutterFlow
A CRM becomes powerful when you can group contacts into segments for targeted actions. This tutorial builds a complete CRM with contact management, activity logging, and a dynamic segment builder where admins define conditions to automatically group contacts. Cloud Functions handle the server-side evaluation, and bulk actions let you act on entire segments at once.
Prerequisites
- A FlutterFlow project with Firestore and authentication configured
- Firebase Cloud Functions enabled for segment evaluation
- Basic familiarity with Firestore queries and Custom Functions
- An admin user role set up for CRM access
Step-by-step guide
Create the Firestore data model for contacts, activities, and segments
Create the Firestore data model for contacts, activities, and segments
Define a segmented CRM data model with contacts collection (name, email, phone, company, status, source, tags array, assignedTo, lifetimeValue, lastContactedAt) plus a segments collection (name, conditions array of {field, operator, value}, memberCount, lastCalculatedAt). The tags array on each contact enables flexible grouping — unlike the basic CRM which uses a single status field, segmentation adds multi-dimensional filtering using combinable conditions like 'lifetimeValue > 100 AND status == active AND tags contains premium'.
Expected result: Firestore has contacts, activities, and segments collections with a members subcollection for segment results.
Build the contacts list with search, filter, and activity timeline
Build the contacts list with search, filter, and activity timeline
Create a ContactsPage with a TextField for search at the top. Add ChoiceChips for status filtering: All, Lead, Prospect, Customer, Churned. Add a DropDown for sorting by name, date, or last contacted. Below, add a ListView with a Backend Query on contacts filtered by the selected status and sorted by the selected field. Each row shows the contact name, company, email, status as a colored badge, and lastContactedAt. Tap a contact to navigate to ContactDetailPage showing all fields plus an activity timeline: a second ListView querying activities filtered by contactId, ordered by timestamp descending. Add a FloatingActionButton to log a new activity with type DropDown and description TextField.
Expected result: A searchable, filterable contact list with detail pages showing contact info and a chronological activity timeline.
Build the segment builder with dynamic condition rows
Build the segment builder with dynamic condition rows
Create a SegmentsPage with a Button labeled Create Segment that opens a BottomSheet. The segment builder contains: a TextField for segment name and a dynamic conditions section. Use Page State to store a list of condition maps. Each condition row is a Row with three widgets: a DropDown for field (lastContactedAt, totalSpent, status, source, tags), a DropDown for operator (equals, not_equals, greater_than, less_than, contains, before_date, after_date), and a TextField for value. Add a plus IconButton to append a new empty condition row to the Page State list. Add a minus IconButton on each row to remove it. At the bottom, add a Calculate Segment button that calls a Cloud Function with the conditions array and a Save Segment button that writes the segment document to Firestore.
Expected result: Admins can visually build segments by combining multiple conditions with field, operator, and value selectors.
Create the Cloud Function for segment evaluation
Create the Cloud Function for segment evaluation
Write a Cloud Function named evaluateSegment that receives the segment ID and conditions array. The function queries all contacts from Firestore, evaluates each contact against all conditions using the specified operators, and collects matching contact IDs. It then batch-writes matching contacts to the segments/{segmentId}/members subcollection, clears any previous members that no longer match, and updates the segment document with the new memberCount and lastCalculatedAt timestamp. Create a second scheduled Cloud Function that runs daily to recalculate all active segments automatically so segment membership stays current as contact data changes.
Expected result: Segment evaluation runs server-side and writes matching contacts to the members subcollection with automatic daily recalculation.
Display segment results and perform bulk actions
Display segment results and perform bulk actions
On the SegmentsPage, add a ListView of all segments showing the segment name, memberCount as a badge, conditions summary, and lastCalculatedAt. Tap a segment to navigate to SegmentDetailPage showing the member list: a ListView querying the members subcollection, joined with contact data to show name, email, and status. Add a Bulk Actions Row at the top with buttons: Send Email (opens email composer for all members), Update Status (DropDown to set a new status on all members), and Export CSV (calls a Cloud Function to export member data). Add a BarChart Custom Widget on the SegmentsPage showing segment sizes side-by-side for comparison.
Expected result: Admins can view segment members, compare segment sizes visually, and perform bulk actions like email and status updates on entire segments.
Complete working example
1FIRESTORE DATA MODEL:2 contacts/{contactId}3 name: String4 email: String5 phone: String6 company: String7 status: "lead" | "prospect" | "customer" | "churned"8 source: String9 assignedTo: String10 totalSpent: Double11 lastContactedAt: Timestamp12 createdAt: Timestamp13 tags: [String]1415 activities/{activityId}16 contactId: String17 type: "call" | "email" | "meeting" | "note"18 description: String19 timestamp: Timestamp20 userId: String2122 segments/{segmentId}23 name: String24 conditions: [25 { "field": "totalSpent", "operator": "greater_than", "value": "100" },26 { "field": "status", "operator": "equals", "value": "customer" }27 ]28 memberCount: Integer29 lastCalculatedAt: Timestamp30 createdBy: String31 └── members/{memberId}32 contactId: String33 addedAt: Timestamp3435PAGE: ContactsPage36WIDGET TREE:37 Column38 ├── TextField (search)39 ├── ChoiceChips (All | Lead | Prospect | Customer | Churned)40 ├── DropDown (sort by name/date/lastContacted)41 └── ListView (contacts, filtered + sorted)42 └── Container (contact row)43 ├── Text (name + company)44 ├── Badge (status, color-coded)45 └── Text (lastContactedAt)4647PAGE: SegmentsPage48WIDGET TREE:49 Column50 ├── Row51 │ ├── Text ("Segments")52 │ └── Button ("Create Segment" → BottomSheet)53 ├── Custom Widget (BarChart: segment sizes)54 └── ListView (segments)55 └── Container56 ├── Text (name)57 ├── Badge (memberCount)58 └── Text (lastCalculatedAt)5960SEGMENT BUILDER BOTTOMSHEET:61 Column62 ├── TextField (segment name)63 ├── Text ("Conditions")64 ├── ListView (condition rows from Page State)65 │ └── Row66 │ ├── DropDown (field)67 │ ├── DropDown (operator)68 │ ├── TextField/DatePicker (value)69 │ └── IconButton (remove row)70 ├── IconButton (+ add condition)71 ├── Button (Calculate Segment → Cloud Function)72 └── Button (Save Segment)Common mistakes when building a Custom CRM with User Segmentation in FlutterFlow
Why it's a problem: Evaluating segment conditions on the client by loading all contacts into the app
How to avoid: Always run segment evaluation in Cloud Functions server-side. The function has more memory and processing power and writes results to Firestore for the client to read.
Why it's a problem: Not recalculating segments as contact data changes
How to avoid: Create a scheduled Cloud Function that recalculates all active segments daily. Display lastCalculatedAt on each segment so admins know how fresh the data is.
Why it's a problem: Not creating Firestore composite indexes for compound contact queries
How to avoid: Create composite indexes proactively for the query combinations your filters use. Firestore logs the exact index creation URL when a query fails, which you can follow to create the needed index.
Best practices
- Run segment evaluation in Cloud Functions to handle large contact databases efficiently
- Recalculate segments daily with a scheduled Cloud Function to keep membership current
- Use dropdown-based condition builders to prevent invalid condition definitions
- Display segment sizes in a bar chart for quick visual comparison
- Create composite Firestore indexes for multi-field contact queries
- Log activities on contacts with timestamps for relationship tracking
- Color-code contact status badges for quick visual scanning of the pipeline
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a CRM with user segmentation in FlutterFlow. Show me the Firestore data model for contacts, activities, and segments, a visual segment builder UI with condition rows, the Cloud Function for server-side evaluation, and bulk actions on segment members.
Create a CRM contacts page with a search bar, status filter chips, a sortable contact list, and a floating action button. Each contact card should show the name, company, status badge, and last contacted date.
Frequently asked questions
How many conditions can a single segment have?
There is no strict limit. However, each additional condition narrows the segment further. Typically 2-5 conditions per segment strikes the right balance between specificity and usable segment size.
Can I create segments based on activity data?
Yes. Add activity-based fields to the condition builder such as 'last activity type' or 'activity count in last 30 days'. The Cloud Function queries the activities collection for each contact to evaluate these conditions.
How do I send bulk emails to a segment?
The Bulk Email button queries the members subcollection, collects email addresses from the linked contact documents, and passes them to a Cloud Function that sends emails via SendGrid, Mailgun, or Firebase Extensions. Always use BCC or individual sends to protect recipient privacy.
Can segments overlap so a contact belongs to multiple segments?
Yes. Each segment is evaluated independently. A contact matching the conditions of multiple segments will appear in all of them. The members subcollection per segment stores its own independent membership.
How do I handle very large contact databases with more than 100,000 contacts?
For large databases, run segment evaluation in batches within the Cloud Function, processing 1,000 contacts at a time. Consider using BigQuery for complex queries and exporting results back to Firestore.
Can RapidDev help build an enterprise CRM system?
Yes. RapidDev can implement full CRM systems with pipeline management, lead scoring, email integration, calendar sync, advanced segmentation with ML-based predictions, and reporting dashboards.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation