# How to Build a Customizable Dashboard for Analytics in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 30-40 min
- Compatibility: FlutterFlow Free+
- Last updated: March 2026

## TL;DR

Build an admin analytics dashboard with KPI metric cards showing value, trend arrow, and percentage change in a GridView. Below, display a LineChart for trends over time, a PieChart for traffic source breakdown, and a BarChart for top-performing items using fl_chart Custom Widgets. All data comes from a pre-computed analytics_daily collection populated by a scheduled Cloud Function. Date range ChoiceChips let users filter between Today, 7 days, 30 days, and 90 days, re-querying the collection by date range.

## Building an Admin Analytics Dashboard in FlutterFlow

This tutorial creates an analytics dashboard for app administrators to monitor key metrics at a glance. Instead of aggregating raw data on every page load, a Cloud Function pre-computes daily metrics and stores them in a dedicated Firestore collection. The dashboard reads this pre-computed data to display KPI cards, trend charts, and breakdowns instantly. Date range filtering lets admins zoom in on recent performance or view long-term trends. This pattern is used for business intelligence, marketing dashboards, SaaS admin panels, and internal reporting tools.

## Before you start

- A FlutterFlow project with Firestore configured
- Firebase Cloud Functions enabled (Blaze plan) for data pre-computation
- Familiarity with Custom Widgets in FlutterFlow
- The fl_chart Flutter package added to the project

## Step-by-step guide

### 1. Set up the pre-computed analytics Firestore collection

Create an analytics_daily collection with document IDs formatted as YYYY-MM-DD. Each document has fields: date (String), totalUsers (int), newUsers (int), revenue (double), pageViews (int), conversionRate (double, 0-100), topPages (array of Maps with page and views), trafficSources (Map with keys like direct, organic, social, referral, each mapping to a count). Create a scheduled Cloud Function that runs daily at midnight. The function aggregates data from your users, orders, and page_views collections for the previous day and writes or updates the analytics_daily document. Seed 30 days of sample data for development.

```
// Cloud Function: computeDailyAnalytics (scheduled daily)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.computeDailyAnalytics = functions.pubsub
  .schedule('0 0 * * *')
  .onRun(async () => {
    const yesterday = new Date();
    yesterday.setDate(yesterday.getDate() - 1);
    const dateStr = yesterday.toISOString().split('T')[0];
    const start = admin.firestore.Timestamp.fromDate(
      new Date(dateStr + 'T00:00:00Z')
    );
    const end = admin.firestore.Timestamp.fromDate(
      new Date(dateStr + 'T23:59:59Z')
    );

    const usersSnap = await admin.firestore().collection('users')
      .where('createdAt', '>=', start).where('createdAt', '<=', end).get();
    const ordersSnap = await admin.firestore().collection('orders')
      .where('createdAt', '>=', start).where('createdAt', '<=', end).get();

    let revenue = 0;
    ordersSnap.docs.forEach(d => revenue += d.data().total || 0);

    await admin.firestore().collection('analytics_daily').doc(dateStr).set({
      date: dateStr,
      totalUsers: (await admin.firestore().collection('users').get()).size,
      newUsers: usersSnap.size,
      revenue: Math.round(revenue * 100) / 100,
      pageViews: Math.floor(Math.random() * 5000) + 1000,
      conversionRate: ordersSnap.size > 0
        ? Math.round((ordersSnap.size / usersSnap.size) * 10000) / 100 : 0,
      trafficSources: { direct: 40, organic: 30, social: 20, referral: 10 },
      topPages: [
        { page: '/home', views: 1200 },
        { page: '/products', views: 800 },
        { page: '/pricing', views: 450 },
      ],
    });
  });
```

**Expected result:** A daily Cloud Function populates analytics_daily documents with pre-computed metrics.

### 2. Build the KPI cards row with trend indicators

Create a DashboardPage. Add Page State: selectedRange (String, default '7d'). Query analytics_daily documents for the selected date range. At the top, display 4 KPI cards in a responsive GridView (2 columns on mobile, 4 on desktop). Each card shows: the metric label (Total Users, Revenue, Page Views, Conversion Rate), the current value in large text, a trend arrow icon (up green or down red), and the percentage change compared to the previous period. Calculate percentage change by comparing the sum of the current range to the same-length previous range. Use a Custom Function for the comparison.

**Expected result:** Four KPI cards display with current values, trend arrows, and percentage changes.

### 3. Create the LineChart Custom Widget for trend visualization

Create a Custom Widget called TrendLineChart that accepts a List of data points (date and value pairs). Use the fl_chart package to render a LineChart with the x-axis showing dates and the y-axis showing the metric value. Add gradient fill below the line, dot markers on data points, and tooltip on touch showing the exact value and date. Wrap the widget in a Container with an explicit height of 250 pixels. On the dashboard, bind this widget to the daily revenue or pageViews data from the analytics_daily query results.

**Expected result:** A smooth line chart shows metric trends over the selected date range with interactive tooltips.

### 4. Add PieChart and BarChart for breakdowns

Create a PieChart Custom Widget for traffic source breakdown. Accept a Map of source names to counts. Render colored pie sections with labels and percentages. Wrap in a 250px height Container. Create a BarChart Custom Widget for top pages. Accept a List of page name and view count pairs. Render horizontal bars with page names on the y-axis and view counts on the x-axis. Place both charts in a Row on desktop (side by side) or Column on mobile (stacked) using Responsive Layout. Bind the PieChart to the aggregated trafficSources data and the BarChart to the topPages array.

