# How to Create a Mental Health Tracking and Support App in FlutterFlow

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

## TL;DR

Build a mental health app with daily mood check-ins using five emoji faces on a 1-5 scale, optional activity tags via ChoiceChips, and free-text journal entries. Store mood_entries and journal_entries in Firestore with strict per-user security rules. Display mood trends over 7, 30, or 90 days using an fl_chart LineChart Custom Widget. Include a resource library with articles, exercises, and hotline information. Add a prominent Crisis Helpline button that launches tel:988 for immediate emergency access.

## Building a Mental Health Tracking and Support App in FlutterFlow

Mental health apps help users track their emotional state, identify patterns, and access support resources. This tutorial creates a complete mood tracking app with daily check-ins, journaling, trend visualization, and a resource library. Privacy is prioritized throughout with strict Firestore security rules ensuring users can only access their own data.

## Before you start

- A FlutterFlow project with Firestore and Firebase Authentication configured
- The fl_chart package added as a Custom Widget dependency
- Basic familiarity with FlutterFlow Action Flows and Backend Queries
- Understanding of Firestore Security Rules for data privacy

## Step-by-step guide

### 1. Set up the Firestore data model for mood and journal entries

Create a mood_entries collection with fields: userId (String), mood (Integer, 1-5 scale), note (String, optional), activities (String Array), timestamp (Timestamp). Create a journal_entries collection with: userId (String), title (String), body (String), mood (Integer, optional), isPrivate (Boolean, default true), timestamp (Timestamp). Create a resources collection with: title (String), type (String: 'article', 'exercise', 'hotline'), content (String), category (String), order (Integer). Add strict Firestore Security Rules: users can only create, read, update, and delete their own entries where resource.data.userId == request.auth.uid.

**Expected result:** Firestore has mood_entries, journal_entries, and resources collections with per-user security rules.

### 2. Build the daily mood check-in screen

Create a CheckInPage with a Column layout. Add a greeting Text ('How are you feeling today?', headlineMedium). Below, add a Row of five IconButtons representing mood levels: 1 (very sad face), 2 (sad face), 3 (neutral face), 4 (happy face), 5 (very happy face). Use Page State selectedMood to track the selection and highlight the selected emoji with a colored circular Container background. Below the emojis, add ChoiceChips for activities: Exercise, Sleep, Social, Work, Nature, Reading, Meditation. Add a TextField (multiline, 3 lines, hint: 'Add a note about your day...') for optional context. Finally, a Save Button that creates a mood_entries document with all values and navigates to the dashboard.

**Expected result:** A clean check-in screen lets users select their mood, tag activities, and save a daily entry.

### 3. Create the mood trend chart with fl_chart LineChart

Create a MoodChart Custom Widget using the fl_chart package. Accept parameters: moodData (List of JSON with mood and date). Render a LineChart with dates on the x-axis and mood (1-5) on the y-axis. Color the line with a gradient from red (1) through yellow (3) to green (5). Add dot indicators at each data point. On the dashboard page, query mood_entries for the current user, ordered by timestamp descending, limited by the selected time range (7, 30, or 90 days via ChoiceChips). Pass the query results to the MoodChart widget. Display the average mood as a Text below the chart.

```
// Custom Widget: MoodChart
import 'package:fl_chart/fl_chart.dart';

class MoodChart extends StatelessWidget {
  final List<Map<String, dynamic>> moodData;
  const MoodChart({required this.moodData});

  @override
  Widget build(BuildContext context) {
    final spots = moodData.asMap().entries.map((e) =>
      FlSpot(e.key.toDouble(), e.value['mood'].toDouble())
    ).toList();

    return LineChart(LineChartData(
      minY: 1, maxY: 5,
      gridData: FlGridData(show: true),
      titlesData: FlTitlesData(
        leftTitles: AxisTitles(sideTitles: SideTitles(
          showTitles: true, reservedSize: 30,
          getTitlesWidget: (v, _) => Text(
            ['', '😢', '😟', '😐', '😊', '😄'][v.toInt()],
            style: TextStyle(fontSize: 14)),
        )),
      ),
      lineBarsData: [LineChartBarData(
        spots: spots, isCurved: true,
        gradient: LinearGradient(
          colors: [Colors.red, Colors.amber, Colors.green]),
        dotData: FlDotData(show: true),
        belowBarData: BarAreaData(
          show: true,
          gradient: LinearGradient(
            colors: [Colors.green.withOpacity(0.1),
                     Colors.red.withOpacity(0.1)],
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter)),
      )],
    ));
  }
}
```

**Expected result:** A colored line chart displays mood trends over the selected time period with emoji labels on the y-axis.

### 4. Build the journaling feature with entry list and editor

Create a JournalPage with a Column: a header Row with Text ('Journal') and an Add IconButton. Below, a ListView with Backend Query on journal_entries filtered by userId == currentUser.uid, ordered by timestamp descending. Each row shows a Container with: title Text, first 100 characters of body as preview Text, mood emoji (if set), and timestamp. Tap a row to navigate to JournalDetailPage. Create a JournalEditorPage with: title TextField, body TextField (multiline, minLines: 10), optional mood selector (same 5 emoji Row), and Save Button. Save creates or updates a journal_entries document. Add a Delete action on the detail page with a confirmation dialog.

**Expected result:** Users can create, view, edit, and delete private journal entries with optional mood tagging.

### 5. Add the resource library and crisis helpline button

Create a ResourcesPage with a Column. At the very top, add a prominent Container with red background, white Text ('Crisis Helpline: 988'), and a phone Icon. On tap, use Launch URL action with 'tel:988' to dial the Suicide and Crisis Lifeline. Below, add ChoiceChips for resource categories: Articles, Exercises, Hotlines, All. Add a ListView with Backend Query on resources filtered by the selected category, ordered by the order field. Each resource row shows: type icon (article, exercise, phone), title Text, and a preview of content. Tap to open a ResourceDetailPage showing the full content.

**Expected result:** A resource library with categorized content and a prominent crisis helpline button accessible from the main navigation.

### 6. Build the dashboard tying everything together

Create a DashboardPage as the app home. Use a SingleChildScrollView with a Column. Add: a greeting Text with the user name and today date, the daily check-in prompt Container (tap navigates to CheckInPage, with Conditional Visibility hidden if already checked in today), the MoodChart Custom Widget with time range ChoiceChips (7/30/90 days), a Row of stat Containers (average mood this week, current streak of check-ins, total journal entries), and a 'Recent Journal Entries' horizontal ListView showing the last 3 entries. Add bottom navigation tabs: Dashboard, Check-In, Journal, Resources.

**Expected result:** A comprehensive dashboard showing mood trends, stats, and quick access to all features.

## Complete code example

File: `FlutterFlow Mental Health App Setup`

```text
FIRESTORE DATA MODEL:
  mood_entries/{docId}
    userId: String
    mood: Integer (1-5)
    note: String (optional)
    activities: [String]
    timestamp: Timestamp

  journal_entries/{docId}
    userId: String
    title: String
    body: String
    mood: Integer (optional)
    isPrivate: Boolean (default true)
    timestamp: Timestamp

  resources/{docId}
    title: String
    type: "article" | "exercise" | "hotline"
    content: String
    category: String
    order: Integer

FIRESTORE SECURITY RULES:
  match /mood_entries/{doc} {
    allow read, write: if request.auth.uid == resource.data.userId;
    allow create: if request.auth.uid == request.resource.data.userId;
  }
  match /journal_entries/{doc} {
    allow read, write: if request.auth.uid == resource.data.userId;
    allow create: if request.auth.uid == request.resource.data.userId;
  }

DASHBOARD PAGE:
  SingleChildScrollView > Column
    ├── Text (greeting + date)
    ├── Container (daily check-in prompt, if not done)
    ├── ChoiceChips (7 / 30 / 90 days)
    ├── MoodChart Custom Widget (fl_chart LineChart)
    ├── Row (stat cards: avg mood, streak, journal count)
    └── ListView.horizontal (recent journal entries)

CHECK-IN PAGE:
  Column
    ├── Text ("How are you feeling today?")
    ├── Row (5 emoji IconButtons, mood 1-5)
    ├── ChoiceChips (activities: Exercise, Sleep, Social...)
    ├── TextField (optional note)
    └── Button ("Save Check-In")

CRISIS HELPLINE:
  Container (red bg, always visible)
    Row: Icon(phone) + Text("Crisis Helpline: 988")
    On Tap: Launch URL → tel:988
```

## Common mistakes

- **Storing mood and journal data without strict per-user Firestore Security Rules** — Mental health data is extremely sensitive. Without rules, any authenticated user could query another user's mood entries and journal content. Fix: Add Firestore Security Rules requiring request.auth.uid == resource.data.userId for all read and write operations on mood_entries and journal_entries.
- **Burying the crisis helpline button in a submenu or settings page** — Users in crisis need immediate access. If the helpline button requires multiple taps to find, it fails its critical purpose. Fix: Place the crisis helpline button prominently at the top of the Resources page and consider adding it to the main dashboard as well.
- **Querying all mood entries without a date range limit for the chart** — A user with months of daily entries would load hundreds of documents, slowing the chart rendering and increasing Firestore read costs. Fix: Always filter mood_entries by timestamp within the selected range (7, 30, or 90 days) and limit the query accordingly.
- **Using local caching for mood data without encryption** — If someone gains access to the device, unencrypted local mood and journal data could be exposed. Fix: Enable Secure Persisted Fields in FlutterFlow for any locally cached sensitive data. Avoid storing full journal text in App State.

## Best practices

- Enforce per-user data isolation with Firestore Security Rules on all sensitive collections
- Make the crisis helpline button prominent and accessible from every main screen
- Limit chart data queries to the visible date range for performance
- Use Secure Persisted Fields for any locally cached mental health data
- Include both structured mood ratings and free-text journaling for comprehensive tracking
- Show activity correlation (which activities correlate with better moods) to provide actionable insights
- Add a daily check-in reminder via push notifications at a user-selected time

## Frequently asked questions

### Can I add guided meditation or breathing exercises to the app?

Yes. Add a 'guided_exercises' collection with audio URLs and step-by-step instructions. Use a custom audio player component or the built-in FlutterFlow audio player to play guided content. Timer-based breathing exercises can use a circular animation with countdown.

### How do I show users which activities correlate with better moods?

Query mood_entries with high mood scores (4-5) and aggregate the activities array. Compare against entries with low scores (1-2). Display the most common positive and negative activity correlations in a simple bar chart or ranked list on the dashboard.

### Is the mood data shared with anyone else?

No. Firestore Security Rules ensure each user can only access their own mood_entries and journal_entries. The rules check request.auth.uid against the document userId field for every read and write operation.

### Can I add therapist or counselor connectivity?

Yes. Add a 'providers' collection with therapist profiles and a messaging system. Users can share specific mood summaries (aggregated, not raw entries) with their therapist via a dedicated sharing action that creates a read-only copy.

### How do I handle the crisis helpline for international users?

Create a crisis_numbers collection with country and phone_number fields. Detect the user's locale or let them set their country in settings. Display the appropriate local crisis number. The International Association for Suicide Prevention maintains a directory of global helplines.

### Can RapidDev help build a complete mental health platform?

Yes. RapidDev can implement a full mental health platform including mood tracking, journaling, guided exercises, therapist connectivity, crisis resources, push notification reminders, and HIPAA-compliant data handling.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-create-a-mental-health-tracking-and-support-app-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-create-a-mental-health-tracking-and-support-app-in-flutterflow
