# How to Integrate Environmental Sensors Data into a FlutterFlow App

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

## TL;DR

Integrate environmental sensor data into a FlutterFlow app by calling air quality APIs (OpenAQ, AirVisual, OpenWeatherMap Air Pollution) via a Cloud Function, or by receiving readings from custom IoT sensors through MQTT or HTTP. Store readings in Firestore sensor_readings collection and display with an AQI gauge (CircularPercentIndicator colored by health category), historical line chart, and map with color-coded markers. Always convert raw PM2.5 values to the AQI 0-500 scale with health category labels — never display raw sensor values to end users.

## Display real-time air quality and environmental data in your FlutterFlow app

Environmental monitoring apps display data like air quality index (AQI), PM2.5 particulate matter, temperature, humidity, CO2 levels, UV index, and noise levels. Data comes from two sources: public environmental APIs (OpenAQ, AirVisual, OpenWeatherMap) for city-level air quality, and custom IoT sensors (custom hardware, weather stations, industrial sensors) for specific location monitoring. Both sources follow the same pattern: fetch readings via a Cloud Function, store in Firestore with a timestamp, and display with appropriate visualizations. The most important user experience rule: convert scientific units (PM2.5 µg/m³) to the human-readable AQI scale (0-500) with color coding and health advisories.

## Before you start

- A FlutterFlow project connected to Firebase
- An AirVisual or OpenAQ API key (both have free tiers — sign up at iqair.com or openaq.org)
- Basic familiarity with Cloud Functions and FlutterFlow's API Manager

## Step-by-step guide

### 1. Fetch air quality data via a Cloud Function

Deploy a Cloud Function named getAirQuality. It accepts a city parameter and calls the AirVisual API: GET https://api.airvisual.com/v2/city?city={city}&state={state}&country={country}&key={API_KEY}. The response includes weather (temperature, humidity, wind) and pollution (aqiUS, aqiCN, p2 PM2.5, p1 PM10, o3 ozone, n2 NO2) objects. Store the API key in Cloud Function environment variables as AIRVISUAL_API_KEY. After fetching the current reading, write it to Firestore: air_quality_readings/{city.toLowerCase()} with: aqiUS (Integer), aqiCategory (String), p2 (Double, PM2.5), temperature (Double), humidity (Integer), fetchedAt (Timestamp). Return the same data to FlutterFlow. Register this Cloud Function in FlutterFlow's API Manager as an API Group with base URL https://us-central1-{projectId}.cloudfunctions.net and a getAirQuality API Call (POST, /getAirQuality, body: {"data": {"city": [city], "state": [state], "country": [country]}}).

```
// Cloud Function: getAirQuality
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const fetch = require('node-fetch');

exports.getAirQuality = functions.https.onCall(async (data, context) => {
  const { city, state, country } = data;
  const apiKey = process.env.AIRVISUAL_API_KEY;
  
  const url = `https://api.airvisual.com/v2/city?city=${encodeURIComponent(city)}` +
    `&state=${encodeURIComponent(state)}&country=${encodeURIComponent(country)}&key=${apiKey}`;
  
  const response = await fetch(url);
  const json = await response.json();
  
  if (json.status !== 'success') {
    throw new functions.https.HttpsError('not-found', `City not found: ${city}`);
  }
  
  const pollution = json.data.current.pollution;
  const weather = json.data.current.weather;
  
  const aqiUS = pollution.aqius;
  const aqiCategory = getAQICategory(aqiUS);
  
  const reading = {
    city,
    aqiUS,
    aqiCategory,
    pm25: pollution.p2?.conc || null,
    temperature: weather.tp,
    humidity: weather.hu,
    windSpeed: weather.ws,
    fetchedAt: admin.firestore.FieldValue.serverTimestamp()
  };
  
  // Cache in Firestore
  await admin.firestore().collection('air_quality_readings')
    .doc(city.toLowerCase().replace(/ /g, '_'))
    .set(reading, { merge: true });
  
  return reading;
});

function getAQICategory(aqi) {
  if (aqi <= 50) return 'Good';
  if (aqi <= 100) return 'Moderate';
  if (aqi <= 150) return 'Unhealthy for Sensitive Groups';
  if (aqi <= 200) return 'Unhealthy';
  if (aqi <= 300) return 'Very Unhealthy';
  return 'Hazardous';
}
```

**Expected result:** The Cloud Function returns AQI value, health category, PM2.5, temperature, and humidity for the requested city, and caches the result in Firestore.

### 2. Build the AQI gauge using CircularPercentIndicator

Add the percent_indicator Flutter package to your FlutterFlow project (Custom Code → Pubspec Dependencies: percent_indicator: ^4.2.3). Create a Custom Widget named AQIGauge. The widget takes: aqiValue (Integer, 0-500), aqiCategory (String). It renders a CircularPercentIndicator with: percent = aqiValue / 500 (normalized to 0.0-1.0), radius = 80, lineWidth = 15, center: Column with aqiValue as large bold text and aqiCategory as small text below. The progressColor and backgroundColor change based on the AQI range: Green (#4CAF50) for 0-50, Yellow (#FFEB3B) for 51-100, Orange (#FF9800) for 101-150, Red (#F44336) for 151-200, Purple (#9C27B0) for 201-300, Maroon (#7D1B1B) for 301-500. Add the AQIGauge widget to your dashboard page and pass in the aqiUS and aqiCategory values from the Backend Query bound to the Firestore air_quality_readings document.

**Expected result:** An AQI gauge widget displays the air quality index with appropriate color coding and health category label.

### 3. Add historical data chart and location map

For historical trends: add a Firestore subcollection air_quality_readings/{city}/hourly_history with documents written every hour by a scheduled Cloud Function (Cloud Scheduler triggers the getAirQuality function for configured cities hourly). On the dashboard page, add a Backend Query for the hourly_history subcollection ordered by fetchedAt descending, limit 24. Add a Custom Widget using fl_chart LineChart: x-axis shows the last 24 hours, y-axis shows AQI values 0-500 with horizontal threshold lines at 50, 100, 150, 200 (the category boundaries). Plot the AQI values as a line. Color the area under the line using the gradient matching the AQI scale. For the map: add a FlutterFlowGoogleMap widget with marker pins for each monitored city. Use a Custom Function to map aqiUS to a marker color matching the AQI scale — green pins for Good, yellow for Moderate, orange for Unhealthy for Sensitive Groups, red for Unhealthy. Tap a marker to show a popup with that city's current AQI and category.

**Expected result:** The dashboard shows a 24-hour AQI trend line chart and a map with color-coded markers for all monitored cities.

### 4. Handle custom IoT sensor data via MQTT or HTTP webhook

For custom environmental sensors (DIY weather stations, industrial air quality monitors, smart agriculture sensors) that send their own data: Option 1 — HTTP POST webhook: configure the sensor or its gateway to POST readings to a Cloud Function URL. The Cloud Function validates the sensor's API key (stored in Firestore sensor_registry/{sensorId}), parses the payload (metric, value, unit, lat, lng), and writes to Firestore sensor_readings/{sensorId}/readings. Option 2 — MQTT: deploy an MQTT broker (AWS IoT Core, HiveMQ) and configure the sensor to publish to topics like sensors/{sensorId}/readings. A Cloud Function subscribes to the MQTT topic or a PubSub topic connected to AWS IoT and writes readings to Firestore. In FlutterFlow, use a real-time Backend Query on sensor_readings/{sensorId}/readings ordered by timestamp to show live sensor data as it arrives.

**Expected result:** Custom IoT sensor readings appear in real time in the FlutterFlow dashboard within 5 seconds of the sensor transmitting data.

## Complete code example

File: `environmental_sensors_architecture.txt`

```text
ENVIRONMENTAL SENSOR INTEGRATION IN FLUTTERFLOW

DATA SOURCES:
├── OpenAQ (free, 90+ countries)
│   └── GET https://api.openaq.org/v2/measurements
│       └── Params: city, parameter (pm25, pm10, o3, no2)
├── AirVisual (free tier: 10k calls/month)
│   └── GET https://api.airvisual.com/v2/city
│       └── Returns: AQI (US+CN), PM2.5, weather
├── OpenWeatherMap Air Pollution (free)
│   └── GET api.openweathermap.org/data/2.5/air_pollution
│       └── Params: lat, lon
└── Custom IoT: HTTP POST or MQTT → Cloud Function

FIRESTORE STRUCTURE:
├── air_quality_readings/{city}
│   ├── aqiUS: Integer (0-500)
│   ├── aqiCategory: String
│   ├── pm25: Double
│   ├── temperature: Double
│   ├── humidity: Integer
│   └── fetchedAt: Timestamp
│   └── hourly_history/{docId}
│       └── (same fields + timestamp)
└── sensor_readings/{sensorId}/readings/{readingId}
    ├── metric: 'pm25' | 'temperature' | 'co2' | 'humidity'
    ├── value: Double
    ├── unit: 'µg/m³' | '°C' | 'ppm' | '%'
    └── timestamp: Timestamp

AQI COLOR SCALE:
├── 0-50:   Good              → #4CAF50 (green)
├── 51-100: Moderate          → #FFEB3B (yellow)
├── 101-150: Unhealthy (Sensitive) → #FF9800 (orange)
├── 151-200: Unhealthy        → #F44336 (red)
├── 201-300: Very Unhealthy   → #9C27B0 (purple)
└── 301-500: Hazardous        → #7D1B1B (maroon)

FLUTTERFLOW UI:
├── AQIGauge Custom Widget (CircularPercentIndicator)
│   └── percent = aqiUS / 500, color by range
├── fl_chart LineChart (24h history)
│   └── Backend Query: hourly_history, limit 24
├── FlutterFlowGoogleMap
│   └── Marker pins colored by AQI range
└── Alert Container (visible if aqiUS > 150)
    └── 'Air quality is unhealthy. Limit outdoor activity.'
```

## Common mistakes

- **Displaying raw PM2.5 values (e.g., 35.2 µg/m³) directly to users without converting to AQI** — PM2.5 concentration in micrograms per cubic meter is a scientific unit that means nothing to most users. A reading of 35 µg/m³ sounds low but is classified as Unhealthy for Sensitive Groups on the AQI scale. Users cannot make informed health decisions without the AQI context. Fix: Always convert PM2.5 to the AQI index (0-500 scale) using the EPA conversion formula and display with health category labels and color coding. Show 'Moderate (AQI: 85)' not '18.5 µg/m³'. Add a health advisory text like 'Unusually sensitive people should consider reducing prolonged outdoor exertion.'
- **Fetching air quality data from the API on every app open or page navigation** — Air quality values update every 1-4 hours in most public APIs. Fetching on every page load wastes API quota (free tier: typically 10,000 calls/month on AirVisual) and slows down the app with unnecessary network requests. Fix: Cache the latest reading in Firestore with a fetchedAt timestamp. In the Cloud Function, check if the cached reading is less than 30 minutes old before calling the external API — if so, return the cached Firestore data instead. The FlutterFlow Backend Query reads from Firestore (fast, no API cost) and the Cloud Function only calls the external API when the cache is stale.
- **Polling a custom IoT sensor's HTTP endpoint directly from the FlutterFlow app** — IoT sensors often have low-bandwidth connections, restrictive firewalls, or dynamically changing IP addresses. Polling from multiple users' devices creates unnecessary sensor load and fails when the sensor is not directly reachable from the internet. Fix: Configure the sensor to push data to a Cloud Function HTTP endpoint (the sensor initiates the connection, not the app). The Cloud Function writes to Firestore. FlutterFlow reads from Firestore with a real-time listener. This decouples the sensor network from the user-facing app.

## Best practices

- Always convert raw sensor values (PM2.5, PM10, O3) to the AQI 0-500 scale with health category labels before displaying to users
- Cache air quality readings in Firestore with a fetchedAt timestamp and only refresh from the external API when the cache is older than 30 minutes
- Use the EPA AQI color scale consistently — green (Good), yellow (Moderate), orange (Unhealthy for Sensitive), red (Unhealthy), purple (Very Unhealthy), maroon (Hazardous)
- Add threshold alerts: when AQI exceeds 150 (Unhealthy), trigger a local notification advising users to limit outdoor activity
- Store hourly historical readings in a Firestore subcollection for trend visualization — delete readings older than 30 days with a scheduled Cloud Function to control storage costs
- Show the data source and last-updated timestamp on the dashboard so users know when the reading was captured
- Use Cloud Scheduler to fetch air quality data for popular cities on a schedule rather than on-demand — pre-populate Firestore so app loads are instant

## Frequently asked questions

### How do I display environmental sensor data in a FlutterFlow app?

Deploy a Cloud Function that calls an air quality API (AirVisual, OpenAQ, or OpenWeatherMap Air Pollution) and stores the result in Firestore. In FlutterFlow, add a Backend Query to fetch from Firestore and bind the AQI value, health category, temperature, and humidity fields to Text widgets. For visualization, add a Custom Widget using CircularPercentIndicator for the AQI gauge and fl_chart for historical trends.

### What is the best API for air quality data in FlutterFlow apps?

AirVisual (IQAir) is the most popular for consumer apps: free tier with 10,000 API calls per month, covers 10,000+ cities worldwide, returns US AQI, PM2.5, temperature, and humidity in one call. OpenAQ is better for research and open data needs — it aggregates government monitoring stations and is completely free with no key required for basic usage. OpenWeatherMap Air Pollution API is a good option if you already use OpenWeatherMap for weather data.

### How do I convert PM2.5 to AQI in my FlutterFlow app?

AirVisual's API returns the AQI value (aqius for US AQI) directly — no conversion needed. If you receive raw PM2.5 in µg/m³ from another source, the US EPA conversion formula uses breakpoints: 0-12 µg/m³ = AQI 0-50 (Good), 12.1-35.4 = AQI 51-100 (Moderate), 35.5-55.4 = AQI 101-150 (Unhealthy for Sensitive Groups), 55.5-150.4 = AQI 151-200 (Unhealthy). Create a Custom Function with these breakpoints to convert PM2.5 to AQI.

### Can I integrate a custom air quality sensor (not a commercial API) with FlutterFlow?

Yes. Configure your sensor or sensor gateway to POST data to a Cloud Function HTTP endpoint whenever a new reading is available. The Cloud Function validates the request, parses the sensor data payload, and writes to Firestore sensor_readings/{sensorId}/readings. FlutterFlow uses a real-time Backend Query on this collection to display live data as it arrives. This pattern works for any sensor that can make HTTP requests — most modern IoT sensors and gateways support HTTP webhooks.

### How do I add health advisories to my AQI display?

Create a Custom Function in FlutterFlow named getAQIAdvisory that takes an aqiValue integer and returns the appropriate advisory text. Use the EPA's standard language: 0-50: 'Air quality is satisfactory, and air pollution poses little or no risk.' 51-100: 'Air quality is acceptable. However, there may be a risk for some people.' 101-150: 'Members of sensitive groups may experience health effects. The general public is less likely to be affected.' 151-200: 'Some members of the general public may experience health effects; members of sensitive groups may experience more serious health effects.' Show this text below the AQI gauge and change the text color to match the AQI category color.

### What if I need a custom environmental monitoring solution built for my FlutterFlow app?

A production environmental monitoring app typically requires multiple data sources, custom sensor integration, alert systems, historical analytics, and multi-location management. RapidDev has built IoT and sensor data visualization apps in FlutterFlow including real-time dashboards, alert systems, and custom sensor integrations via MQTT and HTTP webhooks. If your project requires going beyond a standard API integration, professional development support ensures reliable data delivery and visualization.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-integrate-environmental-sensors-data-into-a-flutterflow-app
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-integrate-environmental-sensors-data-into-a-flutterflow-app