**Expected result:** A pie chart shows traffic source distribution and a bar chart shows top-performing pages.

### 5. Add date range filtering with ChoiceChips

Above the KPI cards, add ChoiceChips with options: Today, 7d, 30d, 90d. When the user selects a range, update Page State selectedRange and recalculate the date boundaries. For Today, query the single document with today's date. For 7d, query documents where date >= 7 days ago. For 30d and 90d, extend accordingly. All KPI values, charts, and breakdowns update based on the new query results. Add a RefreshIndicator wrapping the entire scroll view for manual refresh. Show a last-updated timestamp at the top right from the most recent document's date.

**Expected result:** Selecting a date range updates all dashboard cards and charts to reflect the chosen time period.

## Complete code example

File: `FlutterFlow Analytics Dashboard Setup`

```text
FIRESTORE DATA MODEL:
  analytics_daily/{YYYY-MM-DD}
    date: String
    totalUsers: int
    newUsers: int
    revenue: double
    pageViews: int
    conversionRate: double
    trafficSources: { direct: 40, organic: 30, social: 20, referral: 10 }
    topPages: [
      { page: "/home", views: 1200 },
      { page: "/products", views: 800 }
    ]

PAGE: DashboardPage
  Page State: selectedRange (String, default '7d')
  Backend Query: analytics_daily where date >= rangeStart, orderBy date asc

  WIDGET TREE:
    RefreshIndicator
      SingleChildScrollView
        Column
          ├── Row
          │     ├── Text ("Dashboard")
          │     └── Text ("Last updated: date")
          ├── ChoiceChips (Today / 7d / 30d / 90d)
          │     On Change: update selectedRange → re-query
          ├── GridView (crossAxisCount: 2 mobile / 4 desktop)
          │     └── KPI Card (×4)
          │           Container
          │             ├── Text (label: "Total Users")
          │             ├── Text (value: "12,450", large)
          │             └── Row
          │                   ├── Icon (arrow_up green / arrow_down red)
          │                   └── Text ("+12.3%")
          ├── Container (height: 250)
          │     └── Custom Widget: TrendLineChart
          │           data: daily revenue or pageViews
          └── Responsive Row/Column
                ├── Container (height: 250)
                │     └── Custom Widget: PieChart
                │           data: aggregated trafficSources
                └── Container (height: 250)
                      └── Custom Widget: BarChart
                            data: aggregated topPages

KPI CHANGE CALCULATION:
  currentSum = sum of metric for selected range
  previousSum = sum of metric for same-length preceding range
  change = ((currentSum - previousSum) / previousSum) * 100
  Arrow: green up if positive, red down if negative
```

## Common mistakes

- **Not setting explicit height on chart Containers** — The fl_chart package throws a 'RenderBox was not laid out' error when its parent Container has unconstrained height. The chart cannot determine how tall to render. Fix: Always wrap fl_chart widgets in a Container with an explicit height, typically 200-300 pixels.
- **Aggregating raw data on every dashboard page load** — Counting all users, summing all orders, and scanning all page views on each load consumes thousands of Firestore reads and makes the dashboard slow. Fix: Pre-compute daily aggregates in a scheduled Cloud Function and store them in analytics_daily. The dashboard reads only pre-computed documents.
- **Hardcoding metric values instead of calculating percentage change dynamically** — Static trend indicators give admins false confidence. The dashboard shows 'up 12%' even when the real trend is declining. Fix: Calculate percentage change by comparing the current range sum to the equivalent previous range sum using a Custom Function.

## Best practices

- Pre-compute analytics in a scheduled Cloud Function to minimize client-side Firestore reads
- Set explicit height on every Container wrapping an fl_chart widget
- Use responsive GridView columns: 2 on mobile, 4 on desktop for KPI cards
- Show trend arrows and percentage changes so admins see direction at a glance
- Add a last-updated timestamp so admins know data freshness
- Use date-formatted document IDs (YYYY-MM-DD) for efficient range queries
- Include a pull-to-refresh so admins can manually reload without navigating away

## Frequently asked questions

### Why pre-compute analytics instead of querying live data?

Live aggregation scans every document on each page load, consuming thousands of Firestore reads and making the dashboard slow. Pre-computation runs once daily, and the dashboard reads a few dozen lightweight documents.

### How do I add real-time updates to the dashboard?

For real-time KPIs like active users, use a separate Firestore document updated by Cloud Functions on every relevant event. Set Single Time Query to OFF on that document so it updates live. Keep historical charts on the pre-computed daily data.

### Can I export dashboard data to CSV?

Yes. Create a Custom Action that reads the analytics_daily documents, formats the data as CSV rows, and triggers a file download using the dart:html library for web or writes to a temporary file for mobile.

### How do I add custom date range selection beyond the preset options?

Add a Custom Range option to the ChoiceChips. When selected, show two DateTimePickers for start and end dates. Use those dates to query analytics_daily documents within the custom range.

### What if I have more than 90 days of data?

For longer ranges, consider aggregating into weekly or monthly summary documents to reduce the number of documents queried. A weekly_analytics collection with 52 documents covers a full year efficiently.

### Can RapidDev help build a comprehensive analytics platform?

Yes. RapidDev can build custom analytics dashboards with real-time metrics, cohort analysis, funnel visualization, user segmentation, and data export to spreadsheets or BI tools.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-build-a-customizable-dashboard-for-analytics-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-build-a-customizable-dashboard-for-analytics-in-flutterflow
