# How to Implement Sentiment Analysis on User Feedback in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 40-55 min
- Compatibility: FlutterFlow Pro+ (code export required for custom functions)
- Last updated: March 2026

## TL;DR

Sentiment analysis automatically scores user feedback as positive, negative, or neutral so you can prioritize what to fix. Connect a Cloud Function to Google Cloud Natural Language API's analyzeSentiment endpoint, store the score and magnitude in Firestore, then display trend charts in an admin dashboard. Set up alerts when the average sentiment score drops below a threshold.

## From raw feedback to actionable sentiment data

Star ratings tell you how happy users are in aggregate, but they don't tell you why. A 3-star review with 'checkout was confusing but products are great' contains two distinct signals. Google Cloud Natural Language API's analyzeSentiment endpoint returns a score (–1.0 to +1.0) and a magnitude (0 to infinity). Score indicates polarity; magnitude indicates how strongly the text expresses that emotion. A score of –0.8 with high magnitude means strongly negative and confident. By storing these values in Firestore alongside every feedback submission, you build a queryable sentiment history that powers admin charts, product prioritization, and automated alerts. The Cloud Function pattern keeps your API key server-side and adds analysis without changing your existing feedback submission flow.

## Before you start

- FlutterFlow project connected to Firebase with Firestore enabled
- Google Cloud project with Natural Language API enabled and a service account key
- Firebase Cloud Functions set up (firebase init functions in your project)
- An existing feedback collection in Firestore or a form to create one
- Basic familiarity with FlutterFlow Action Flows

## Step-by-step guide

### 1. Enable Google Cloud Natural Language API and get credentials

Go to console.cloud.google.com and select your project. In the search bar type 'Natural Language API' and click Enable. Next, go to APIs & Services → Credentials → Create Credentials → API Key. Copy the key. For production, restrict the key to the Natural Language API only by clicking Edit on the key and setting API restrictions. Store this key as a Firebase environment variable: in your terminal run 'firebase functions:config:set nlp.key=YOUR_API_KEY'. This keeps the key off the client and out of your codebase.

**Expected result:** Natural Language API shows as 'Enabled' in your Google Cloud console. API key is stored as a Firebase config variable.

### 2. Write a Cloud Function that analyzes sentiment and updates Firestore

Create a new Cloud Function that triggers when a document is written to your feedback collection. It reads the comment text, calls the Natural Language API, extracts the score and magnitude, then writes those values back to the same Firestore document. This is a Firestore onWrite trigger — it fires automatically every time a feedback document is created or updated, so you never need to call it manually from your app. Deploy with 'firebase deploy --only functions'.

```
// functions/index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const axios = require('axios');

admin.initializeApp();

exports.analyzeFeedbackSentiment = functions.firestore
  .document('feedback/{feedbackId}')
  .onCreate(async (snap, context) => {
    const data = snap.data();
    const text = data.comment;
    if (!text || text.trim().length === 0) return null;

    const apiKey = functions.config().nlp.key;
    const url = `https://language.googleapis.com/v1/documents:analyzeSentiment?key=${apiKey}`;

    try {
      const response = await axios.post(url, {
        document: { type: 'PLAIN_TEXT', content: text },
        encodingType: 'UTF8',
      });

      const sentiment = response.data.documentSentiment;
      const score = sentiment.score;       // -1.0 to +1.0
      const magnitude = sentiment.magnitude; // 0 to infinity

      // Classify for easy filtering
      let label = 'neutral';
      if (score >= 0.25) label = 'positive';
      if (score <= -0.25) label = 'negative';

      await snap.ref.update({
        sentiment_score: score,
        sentiment_magnitude: magnitude,
        sentiment_label: label,
        analyzed_at: admin.firestore.FieldValue.serverTimestamp(),
      });

      console.log(`Feedback ${context.params.feedbackId}: ${label} (${score})`);
      return null;
    } catch (error) {
      console.error('Sentiment analysis failed:', error.message);
      return null;
    }
  });
```

**Expected result:** After deploying, submit a test feedback document in Firestore. Within 5-10 seconds it should gain sentiment_score, sentiment_magnitude, sentiment_label, and analyzed_at fields.

### 3. Update the FlutterFlow feedback form to write to Firestore

In FlutterFlow, open your feedback page. Make sure it has a TextField for the comment and a Button to submit. In the Button's Action Flow, add a Firestore Create Document action targeting your 'feedback' collection. Map the TextField value to the 'comment' field. Also store the current user's UID (from Authenticated User → uid) and a timestamp (from Set from Variable → Current Time). You do NOT need to include sentiment fields — the Cloud Function populates those automatically after the document is created. Add a SnackBar action after the create action to show 'Thanks for your feedback!'.

**Expected result:** Submitting the form creates a new document in the feedback collection. The Cloud Function enriches it with sentiment data within seconds.

### 4. Build the admin sentiment dashboard with charts

Create a new page called 'Admin Dashboard' in FlutterFlow. Add a Backend Query at the page level that fetches all documents from the feedback collection, ordered by analyzed_at descending. Add three Count widgets showing the number of documents where sentiment_label equals 'positive', 'negative', and 'neutral' respectively — use Firestore Query conditions to filter. Add a Bar Chart widget: set the X axis to the submission date (grouped by day) and the Y axis to the average sentiment_score. Finally, add a ListView below the chart showing recent feedback cards with the comment text and a color-coded sentiment badge (green, red, neutral).

**Expected result:** Admin dashboard shows live counts of positive/negative/neutral feedback and a chart of sentiment over time, updating as new feedback arrives.

### 5. Add automated alerts when negative feedback spikes

Extend your Cloud Function to send an alert email when the rolling negative sentiment ratio exceeds a threshold. After writing the sentiment data back to Firestore, query the last 50 feedback documents and calculate the percentage that are 'negative'. If it exceeds 30%, send an alert using the Firebase Transactional Email extension or a simple SendGrid API call. Add a cooldown check by storing the last alert time in a Firestore config document so you don't flood your inbox.

```
// Add inside analyzeFeedbackSentiment, after the snap.ref.update() call:
const db = admin.firestore();
const recentDocs = await db.collection('feedback')
  .orderBy('analyzed_at', 'desc')
  .limit(50)
  .get();

const analyzed = recentDocs.docs.filter(d => d.data().sentiment_label);
const negCount = analyzed.filter(d => d.data().sentiment_label === 'negative').length;
const negRatio = negCount / analyzed.length;

if (negRatio > 0.30) {
  const configRef = db.doc('config/sentiment_alerts');
  const config = await configRef.get();
  const lastAlert = config.data()?.last_alert_at?.toMillis() || 0;
  const oneHour = 60 * 60 * 1000;

  if (Date.now() - lastAlert > oneHour) {
    // Send alert via your preferred email service
    console.warn(`ALERT: ${Math.round(negRatio * 100)}% negative sentiment in last 50 reviews`);
    await configRef.set({ last_alert_at: admin.firestore.FieldValue.serverTimestamp() }, { merge: true });
  }
}
```

**Expected result:** When 30%+ of recent feedback is negative, an alert is logged (or emailed) and a cooldown prevents repeated alerts within one hour.

## Complete code example

File: `functions/index.js`

```javascript
// Firebase Cloud Function: Sentiment Analysis on User Feedback
// Deploy: firebase deploy --only functions
// Config: firebase functions:config:set nlp.key=YOUR_GOOGLE_NLP_API_KEY

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const axios = require('axios');

admin.initializeApp();

exports.analyzeFeedbackSentiment = functions.firestore
  .document('feedback/{feedbackId}')
  .onCreate(async (snap, context) => {
    const data = snap.data();
    const text = data.comment;

    if (!text || text.trim().length < 3) return null;

    const apiKey = functions.config().nlp.key;
    const url =
      `https://language.googleapis.com/v1/documents:analyzeSentiment?key=${apiKey}`;

    try {
      const response = await axios.post(url, {
        document: { type: 'PLAIN_TEXT', content: text },
        encodingType: 'UTF8',
      });

      const { score, magnitude } = response.data.documentSentiment;

      let label = 'neutral';
      if (score >= 0.25) label = 'positive';
      if (score <= -0.25) label = 'negative';

      await snap.ref.update({
        sentiment_score: score,
        sentiment_magnitude: magnitude,
        sentiment_label: label,
        analyzed_at: admin.firestore.FieldValue.serverTimestamp(),
      });

      // Check for negative spike alert
      const db = admin.firestore();
      const recentDocs = await db.collection('feedback')
        .orderBy('analyzed_at', 'desc')
        .limit(50)
        .get();

      const analyzed = recentDocs.docs.filter(d => d.data().sentiment_label);
      if (analyzed.length >= 10) {
        const negCount = analyzed.filter(
          d => d.data().sentiment_label === 'negative'
        ).length;
        const negRatio = negCount / analyzed.length;

        if (negRatio > 0.30) {
          const configRef = db.doc('config/sentiment_alerts');
          const config = await configRef.get();
          const lastAlert = config.data()?.last_alert_at?.toMillis() || 0;
          const oneHour = 60 * 60 * 1000;

          if (Date.now() - lastAlert > oneHour) {
            console.warn(
              `SENTIMENT ALERT: ${Math.round(negRatio * 100)}% negative in last ${analyzed.length} reviews`
            );
            await configRef.set(
              { last_alert_at: admin.firestore.FieldValue.serverTimestamp() },
              { merge: true }
            );
          }
        }
      }

      return null;
    } catch (err) {
      console.error('Sentiment analysis error:', err.message);
      return null;
    }
  });
```

## Common mistakes

- **Using only star rating and ignoring text comment sentiment** — Star ratings are biased toward extremes — users rarely leave 2 or 4 stars. Text comments contain the actual reasons for dissatisfaction and specific feature mentions that stars cannot capture. Fix: Store and analyze both. Show star rating for quick trend, but surface low-magnitude high-score anomalies (e.g., sarcastic 5-star reviews) using the NLP score.
- **Calling the Natural Language API directly from the Flutter client** — The API key is visible in network requests and can be extracted from the app binary. Any user could use your key to rack up charges. Fix: Always call the NLP API from a Cloud Function. The Cloud Function has the key stored in firebase functions:config, which is never exposed to clients.
- **Not handling empty or very short feedback text** — The Natural Language API returns an error or meaningless results for strings shorter than 3-4 words. This causes the Cloud Function to fail and may leave documents in an un-analyzed state. Fix: Check text length before calling the API. If the comment is fewer than 3 words, set sentiment_label to 'insufficient_data' and skip the API call.
- **Building the admin dashboard with a large unindexed Firestore query** — Fetching all feedback documents without a limit and with compound filters (date range + label) will fail without a composite Firestore index and becomes slow at scale. Fix: Create composite indexes in the Firebase console for the fields you filter and sort on (sentiment_label + analyzed_at). Use pagination with a 50-item limit per page.

## Best practices

- Analyze sentiment asynchronously via Cloud Function trigger — never block the user's form submission waiting for NLP results
- Store raw score and magnitude alongside the label so you can adjust thresholds later without re-analyzing
- Segment sentiment by user cohort, feature area, or app version to identify which parts of your product drive negative feedback
- Use magnitude to filter out noise — a score of –0.1 with magnitude 0.2 is nearly neutral, not a real complaint
- Combine sentiment with session data (screens visited before submitting) to correlate UX pain points with negative text
- Review and re-label a sample of 50 results manually each month to verify the API's accuracy for your domain
- Set budget alerts on the Google Cloud Natural Language API — costs are $1 per 1,000 calls beyond the free tier

## Frequently asked questions

### How accurate is Google Cloud Natural Language API for sentiment analysis?

It's highly accurate for standard English text — typically 80-90% agreement with human raters on clear positive/negative content. Accuracy drops for short texts (under 10 words), industry-specific jargon, or sarcasm. Review a sample of your own data to confirm accuracy for your use case.

### What does 'magnitude' mean and when should I use it?

Magnitude measures how strongly sentiment is expressed, regardless of direction. Score of –0.9 with magnitude 3.0 means strongly and confidently negative. Score of –0.3 with magnitude 0.2 means slightly negative but the text is mostly factual. Use magnitude to filter out weak signals — only alert on high magnitude negative feedback.

### Can I use OpenAI instead of Google Cloud NLP for sentiment?

Yes. Send the feedback text to GPT-4 with a prompt like 'Classify this as positive, negative, or neutral and give a confidence score 0-1'. OpenAI gives more nuanced output but costs more per call and has higher latency. Google NLP is faster and cheaper for bulk sentiment classification.

### Does this work with non-English feedback?

Google Cloud Natural Language API supports 700+ languages for sentiment analysis. Pass the language code in the document object (e.g., language: 'es' for Spanish) or let the API auto-detect it. Auto-detection is reliable for texts over 20 words.

### How do I display a sentiment chart in FlutterFlow?

FlutterFlow has a built-in Chart widget. Add a Backend Query at the page level loading feedback documents grouped by day. Use a Bar Chart with the date on the X axis and average sentiment_score on the Y axis. For the color fill, set positive values to green and negative to red using conditional chart styling.

### What does it cost to analyze 1,000 feedback submissions per month?

Google Cloud Natural Language API has a free tier of 5,000 units per month. Beyond that, sentiment analysis is $1 per 1,000 records (each record up to 1,000 characters). 1,000 submissions per month falls within the free tier. 10,000 submissions would cost about $5/month.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-implement-sentiment-analysis-on-user-feedback-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-implement-sentiment-analysis-on-user-feedback-in-flutterflow
