Build a community weather app where users submit local weather reports with their current GPS location, selected condition (sunny, cloudy, rainy, snowy, stormy), optional temperature and photo, stored in Firestore with a geoHash for proximity queries. A Google Map displays reports as condition-colored markers. A feed view shows nearby reports using geoHash prefix matching. A Cloud Function computes hourly area averages that complement official weather API data.
Building a Crowd-Sourced Weather Reporting App in FlutterFlow
Official weather data comes from distant stations and satellites. Crowd-sourced reports capture hyperlocal conditions in real time: what is actually happening at a specific street corner right now. This tutorial builds a community reporting system with GPS-located submissions, a map visualization with condition-colored markers, proximity-based feeds, and Cloud Function aggregation.
Prerequisites
- A FlutterFlow project with Firestore, Firebase Storage, and Google Maps configured
- Google Maps API key added in FlutterFlow project settings
- Understanding of FlutterFlowGoogleMap widget and Custom Actions
- Location permissions configured for iOS and Android
Step-by-step guide
Design the Firestore data model with geoHash for proximity queries
Design the Firestore data model with geoHash for proximity queries
Create a weather_reports collection with fields: userId (String), lat (double), lng (double), geoHash (String, computed from lat/lng), condition (String: sunny, cloudy, rainy, snowy, stormy), temperature (double, optional, user-estimated or from device sensor), description (String, optional freeform note), photoUrl (String, optional), timestamp (Timestamp). The geoHash field is critical: it encodes latitude and longitude into a single sortable string that enables proximity queries. Use a Custom Function or Cloud Function to compute geoHash at precision 5, which gives roughly 2.4km accuracy.
1// Custom Function: computeGeoHash2String computeGeoHash(double lat, double lng, {int precision = 5}) {3 const base32 = '0123456789bcdefghjkmnpqrstuvwxyz';4 double minLat = -90, maxLat = 90;5 double minLng = -180, maxLng = 180;6 bool isLng = true;7 int bit = 0;8 int hashValue = 0;9 String hash = '';1011 while (hash.length < precision) {12 double mid = isLng13 ? (minLng + maxLng) / 214 : (minLat + maxLat) / 2;15 double val = isLng ? lng : lat;16 if (val >= mid) {17 hashValue = (hashValue << 1) + 1;18 if (isLng) minLng = mid; else minLat = mid;19 } else {20 hashValue = hashValue << 1;21 if (isLng) maxLng = mid; else maxLat = mid;22 }23 isLng = !isLng;24 bit++;25 if (bit == 5) {26 hash += base32[hashValue];27 bit = 0;28 hashValue = 0;29 }30 }31 return hash;32}Expected result: Firestore has a weather_reports collection with geoHash field enabling proximity-based queries.
Build the weather report submission form
Build the weather report submission form
Create a SubmitReport page. On page load, trigger a Custom Action using the geolocator package to get the current GPS coordinates and store them in Page State variables currentLat and currentLng. Display a GridView of weather condition icons: sun for sunny (yellow), cloud for cloudy (grey), rain drops for rainy (blue), snowflake for snowy (light blue), lightning for stormy (red). Users tap one to select. Add an optional temperature TextField (number keyboard), an optional description TextField, and an optional FlutterFlowUploadButton for a photo. On Submit, compute the geoHash from lat/lng, create the weather_reports document, and show a success SnackBar.
Expected result: Users submit weather reports with their current location, selected condition, and optional temperature and photo.
Display reports as condition-colored markers on Google Maps
Display reports as condition-colored markers on Google Maps
Create a MapView page with a FlutterFlowGoogleMap widget. Query weather_reports from the last 4 hours to keep data fresh. For each report, create a map marker with position set to lat/lng and color based on condition: yellow for sunny, grey for cloudy, blue for rainy, light blue for snowy, red for stormy. The marker info window shows the condition, temperature if present, time ago, and a thumbnail of the photo if uploaded. On map load, center on the user's current location. Users can zoom out to see regional patterns.
Expected result: A Google Map displays recent weather reports as color-coded markers showing conditions across the area.
Build a nearby reports feed using geoHash prefix queries
Build a nearby reports feed using geoHash prefix queries
Create a FeedView page showing recent reports near the user. Get the user's current geoHash at precision 4 (wider area, approximately 20km). Query weather_reports where geoHash starts with this 4-character prefix using Firestore range query: geoHash >= prefix AND geoHash < prefix + next character. This returns all reports in the surrounding area. Display in a ListView ordered by timestamp descending, each row showing: condition icon, temperature, description excerpt, time ago, distance from user (calculated with Haversine formula Custom Function), and photo thumbnail if present.
Expected result: A feed shows nearby weather reports sorted by recency with distance indicators.
Aggregate reports into area averages with a Cloud Function
Aggregate reports into area averages with a Cloud Function
Create a scheduled Cloud Function that runs every hour. It queries all weather_reports from the last hour, groups them by geoHash prefix at precision 3 (approximately 78km areas), and for each area calculates: most common condition (mode), average temperature, and report count. Store these aggregates in a weather_aggregates collection: geoHash3 (String), avgTemperature (double), dominantCondition (String), reportCount (int), aggregatedAt (Timestamp). Display these on the map as larger area summary markers when the user is zoomed out.
Expected result: Hourly area averages computed from community reports provide regional weather summaries.
Complement crowd data with official weather API data
Complement crowd data with official weather API data
Add an optional official weather comparison. Create an API Group call to OpenWeatherMap using the user's coordinates. Display the official temperature and condition alongside community data in a comparison card: Official says 22 degrees and Sunny, Community reports 24 degrees and Partly Cloudy (from 12 reports). This gives users both official forecasts and real-time ground truth from the community. Show the comparison only when sufficient community reports exist in the area (at least 3 reports in the last 2 hours).
Expected result: Users see both official weather data and crowd-sourced reports side by side for comparison.
Complete working example
1FIRESTORE DATA MODEL:2 weather_reports/{reportId}3 userId: String4 lat: double5 lng: double6 geoHash: String (precision 5, ~2.4km)7 condition: "sunny" | "cloudy" | "rainy" | "snowy" | "stormy"8 temperature: double (optional)9 description: String (optional)10 photoUrl: String (optional)11 timestamp: Timestamp1213 weather_aggregates/{aggregateId}14 geoHash3: String (precision 3, ~78km)15 avgTemperature: double16 dominantCondition: String17 reportCount: int18 aggregatedAt: Timestamp1920WIDGET TREE — Submit Report Page:21 Column (padding: 16)22 ├── Text ('Report Weather at Your Location')23 ├── Text (currentLat + ', ' + currentLng, grey)24 ├── SizedBox (16)25 ├── GridView (3 columns, condition icons)26 │ └── GestureDetector → set selectedCondition27 │ Column28 │ ├── Container (circle, color by condition)29 │ │ Icon (condition icon, white)30 │ └── Text (condition name)31 ├── SizedBox (16)32 ├── TextField ('Temperature (optional)', number keyboard)33 ├── TextField ('Notes (optional)', multiline)34 ├── FlutterFlowUploadButton ('Add Photo')35 └── Button 'Submit Report'3637WIDGET TREE — Map View:38 Stack39 ├── FlutterFlowGoogleMap40 │ markers: weather_reports (last 4 hours)41 │ color: condition-based (yellow/grey/blue/lightBlue/red)42 │ infoWindow: condition + temp + timeAgo43 └── Positioned (bottom)44 Container (official vs community comparison card)4546WIDGET TREE — Feed View:47 Column48 ├── Text ('Nearby Reports')49 └── ListView (geoHash prefix query, orderBy timestamp desc)50 └── Container (card)51 Row52 ├── Container (condition icon circle, colored)53 ├── Column54 │ ├── Text (condition + ' | ' + temp + '°')55 │ ├── Text (description, maxLines 1)56 │ └── Text (timeAgo + ' | ' + distance + ' away')57 └── Image (photoUrl thumbnail, if present)Common mistakes when creating a Crowd-Sourced Weather Reporting App in FlutterFlow
Why it's a problem: Not using geoHash for proximity queries in Firestore
How to avoid: Store a geoHash on each report and query by geoHash prefix for approximate area matching. Precision 5 gives roughly 2.4km cells.
Why it's a problem: Displaying stale weather reports from hours or days ago
How to avoid: Filter queries to the last 2 to 4 hours. On the map and feed, always show the time since submission so users know how fresh each report is.
Why it's a problem: Not handling location permission denial gracefully
How to avoid: Check permission status before requesting location. If denied, show a message explaining why location is needed and provide a manual city search as fallback.
Best practices
- Use geoHash for Firestore proximity queries since native radius queries are not supported
- Filter reports to the last 2 to 4 hours to keep weather data fresh and relevant
- Color-code map markers by weather condition for instant visual pattern recognition
- Show time-since-submission on every report so users judge data freshness
- Aggregate reports hourly with Cloud Functions for regional summaries
- Handle location permission denial with a manual search fallback
- Complement crowd-sourced data with official API data for credibility
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a crowd-sourced weather reporting app in FlutterFlow. Users submit reports with GPS location, condition (sunny/cloudy/rainy/snowy/stormy), temperature, and photo. Reports show as colored markers on Google Maps. Nearby reports use geoHash prefix queries. A Cloud Function aggregates hourly area averages. Show me the data model, geoHash function, submit form, and map display.
Create a weather report page with a grid of weather condition icons (sun, cloud, rain, snow, lightning), temperature and notes fields, a photo upload button, and a submit button. Add a map page with colored markers.
Frequently asked questions
How accurate is geoHash precision 5 for nearby queries?
GeoHash precision 5 covers cells approximately 4.9km by 4.9km. For city-level nearby queries this is sufficient. Increase to precision 6 (1.2km by 0.6km) for denser urban coverage.
How do I prevent fake or spam weather reports?
Require authentication for submissions. Limit reports to one per user per hour per location. Flag reports where the condition drastically differs from all other reports in the same area. Use Cloud Functions to auto-moderate outliers.
Can I add real-time updates so the map refreshes automatically?
Use Firestore real-time listeners by setting Single Time Query to OFF on the map's Backend Query. New reports appear as markers without page refresh.
How do I show weather trends over time for an area?
Query weather_aggregates for a specific geoHash3 prefix over the past 24 hours. Display the data in a line chart Custom Widget using fl_chart showing temperature and condition changes.
What if the user has no GPS signal?
Fall back to a manual location entry: let the user type a city name or tap a location on the map. Use Google Geocoding API to convert the selection to coordinates.
Can RapidDev build a weather or location-based reporting app?
Yes. RapidDev can build location-based reporting apps with real-time maps, crowd-sourced data aggregation, moderation systems, and official API integrations.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation