Create a custom event logging system by building a fire-and-forget Custom Action that writes events to a Firestore event_log collection with the event name, user ID, session ID, properties map, and timestamp. Call this action from key Action Flows throughout your app to track button clicks, page views, purchases, and errors. Build an admin dashboard that aggregates events by name and displays trends over time using charts.
Building a Custom Event Logging System in FlutterFlow
Understanding how users interact with your app is critical for improving it. This tutorial shows you how to build a lightweight custom analytics system that logs events to Firestore, tracks sessions, and displays aggregated data in an admin dashboard — all without relying on third-party analytics tools.
Prerequisites
- A FlutterFlow project with Firestore and authentication configured
- Basic familiarity with Custom Actions and App State in FlutterFlow
- An existing app with pages and actions to instrument
Step-by-step guide
Create the Firestore data model for event logs
Create the Firestore data model for event logs
Create an event_log collection with fields: eventName (String), userId (String), sessionId (String), properties (Map, for key-value metadata), platform (String: ios, android, or web), appVersion (String), timestamp (Timestamp). Create Firestore indexes on eventName + timestamp descending for efficient querying. Add a second index on userId + timestamp descending for per-user event history. The properties map lets you attach arbitrary context to each event, such as the button name, page name, product ID, or error message.
Expected result: Firestore has an event_log collection with indexes ready for querying events by name and by user.
Build the logEvent Custom Action with fire-and-forget pattern
Build the logEvent Custom Action with fire-and-forget pattern
Create a Custom Action named logEvent that takes two parameters: eventName (String, required) and properties (Map of String to dynamic, optional). Inside the action, get the current user ID from the authenticated user. Get the sessionId from App State (set on app launch). Write a document to the event_log collection with all fields. Critically, do NOT await the Firestore write — use fire-and-forget so the event logging does not add latency to the user's action flow. This means calling the create document method without await so it runs in the background.
1// Custom Action: logEvent2import 'package:cloud_firestore/cloud_firestore.dart';3import 'dart:io' show Platform;45Future<void> logEvent(6 String eventName,7 String sessionId,8 Map<String, dynamic>? properties,9) async {10 final userId = FirebaseAuth.instance.currentUser?.uid ?? 'anonymous';11 // Fire-and-forget: intentionally not awaiting12 FirebaseFirestore.instance.collection('event_log').add({13 'eventName': eventName,14 'userId': userId,15 'sessionId': sessionId,16 'properties': properties ?? {},17 'platform': Platform.isIOS ? 'ios' : 'android',18 'timestamp': FieldValue.serverTimestamp(),19 });20}Expected result: A reusable Custom Action that logs events to Firestore without blocking the UI or adding latency.
Set up session tracking on app launch
Set up session tracking on app launch
In your App State, create a sessionId variable of type String with no persistence (resets on each app launch). On your initial page's On Page Load action (or your app's entry point), generate a unique session ID using a Custom Function that returns a UUID string. Store it in App State sessionId. This ID is passed to every logEvent call so you can group all events from a single app session together. Additionally, call logEvent with eventName 'session_start' to mark the beginning of each session.
Expected result: Each app launch generates a unique session ID and logs a session_start event.
Instrument key user flows with event logging
Instrument key user flows with event logging
Add logEvent calls to your existing Action Flows at strategic points. On each page's On Page Load action, call logEvent with eventName 'page_view' and properties containing the page name. On important button taps (sign up, purchase, add to cart), call logEvent with a descriptive event name and relevant properties like product ID or amount. On error states, call logEvent with eventName 'error_occurred' and properties containing the error message and context. Aim for 5 to 10 key events that cover the most important user journey steps.
Expected result: Key user actions throughout the app generate event log entries in Firestore for analysis.
Build an admin dashboard for event analysis
Build an admin dashboard for event analysis
Create an AdminEventsPage accessible only to admin users. Add a DropDown at the top to filter by eventName (populated from distinct event names). Add a DatePicker range for filtering by time period. Below, display a summary Row with total events count, unique users count, and unique sessions count for the selected filters. Add a ListView showing recent events with eventName, userId, properties, and timestamp. For trend visualization, add a Custom Widget using fl_chart that shows a BarChart of daily event counts over the past 7 days. Use a Custom Function to aggregate the event data by day.
Expected result: An admin dashboard showing event counts, recent events, and daily trend charts with filtering by event name and date range.
Add privacy controls and data export
Add privacy controls and data export
Create a scheduled Cloud Function that runs daily and anonymizes event logs older than 90 days by replacing the userId with 'anonymized'. Add a Cloud Function for data export that queries events for a date range and writes them as a CSV file to Firebase Storage, returning the download URL. On the admin dashboard, add an Export CSV button that calls this function and opens the download URL. In the app settings, add a toggle for users to opt out of analytics. Check this preference in the logEvent Custom Action and skip writing if the user has opted out.
Expected result: User data is automatically anonymized after 90 days, admins can export event data, and users can opt out of tracking.
Complete working example
1FIRESTORE DATA MODEL:2 event_log/{eventId}3 eventName: String4 userId: String5 sessionId: String6 properties: Map<String, dynamic>7 platform: String (ios/android/web)8 timestamp: Timestamp910 INDEXES:11 eventName ASC + timestamp DESC12 userId ASC + timestamp DESC1314APP STATE:15 sessionId: String (not persisted, regenerated on launch)1617CUSTOM ACTION: logEvent(eventName, sessionId, properties?)18 Fire-and-forget Firestore write (no await)19 Includes: userId, sessionId, platform, timestamp2021INSTRUMENTATION POINTS:22 1. session_start → On app launch23 2. page_view → On Page Load of every page24 Properties: { "page": "HomePage" }25 3. button_click → On key button taps26 Properties: { "button": "add_to_cart", "productId": "abc" }27 4. purchase_complete → After successful payment28 Properties: { "amount": 29.99, "productId": "abc" }29 5. error_occurred → On error states30 Properties: { "error": "Payment failed", "code": "card_declined" }3132PAGE: AdminEventsPage (admin only)33WIDGET TREE:34 Column35 ├── Row (filters)36 │ ├── DropDown (eventName filter)37 │ └── DatePicker (date range)38 ├── Row (summary stats)39 │ ├── Container (total events count)40 │ ├── Container (unique users count)41 │ └── Container (unique sessions count)42 ├── Custom Widget (fl_chart BarChart: daily event counts)43 ├── Button (Export CSV)44 └── ListView (recent events)45 └── Container46 ├── Text (eventName)47 ├── Text (userId)48 ├── Text (properties as formatted text)49 └── Text (timestamp)Common mistakes when creating a Custom Event Logging System in FlutterFlow
Why it's a problem: Logging events synchronously by awaiting the Firestore write in the Action Flow
How to avoid: Use fire-and-forget by not awaiting the Firestore write in the Custom Action. The write happens in the background without blocking the user.
Why it's a problem: Logging too many events with excessive detail on every user interaction
How to avoid: Focus on 5-10 key events that represent meaningful steps in the user journey. Use the properties map for relevant context rather than logging every micro-interaction.
Why it's a problem: Not anonymizing or expiring old event data
How to avoid: Create a scheduled Cloud Function that anonymizes userId on events older than 90 days. Provide users an opt-out toggle and honor it in the logEvent action.
Best practices
- Use fire-and-forget pattern for event logging to avoid adding latency to user actions
- Generate a unique session ID on each app launch for grouping related events
- Use the properties map for flexible event context rather than separate fields per event type
- Limit instrumentation to 5-10 key events covering the core user journey
- Create Firestore composite indexes for the queries your admin dashboard needs
- Anonymize event data after a retention period for privacy compliance
- Add user opt-out controls for analytics tracking
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a custom event logging and analytics system in FlutterFlow using Firestore. Show me the data model, a fire-and-forget Custom Action for logging events, session tracking setup, instrumentation examples, and an admin dashboard with event charts.
Create an analytics dashboard page with a dropdown filter at the top, three summary stat cards in a row, a bar chart in the middle, and a scrollable list of recent events at the bottom.
Frequently asked questions
How much does event logging cost in Firestore?
Each logged event is one Firestore write at approximately $0.18 per 100,000 writes. An app with 1,000 daily active users logging 10 events each generates 10,000 writes per day, costing about $0.54 per month.
Can I use this instead of Google Analytics or Firebase Analytics?
This custom system is best for app-specific events and custom dashboards. For standard analytics like user acquisition, retention, and demographics, Firebase Analytics is more appropriate. You can use both simultaneously.
How do I prevent event log data from growing too large?
Create a scheduled Cloud Function that deletes or archives event logs older than your retention period (e.g., 90 days). Export old data to BigQuery or CSV before deletion if you need historical analysis.
Can I track events from users who are not logged in?
Yes. Set the userId to 'anonymous' when no authenticated user exists. You can still track session-level behavior using the sessionId, which is generated regardless of auth status.
How do I create a funnel visualization from logged events?
Query events in sequence: count users who triggered event A, then of those, count who triggered event B, then event C. Display as a stacked bar chart or funnel Custom Widget showing drop-off between each step.
Can RapidDev help build advanced analytics for my app?
Yes. RapidDev can implement real-time analytics dashboards, funnel analysis, cohort tracking, A/B testing frameworks, BigQuery integration for large-scale analysis, and automated alerting on anomalous events.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation