Build a stock tracker with a Firestore-backed watchlist, live price display, and historical chart. A scheduled Cloud Function fetches stock quotes from Alpha Vantage every 15 minutes and writes to a stock_quotes collection. The FlutterFlow app reads from Firestore with real-time listeners so prices update automatically. A Custom Widget using fl_chart renders interactive price history with selectable time ranges.
Building a Real-Time Stock Market Tracker in FlutterFlow
Stock tracking apps need live data, interactive charts, and personalized watchlists. This tutorial shows you how to fetch market data through a scheduled Cloud Function, store it in Firestore, display a watchlist with green/red price changes, render historical price charts, and integrate a news feed — all within FlutterFlow's visual builder.
Prerequisites
- A FlutterFlow project on the Pro plan or higher
- Firebase project with Firestore and Cloud Functions enabled
- An Alpha Vantage or Polygon.io API key (free tier available)
- Basic familiarity with Cloud Functions and Backend Queries in FlutterFlow
Step-by-step guide
Set up the Cloud Function to fetch and cache stock quotes
Set up the Cloud Function to fetch and cache stock quotes
Create a scheduled Cloud Function that runs every 15 minutes (matching free API tier limits). The function reads a list of tracked symbols from a Firestore `tracked_symbols` document, calls the Alpha Vantage Global Quote endpoint for each symbol, and writes the response data to `stock_quotes/{symbol}` documents with fields: symbol (String), price (double), change (double), changePercent (String), volume (int), high (double), low (double), and lastUpdated (Timestamp). Store your Alpha Vantage API key in Cloud Functions environment config, never in client code.
1// Cloud Function: fetchStockQuotes2// Scheduled: every 15 minutes3const functions = require('firebase-functions');4const admin = require('firebase-admin');5const fetch = require('node-fetch');6admin.initializeApp();78exports.fetchStockQuotes = functions.pubsub9 .schedule('every 15 minutes')10 .onRun(async () => {11 const db = admin.firestore();12 const apiKey = functions.config().alphavantage.key;13 const doc = await db.doc('config/tracked_symbols').get();14 const symbols = doc.data().symbols || [];1516 for (const symbol of symbols) {17 const url = `https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${symbol}&apikey=${apiKey}`;18 const res = await fetch(url);19 const data = await res.json();20 const q = data['Global Quote'];21 if (!q) continue;2223 await db.doc(`stock_quotes/${symbol}`).set({24 symbol,25 price: parseFloat(q['05. price']),26 change: parseFloat(q['09. change']),27 changePercent: q['10. change percent'],28 volume: parseInt(q['06. volume']),29 high: parseFloat(q['03. high']),30 low: parseFloat(q['04. low']),31 lastUpdated: admin.firestore.FieldValue32 .serverTimestamp(),33 });34 }35 });Expected result: Stock quotes update in Firestore every 15 minutes automatically. The client never calls the stock API directly.
Build the watchlist page with real-time prices
Build the watchlist page with real-time prices
Create a Watchlist page. Store each user's watched symbols in a `users/{uid}/watchlist` subcollection, each document containing a symbol field. Add a Backend Query on this subcollection to get the user's symbols. For each symbol, run a second Backend Query on `stock_quotes/{symbol}` with Single Time Query set to OFF for real-time updates. Display each stock in a ListView with a Container showing: symbol (bold Text), price (Text), and change with changePercent in green (positive) or red (negative) using Conditional Styling. Add a sparkline by storing the last 20 price points in an array field on the stock_quotes document.
Expected result: Users see their watched stocks with live prices that update every 15 minutes. Positive changes appear green and negative changes appear red.
Add stock symbol search and watchlist management
Add stock symbol search and watchlist management
At the top of the Watchlist page, add a TextField with a search icon for entering stock symbols. On submit, call an API endpoint (Alpha Vantage Symbol Search) via a Cloud Function that returns matching symbols with company names. Display results in a ListView below the search field. Each result shows the symbol, company name, and an Add to Watchlist IconButton. The Add action creates a document in `users/{uid}/watchlist` with the symbol and also adds the symbol to the `config/tracked_symbols` array (using FieldValue.arrayUnion) so the scheduled function starts fetching it. Add a swipe-to-dismiss gesture on watchlist items that deletes the symbol from the user's watchlist subcollection.
Expected result: Users can search for stock symbols, add them to their watchlist, and remove them by swiping.
Create the stock detail page with a price history chart
Create the stock detail page with a price history chart
When a user taps a stock in the watchlist, navigate to a StockDetail page passing the symbol as a parameter. Fetch historical data by calling the Alpha Vantage Daily endpoint via a Cloud Function and store results in `stock_history/{symbol}` with a prices array of {date, close} objects. Create a Custom Widget named StockChart using fl_chart's LineChart. The widget takes a list of price points and renders them as a curved line with gradient fill beneath. Add ChoiceChips above the chart for time range selection: 1D, 1W, 1M, 3M, 1Y. Each selection filters the price data array to the appropriate date range and rebuilds the chart.
1// Custom Widget: StockChart (simplified)2import 'package:flutter/material.dart';3import 'package:fl_chart/fl_chart.dart';45class StockChart extends StatelessWidget {6 final double width;7 final double height;8 final List<double> prices;910 const StockChart({11 Key? key,12 required this.width,13 required this.height,14 required this.prices,15 }) : super(key: key);1617 @override18 Widget build(BuildContext context) {19 final spots = prices.asMap().entries.map(20 (e) => FlSpot(e.key.toDouble(), e.value),21 ).toList();2223 final isPositive = prices.last >= prices.first;24 final color = isPositive ? Colors.green : Colors.red;2526 return SizedBox(27 width: width,28 height: height,29 child: LineChart(LineChartData(30 gridData: const FlGridData(show: false),31 titlesData: const FlTitlesData(show: false),32 borderData: FlBorderData(show: false),33 lineBarsData: [34 LineChartBarData(35 spots: spots,36 isCurved: true,37 color: color,38 barWidth: 2,39 dotData: const FlDotData(show: false),40 belowBarData: BarAreaData(41 show: true,42 color: color.withOpacity(0.1),43 ),44 ),45 ],46 )),47 );48 }49}Expected result: The stock detail page shows an interactive price chart with time range selection. The line color is green for positive trends and red for negative.
Add a news feed for the selected stock
Add a news feed for the selected stock
Below the chart on the StockDetail page, add a News section. Create a Cloud Function that fetches news articles from a news API (like NewsAPI.org) filtered by the stock's company name. Cache results in `stock_news/{symbol}` with an articles array containing title, source, publishedAt, url, and imageUrl fields. Update the cache hourly via a scheduled function. In FlutterFlow, add a Backend Query on the stock_news document and bind results to a ListView. Each news item shows a Container with the article image, title, source name, and publication time. Tapping an item calls Launch URL to open the full article in the browser.
Expected result: The stock detail page displays relevant news articles below the price chart, and users can tap to read full articles.
Complete working example
1// Custom Widget: StockChart2// Pubspec: fl_chart: ^0.66.034import 'package:flutter/material.dart';5import 'package:fl_chart/fl_chart.dart';67class StockChart extends StatelessWidget {8 final double width;9 final double height;10 final List<double> prices;11 final String timeRange;1213 const StockChart({14 Key? key,15 required this.width,16 required this.height,17 required this.prices,18 this.timeRange = '1M',19 }) : super(key: key);2021 @override22 Widget build(BuildContext context) {23 if (prices.isEmpty) {24 return SizedBox(25 width: width,26 height: height,27 child: const Center(child: Text('No data')),28 );29 }3031 final spots = prices.asMap().entries32 .map((e) => FlSpot(e.key.toDouble(), e.value))33 .toList();3435 final isPositive = prices.last >= prices.first;36 final lineColor = isPositive ? Colors.green : Colors.red;3738 return SizedBox(39 width: width,40 height: height,41 child: LineChart(42 LineChartData(43 gridData: FlGridData(44 show: true,45 drawVerticalLine: false,46 horizontalInterval: _calcInterval(),47 getDrawingHorizontalLine: (v) => FlLine(48 color: Colors.grey.withOpacity(0.2),49 strokeWidth: 1,50 ),51 ),52 titlesData: const FlTitlesData(show: false),53 borderData: FlBorderData(show: false),54 lineTouchData: LineTouchData(55 touchTooltipData: LineTouchTooltipData(56 getTooltipItems: (spots) => spots.map((s) =>57 LineTooltipItem(58 '\$${s.y.toStringAsFixed(2)}',59 const TextStyle(60 color: Colors.white,61 fontWeight: FontWeight.bold,62 ),63 ),64 ).toList(),65 ),66 ),67 lineBarsData: [68 LineChartBarData(69 spots: spots,70 isCurved: true,71 color: lineColor,72 barWidth: 2,73 dotData: const FlDotData(show: false),74 belowBarData: BarAreaData(75 show: true,76 color: lineColor.withOpacity(0.1),77 ),78 ),79 ],80 ),81 ),82 );83 }8485 double _calcInterval() {86 if (prices.isEmpty) return 1;87 final max = prices.reduce((a, b) => a > b ? a : b);88 final min = prices.reduce((a, b) => a < b ? a : b);89 return ((max - min) / 5).clamp(0.01, double.infinity);90 }91}Common mistakes when implementing a Real-Time Stock Market Tracker in FlutterFlow
Why it's a problem: Calling the stock API directly from the FlutterFlow client on every page load
How to avoid: Fetch data via a scheduled Cloud Function every 15 minutes and store results in Firestore. The client reads from Firestore with real-time listeners instead of calling the API directly.
Why it's a problem: Displaying stale prices without showing when the data was last updated
How to avoid: Always display the lastUpdated timestamp on the watchlist and detail pages. Add a 'Data delayed 15 min' disclaimer and show the time since last update.
Why it's a problem: Not handling API failures gracefully in the Cloud Function
How to avoid: Check for valid data in the API response before writing to Firestore. If the response is an error, skip the update and log the failure. Existing data remains unchanged.
Best practices
- Use Conditional Styling to color price changes green for positive and red for negative — this is the universal visual language for stock data
- Cache historical price data in Firestore to avoid repeated API calls for the same date range
- Add a 'Data delayed 15 minutes' disclaimer since free API tiers do not provide real-time quotes
- Store the user's watchlist symbols in a subcollection for efficient per-user queries
- Limit the tracked_symbols config to under 25 symbols on the free API tier to stay within rate limits
- Use fl_chart's touch tooltip to show exact price values when users tap on the chart line
- Add pull-to-refresh that triggers a manual Cloud Function call for on-demand price updates
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building a stock market tracker in FlutterFlow. I need a Cloud Function that fetches stock quotes from Alpha Vantage every 15 minutes and stores them in Firestore. Then I need a watchlist page with real-time price updates and a detail page with an fl_chart line chart for price history. Show me the schema and code.
Create a stock watchlist page showing stock symbols with their current price, daily change in green or red, and a small sparkline chart. Add a search bar at the top to find and add stocks. Tapping a stock should navigate to a detail page with a larger price chart and time range selector.
Frequently asked questions
Can I use a different stock API instead of Alpha Vantage?
Yes. Polygon.io, Finnhub, and Yahoo Finance API all work. Update the Cloud Function endpoint URL and response parsing to match the new API's format. The Firestore schema and FlutterFlow UI remain the same.
How do I show real-time stock prices instead of 15-minute delayed data?
Real-time market data requires a paid API subscription (e.g., Polygon.io WebSocket feed). Connect via a Cloud Function that maintains a WebSocket connection and writes to Firestore on each price update.
Can I add price alerts that notify users when a stock hits a target price?
Yes. Store alert thresholds in a user_alerts subcollection. In the scheduled Cloud Function, after fetching quotes, check if any price crosses a user's threshold and send an FCM push notification.
Does the chart support pinch-to-zoom for detailed price analysis?
fl_chart does not natively support pinch-to-zoom. You can wrap the chart in an InteractiveViewer widget to enable zoom and pan, or use a different charting package like syncfusion_flutter_charts.
How many stocks can I track on the free Alpha Vantage plan?
The free tier allows 5 API calls per minute and 500 per day. With the Cloud Function running every 15 minutes (96 runs/day), you can track about 5 symbols reliably. Upgrade to the premium tier for more symbols.
Can RapidDev help build a full investment portfolio tracker?
Yes. RapidDev can implement portfolio tracking with holdings, cost basis, gain/loss calculations, dividend tracking, sector allocation charts, and real-time data feeds.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation