Never call a stock market API directly from FlutterFlow on every page load — the free-tier rate limits (Alpha Vantage: 5 calls/min, 500/day) are exhausted instantly with multiple concurrent users. Instead, use a scheduled Cloud Function to fetch quotes every 15 minutes, store results in Firestore, and read from Firestore in FlutterFlow. For historical price charts, fetch OHLCV data in the same scheduled function and store it in a sub-collection.
Build a live stock watchlist with quotes and price charts via Cloud Functions
Building a stock market data feature in FlutterFlow requires a different approach than most API integrations. Stock data APIs have strict rate limits on free tiers and are expensive on paid tiers — polling them from the client every time a user opens the app is both slow and quickly burns through your API quota. The correct architecture is a scheduled Cloud Function that fetches quotes for your tracked symbols every 15 minutes and writes the results to Firestore. FlutterFlow reads from Firestore in real time, giving users fast, always-fresh data without hitting the API on every request. This tutorial covers setting up Alpha Vantage (free tier) as the data source, building the scheduled fetch function, creating the watchlist UI, and adding a price history chart.
Prerequisites
- A Firebase project connected to FlutterFlow with Blaze (pay-as-you-go) plan enabled for Cloud Functions
- A free Alpha Vantage API key from alphavantage.co (free registration, no credit card required)
- Basic understanding of Firebase Cloud Functions and Firestore
- The fl_chart package added to FlutterFlow Pubspec Dependencies for price history charts
Step-by-step guide
Create the Firestore schema for stock data
Create the Firestore schema for stock data
In the FlutterFlow Firestore panel, create two collections. First: stock_quotes with fields symbol (String), companyName (String), price (Double), change (Double), changePercent (Double), volume (Integer), lastUpdated (Timestamp), high (Double), low (Double), open (Double). Second: stock_history sub-collection under each stock_quotes document, with fields date (String, YYYY-MM-DD format), open (Double), high (Double), low (Double), close (Double), volume (Integer). Also create a watchlist collection with fields userId (String, DocumentReference to users), symbols (List of Strings) so each user has a personal list of tracked symbols. Deploy the Firestore security rules so only authenticated users can read stock_quotes and only write their own watchlist documents.
Expected result: Firestore shows the stock_quotes, stock_quotes/{symbol}/stock_history, and watchlist collections in the FlutterFlow panel.
Build the scheduled Cloud Function to fetch quotes from Alpha Vantage
Build the scheduled Cloud Function to fetch quotes from Alpha Vantage
In your Firebase project, create a Cloud Function named fetchStockQuotes using the firebase-functions/v2/scheduler module. The function runs every 15 minutes (minimum free refresh rate) using pubsub.schedule('every 15 minutes'). It reads the list of symbols to track from a Firestore config document (config/stocks.watchedSymbols array). For each symbol, it calls the Alpha Vantage GLOBAL_QUOTE endpoint: https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={SYMBOL}&apikey={KEY}. Parse the response's 'Global Quote' object and write to Firestore stock_quotes/{symbol}. Store the API key in Firebase Secret Manager, not hardcoded. Deploy with firebase deploy --only functions:fetchStockQuotes.
1const { onSchedule } = require('firebase-functions/v2/scheduler');2const { defineSecret } = require('firebase-functions/params');3const admin = require('firebase-admin');4const axios = require('axios');56const alphaVantageKey = defineSecret('ALPHA_VANTAGE_KEY');78exports.fetchStockQuotes = onSchedule(9 { schedule: 'every 15 minutes', secrets: [alphaVantageKey] },10 async () => {11 const db = admin.firestore();12 const configDoc = await db.doc('config/stocks').get();13 const symbols = configDoc.data()?.watchedSymbols || ['AAPL', 'GOOGL', 'MSFT'];1415 for (const symbol of symbols) {16 const url = `https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${symbol}&apikey=${alphaVantageKey.value()}`;17 const response = await axios.get(url);18 const quote = response.data['Global Quote'];19 if (!quote || !quote['05. price']) continue;2021 await db.collection('stock_quotes').doc(symbol).set({22 symbol,23 price: parseFloat(quote['05. price']),24 change: parseFloat(quote['09. change']),25 changePercent: parseFloat(quote['10. change percent'].replace('%', '')),26 volume: parseInt(quote['06. volume']),27 open: parseFloat(quote['02. open']),28 high: parseFloat(quote['03. high']),29 low: parseFloat(quote['04. low']),30 lastUpdated: admin.firestore.FieldValue.serverTimestamp()31 }, { merge: true });32 }33 }34);Expected result: Cloud Function deploys successfully. After 15 minutes, Firestore stock_quotes collection shows documents for each tracked symbol with price, change, and timestamp fields.
Build the watchlist page with color-coded price changes
Build the watchlist page with color-coded price changes
In FlutterFlow, create a Watchlist page. Add a Backend Query at the page level querying the stock_quotes collection ordered by symbol. Add a ListView below, bound to the query result using Generate Dynamic Children. Each child is a Container with a Row layout. Inside the Row: a Column with two Text widgets (symbol in bold 16px, companyName in gray 12px), a Spacer, and a Column with two more Text widgets (price formatted as $0.00, and changePercent formatted as +1.23% or -1.23%). For the changePercent text, set the font color using a Conditional Value: if changePercent > 0 then Color.green, else if changePercent < 0 then Color.red, else Color.gray. Add an up-arrow or down-arrow Icon conditionally based on the same condition. Make each row tappable to navigate to a StockDetail page passing the symbol as a page parameter.
Expected result: Watchlist page shows all tracked symbols with live prices. Gainers display green text with up arrows, losers display red text with down arrows.
Add historical price chart using fl_chart
Add historical price chart using fl_chart
Create a StockDetail page with a page parameter symbol (String). Add a Backend Query for the stock document at stock_quotes/{symbol}. Add a second Backend Query for the stock_history sub-collection ordered by date descending, limited to 30 records. Create a Custom Widget for the price chart. Import fl_chart in Pubspec Dependencies (version ^0.68.0). In the Custom Widget, build a LineChart using the fl_chart package. Pass the stock_history documents as a list parameter to the widget. Map each document to a FlSpot(x: index.toDouble(), y: close). Set the line color based on whether the current price is above or below the opening price. Add axis labels for dates. Display the chart in a Container with fixed height 220px on the StockDetail page below the quote summary.
Expected result: StockDetail page shows the stock quote card at the top and a 30-day price line chart below, with the line colored green or red based on price direction.
Implement symbol search with the Alpha Vantage SYMBOL_SEARCH endpoint
Implement symbol search with the Alpha Vantage SYMBOL_SEARCH endpoint
Add a search TextField at the top of the Watchlist page, bound to a Page State variable searchQuery. In the API Manager, create an API Group named AlphaVantage with base URL https://www.alphavantage.co. Add an API Call named searchSymbols with method GET, path /query, and query parameters: function=SYMBOL_SEARCH, keywords={searchQuery}, apikey={ALPHA_VANTAGE_KEY} (store the key in FlutterFlow Secrets). On the search TextField's onChange action, wait for 500ms debounce (use a Timer Custom Action), then call the searchSymbols API Call. Bind the response bestMatches array to a ListView below the search field showing symbol, name, and region. Tapping a search result adds the symbol to the user's watchlist Firestore document and navigates to the StockDetail page. Store the API key in Secrets — do NOT hardcode it in the API Call.
Expected result: Typing in the search field shows matching stock symbols from Alpha Vantage with company names. Tapping a result adds it to the watchlist.
Complete working example
1const { onSchedule } = require('firebase-functions/v2/scheduler');2const { defineSecret } = require('firebase-functions/params');3const admin = require('firebase-admin');4const axios = require('axios');56if (!admin.apps.length) admin.initializeApp();78const alphaVantageKey = defineSecret('ALPHA_VANTAGE_KEY');910// Fetches real-time stock quotes every 15 minutes11// Stores in Firestore stock_quotes/{symbol}12exports.fetchStockQuotes = onSchedule(13 {14 schedule: 'every 15 minutes',15 timeZone: 'America/New_York',16 secrets: [alphaVantageKey]17 },18 async () => {19 const db = admin.firestore();20 const configDoc = await db.doc('config/stocks').get();21 const symbols = configDoc.data()?.watchedSymbols || ['AAPL', 'GOOGL', 'MSFT', 'AMZN'];2223 const results = await Promise.allSettled(24 symbols.map(async (symbol) => {25 const url = `https://www.alphavantage.co/query` +26 `?function=GLOBAL_QUOTE&symbol=${symbol}` +27 `&apikey=${alphaVantageKey.value()}`;28 const { data } = await axios.get(url);29 const q = data['Global Quote'];30 if (!q || !q['05. price']) return;3132 await db.collection('stock_quotes').doc(symbol).set({33 symbol,34 price: parseFloat(q['05. price']),35 change: parseFloat(q['09. change']),36 changePercent: parseFloat(q['10. change percent'].replace('%', '')),37 volume: parseInt(q['06. volume']),38 open: parseFloat(q['02. open']),39 high: parseFloat(q['03. high']),40 low: parseFloat(q['04. low']),41 lastUpdated: admin.firestore.FieldValue.serverTimestamp()42 }, { merge: true });43 })44 );4546 const failures = results.filter(r => r.status === 'rejected');47 if (failures.length > 0) {48 console.error(`${failures.length} quote fetches failed:`, failures);49 }50 }51);Common mistakes
Why it's a problem: Calling the stock API directly from FlutterFlow on every page load or widget build
How to avoid: Always fetch via a scheduled Cloud Function (every 15 minutes for free tier, every minute on paid tiers like Polygon.io). Store results in Firestore. FlutterFlow reads from Firestore — zero API calls from the client, instant data load from Firestore's cache.
Why it's a problem: Hardcoding the Alpha Vantage API key in the FlutterFlow API Manager headers
How to avoid: For the scheduled Cloud Function, store the key in Firebase Secret Manager using defineSecret. For any client-side API calls (like symbol search), store the key in FlutterFlow Secrets and route through a Cloud Function proxy that adds the key server-side before calling Alpha Vantage.
Why it's a problem: Using the Alpha Vantage TIME_SERIES_INTRADAY endpoint without checking market hours
How to avoid: For price history charts, use TIME_SERIES_DAILY which is always available. In your Cloud Function, check if the current time is within NYSE market hours before fetching intraday data. Display the last known close price with a 'Market Closed' indicator outside trading hours.
Best practices
- Add a lastUpdated timestamp display near the watchlist header so users know when quotes were last refreshed — builds trust and explains why prices may be slightly delayed
- Implement a pull-to-refresh gesture that triggers an immediate Cloud Function invocation (via an HTTP-triggered function) for users who need on-demand refresh
- Use Firestore real-time listeners (isStreamQuery in FlutterFlow Backend Query settings) so the watchlist updates automatically when the Cloud Function writes new data
- Store the list of symbols to watch in a Firestore config document rather than hardcoding in the Cloud Function — makes it easy to add new symbols without redeploying
- Add a market status indicator (Open / Closed / Pre-Market) based on the current UTC time and NYSE trading hours — users need context for why prices aren't moving
- For production apps with many users, consider Polygon.io Starter plan ($29/mo) which allows unlimited API calls and WebSocket streaming for true real-time data
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I am building a FlutterFlow stock tracking app. Write me: (1) A Firebase Cloud Function using the v2 scheduler that fetches real-time stock quotes from Alpha Vantage's GLOBAL_QUOTE endpoint for a list of symbols and stores results in Firestore, (2) The Firestore schema for stock_quotes and stock_history collections, (3) How to display price changes with conditional green/red coloring in FlutterFlow, and (4) How to build a 30-day price chart using fl_chart as a Custom Widget.
Create a watchlist page with a ListView bound to the stock_quotes Firestore collection. Each row should show the stock symbol in bold, company name below it, current price on the right, and price change percentage below the price. Color the change percentage green if positive and red if negative. Make each row tappable to navigate to a StockDetail page with the symbol passed as a parameter.
Frequently asked questions
Which stock market API is best for FlutterFlow — Alpha Vantage or Polygon.io?
For prototypes and small apps, Alpha Vantage free tier (5 calls/min, 500/day) is sufficient when combined with a 15-minute scheduled Cloud Function. For production apps with many users or intraday data requirements, Polygon.io Starter ($29/mo) offers unlimited API calls, WebSocket streaming for real-time prices, and more reliable data quality.
How do I show real-time (less than 1-minute delayed) stock prices in FlutterFlow?
True real-time prices require a WebSocket connection, which FlutterFlow does not support natively. The approach: use a Cloud Function with WebSocket connection to Polygon.io's WebSocket API, receive price ticks, and write to Firestore. Firestore's real-time listener in FlutterFlow updates the UI within 1-2 seconds. This requires a paid Polygon.io plan and a continuously running Cloud Function (use Cloud Run instead of Functions for persistent WebSocket connections).
Can I display cryptocurrency prices using the same approach?
Yes. CoinGecko has a free API (no key required for basic endpoints) at api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd. Use the same pattern: scheduled Cloud Function fetches prices every 15 minutes, writes to Firestore crypto_prices collection, FlutterFlow reads from Firestore. CoinGecko allows up to 30 calls/minute on the free tier.
How do I implement price alerts when a stock hits a target price?
In the scheduled Cloud Function, after updating stock prices, loop through each user's price alerts (stored in Firestore alerts collection with fields userId, symbol, targetPrice, direction, triggered). For each alert, compare current price to targetPrice. If triggered, send a Firebase Cloud Messaging push notification to that userId and update the alert's triggered field to true to prevent duplicate notifications.
Why does Alpha Vantage return an empty response for some symbols?
Alpha Vantage's free GLOBAL_QUOTE endpoint has gaps in coverage for international stocks, ETFs, and some smaller companies. If the response has an empty 'Global Quote' object or returns 'Information' (rate limit message), add error handling in your Cloud Function: check for empty quotes before writing to Firestore, and log the symbol to a failed_quotes document for monitoring. Polygon.io has broader symbol coverage if Alpha Vantage gaps affect your target stocks.
Can RapidDev help build a production-grade trading data app in FlutterFlow?
Yes. Production stock apps with real-time WebSocket data, candlestick charts, portfolio tracking, alerts, and market depth require architecture beyond the 15-minute polling pattern in this tutorial. RapidDev has built financial data integrations combining Cloud Run WebSocket servers, Firestore real-time sync, and custom Flutter chart widgets for FlutterFlow apps.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation