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.
Prerequisites
- 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
Fetch air quality data via a Cloud Function
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]}}).
1// Cloud Function: getAirQuality2const functions = require('firebase-functions');3const admin = require('firebase-admin');4const fetch = require('node-fetch');56exports.getAirQuality = functions.https.onCall(async (data, context) => {7 const { city, state, country } = data;8 const apiKey = process.env.AIRVISUAL_API_KEY;9 10 const url = `https://api.airvisual.com/v2/city?city=${encodeURIComponent(city)}` +11 `&state=${encodeURIComponent(state)}&country=${encodeURIComponent(country)}&key=${apiKey}`;12 13 const response = await fetch(url);14 const json = await response.json();15 16 if (json.status !== 'success') {17 throw new functions.https.HttpsError('not-found', `City not found: ${city}`);18 }19 20 const pollution = json.data.current.pollution;21 const weather = json.data.current.weather;22 23 const aqiUS = pollution.aqius;24 const aqiCategory = getAQICategory(aqiUS);25 26 const reading = {27 city,28 aqiUS,29 aqiCategory,30 pm25: pollution.p2?.conc || null,31 temperature: weather.tp,32 humidity: weather.hu,33 windSpeed: weather.ws,34 fetchedAt: admin.firestore.FieldValue.serverTimestamp()35 };36 37 // Cache in Firestore38 await admin.firestore().collection('air_quality_readings')39 .doc(city.toLowerCase().replace(/ /g, '_'))40 .set(reading, { merge: true });41 42 return reading;43});4445function getAQICategory(aqi) {46 if (aqi <= 50) return 'Good';47 if (aqi <= 100) return 'Moderate';48 if (aqi <= 150) return 'Unhealthy for Sensitive Groups';49 if (aqi <= 200) return 'Unhealthy';50 if (aqi <= 300) return 'Very Unhealthy';51 return 'Hazardous';52}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.
Build the AQI gauge using CircularPercentIndicator
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.
Add historical data chart and location map
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.
Handle custom IoT sensor data via MQTT or HTTP webhook
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 working example
1ENVIRONMENTAL SENSOR INTEGRATION IN FLUTTERFLOW23DATA SOURCES:4├── OpenAQ (free, 90+ countries)5│ └── GET https://api.openaq.org/v2/measurements6│ └── Params: city, parameter (pm25, pm10, o3, no2)7├── AirVisual (free tier: 10k calls/month)8│ └── GET https://api.airvisual.com/v2/city9│ └── Returns: AQI (US+CN), PM2.5, weather10├── OpenWeatherMap Air Pollution (free)11│ └── GET api.openweathermap.org/data/2.5/air_pollution12│ └── Params: lat, lon13└── Custom IoT: HTTP POST or MQTT → Cloud Function1415FIRESTORE STRUCTURE:16├── air_quality_readings/{city}17│ ├── aqiUS: Integer (0-500)18│ ├── aqiCategory: String19│ ├── pm25: Double20│ ├── temperature: Double21│ ├── humidity: Integer22│ └── fetchedAt: Timestamp23│ └── hourly_history/{docId}24│ └── (same fields + timestamp)25└── sensor_readings/{sensorId}/readings/{readingId}26 ├── metric: 'pm25' | 'temperature' | 'co2' | 'humidity'27 ├── value: Double28 ├── unit: 'µg/m³' | '°C' | 'ppm' | '%'29 └── timestamp: Timestamp3031AQI COLOR SCALE:32├── 0-50: Good → #4CAF50 (green)33├── 51-100: Moderate → #FFEB3B (yellow)34├── 101-150: Unhealthy (Sensitive) → #FF9800 (orange)35├── 151-200: Unhealthy → #F44336 (red)36├── 201-300: Very Unhealthy → #9C27B0 (purple)37└── 301-500: Hazardous → #7D1B1B (maroon)3839FLUTTERFLOW UI:40├── AQIGauge Custom Widget (CircularPercentIndicator)41│ └── percent = aqiUS / 500, color by range42├── fl_chart LineChart (24h history)43│ └── Backend Query: hourly_history, limit 2444├── FlutterFlowGoogleMap45│ └── Marker pins colored by AQI range46└── Alert Container (visible if aqiUS > 150)47 └── 'Air quality is unhealthy. Limit outdoor activity.'Common mistakes
Why it's a problem: Displaying raw PM2.5 values (e.g., 35.2 µg/m³) directly to users without converting to AQI
How to avoid: 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.'
Why it's a problem: Fetching air quality data from the API on every app open or page navigation
How to avoid: 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.
Why it's a problem: Polling a custom IoT sensor's HTTP endpoint directly from the FlutterFlow app
How to avoid: 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
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am building a FlutterFlow app that displays real-time air quality data. I want to use the AirVisual API to get AQI values and PM2.5 readings for cities that users search. Explain: (1) how to call the AirVisual API from a Cloud Function and cache the result in Firestore, (2) how to convert PM2.5 to the AQI 0-500 index, (3) what colors and health category labels correspond to each AQI range, and (4) how to display the AQI with a circular gauge widget in FlutterFlow.
Create an environmental monitoring dashboard page in my FlutterFlow app. The page should: (1) show a search TextField for city name, (2) call my getAirQuality Cloud Function API when the user submits a city, (3) display the AQI value in a large bold number with a health category label below it, (4) show temperature and humidity in smaller text, (5) display a color-coded Container background matching the AQI category (green/yellow/orange/red/purple/maroon), and (6) show a health advisory message when AQI is above 100.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation