Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Integrate a Live Sports Ticker into a FlutterFlow App

Build a live sports ticker in FlutterFlow by connecting to a sports data API (SportsData.io, ESPN, or TheSportsDB) via a Cloud Function that polls for scores every 60 seconds and writes results to Firestore. FlutterFlow reads from Firestore with a real-time listener, displaying active game scores in a horizontally scrolling ticker. Never poll the sports API from each user's device — one Cloud Function polls for all users and writes to a shared Firestore document.

What you'll learn

  • How to fetch sports scores from a sports data API via a scheduled Cloud Function
  • How to display a horizontally auto-scrolling ticker with live game scores in FlutterFlow
  • How to build a game detail page with play-by-play events and team stats
  • How to use Firestore real-time listeners to update scores without user-triggered refreshes
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read60-90 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Build a live sports ticker in FlutterFlow by connecting to a sports data API (SportsData.io, ESPN, or TheSportsDB) via a Cloud Function that polls for scores every 60 seconds and writes results to Firestore. FlutterFlow reads from Firestore with a real-time listener, displaying active game scores in a horizontally scrolling ticker. Never poll the sports API from each user's device — one Cloud Function polls for all users and writes to a shared Firestore document.

Real-time sports scores via scheduled Cloud Functions and Firestore real-time listeners

A live sports ticker requires fresh data from a sports data provider — SportsData.io, ESPN, or TheSportsDB all offer APIs with current scores, play-by-play events, standings, and statistics. The key architecture decision is never polling the sports API from each user's device. With 1,000 concurrent users all refreshing scores independently, you exhaust your API quota in minutes and face massive overage charges. Instead, a single scheduled Cloud Function polls the API every 60 seconds during game time and writes to Firestore. All FlutterFlow users read from the same Firestore documents with real-time listeners — one API call serves unlimited users simultaneously.

Prerequisites

  • A FlutterFlow project with Firebase configured (Settings → Project Setup → Firebase)
  • A SportsData.io API key (free trial available at sportsdata.io) or TheSportsDB free API
  • Cloud Functions enabled on Firebase (Blaze plan required for scheduled functions)
  • Google Cloud Scheduler enabled in your Firebase project

Step-by-step guide

1

Choose a sports data API and understand its data structure

TheSportsDB (thesportsdb.com/api.php) is completely free and requires no API key for basic data — ideal for getting started. SportsData.io provides more comprehensive data including play-by-play and real-time scores but requires paid API access. The ESPN API has no official developer documentation but has well-known unofficial endpoints (site.api.espn.com/apis/site/v2/sports/{sport}/{league}/scoreboard) that are widely used for non-commercial projects. For this tutorial, we use SportsData.io's NFL endpoint as a concrete example. Key endpoints: GET /v3/nfl/scores/{season}/ScoresByWeek/{week} returns current-week scores with homeScore, awayScore, quarter, timeRemaining, status (Scheduled/InProgress/Final). Plan your Firestore structure to match this data.

Expected result: You understand the API response structure and have created a matching Firestore schema for storing games, scores, and events.

2

Create the Firestore schema for sports data

Create a sports_scores Firestore collection. Each document represents one game with fields: gameId (String), sport (String), league (String), homeTeam (String), awayTeam (String), homeScore (Integer), awayScore (Integer), status (String — Scheduled/InProgress/Final), quarter (String), timeRemaining (String), startTime (Timestamp), venue (String), lastUpdated (Timestamp). Create a ticker_config document in a settings collection that controls which sports are displayed and what polling interval to use. Create a play_by_play subcollection under each game document with events: description, team, quarter, timeRemaining, recordedAt. This subcollection allows the game detail page to show a running play list.

Expected result: Firestore has the sports_scores collection and schema ready to receive data from the Cloud Function.

3

Create the score-polling scheduled Cloud Function

Create a Cloud Function triggered by Cloud Scheduler named updateSportsScores. In Cloud Functions → Triggers → Cloud Scheduler, set the schedule to every 1 minute (cron: * * * * *) but only activate during typical game hours (e.g., Thursday-Monday for NFL). The function calls the SportsData.io scores endpoint with your API key. For each game in the response, update the corresponding Firestore sports_scores document using admin.firestore().collection('sports_scores').doc(gameId).set({...scoreData}, {merge: true}). This merge:true ensures only changed fields are updated, not the entire document. Add logic to detect status changes (InProgress → Final) and trigger push notifications for users following those teams.

update_sports_scores.js
1const functions = require('firebase-functions');
2const admin = require('firebase-admin');
3const axios = require('axios');
4admin.initializeApp();
5
6const API_KEY = functions.config().sportsdata.key;
7
8exports.updateSportsScores = functions.pubsub
9 .schedule('every 1 minutes')
10 .onRun(async () => {
11 const url = `https://api.sportsdata.io/v3/nfl/scores/json/ScoresByWeek/2025/1`;
12 const { data } = await axios.get(url, {
13 headers: { 'Ocp-Apim-Subscription-Key': API_KEY },
14 });
15
16 const db = admin.firestore();
17 const batch = db.batch();
18
19 for (const game of data) {
20 const ref = db.collection('sports_scores').doc(String(game.ScoreID));
21 batch.set(ref, {
22 gameId: String(game.ScoreID),
23 sport: 'NFL',
24 homeTeam: game.HomeTeam,
25 awayTeam: game.AwayTeam,
26 homeScore: game.HomeScore || 0,
27 awayScore: game.AwayScore || 0,
28 status: game.Status,
29 quarter: game.Quarter ? `Q${game.Quarter}` : null,
30 timeRemaining: game.TimeRemaining,
31 startTime: new Date(game.DateTime),
32 lastUpdated: admin.firestore.FieldValue.serverTimestamp(),
33 }, { merge: true });
34 }
35
36 await batch.commit();
37 return null;
38 });

Expected result: Sports scores in Firestore update every 60 seconds from a single Cloud Function call, regardless of how many users are watching the ticker.

4

Build the horizontally scrolling ticker in FlutterFlow

On your home page or sports tab, add a Container at the top for the ticker. Inside it, add a ListView with scroll direction set to Horizontal. Add a Backend Query to the ListView pointing to the sports_scores collection filtered by status == InProgress (showing only live games). Turn off Single Time Query so it is a real-time listener — scores update instantly as Firestore changes. Set Generate Dynamic Children on the ListView. Each child is a Container (fixed width 200px) showing: home team abbreviation, away team abbreviation, score (homeScore vs awayScore), and the current quarter and time (Q3 2:45). Add a Timer widget or AnimatedContainer to make the ListView auto-scroll continuously using a Custom Action that increments the scroll controller position every 3 seconds.

Expected result: A horizontally scrolling ticker at the top of the page shows all in-progress games with live scores, updating automatically as Firestore receives new data from the Cloud Function.

5

Build the game detail page with standings and play-by-play

Create a GameDetail page with a Page Parameter gameId (String). Add a Backend Query loading the game document. Show the full score header: team names, logos (from an assets map or URL), quarter, and time remaining. Below the score, add a TabBar with three tabs: (1) Play-by-Play: a Backend Query on the play_by_play subcollection ordered by recordedAt descending, displayed as a ListView of play descriptions. (2) Box Score: a Container with a table layout showing stats from the game document's stats Map field if your API provides them. (3) Standings: a Backend Query on a team_standings collection showing the league table sorted by wins. Add a follow toggle button — when toggled, add the gameId to the user's followedGames array in Firestore so the notification logic can target them.

Expected result: The game detail page shows the full match experience with real-time play-by-play, stats, and the option to follow a game for score change notifications.

Complete working example

sports_ticker_architecture.txt
1Firestore Schema:
2sports_scores/{gameId}
3 gameId: String
4 sport: String (NFL / NBA / MLB / Soccer)
5 league: String
6 homeTeam: String
7 awayTeam: String
8 homeScore: Integer
9 awayScore: Integer
10 status: String (Scheduled / InProgress / Final)
11 quarter: String (Q1/Q2/Q3/Q4/OT)
12 timeRemaining: String
13 startTime: Timestamp
14 venue: String
15 lastUpdated: Timestamp
16 play_by_play (subcollection)
17 {eventId}
18 description: String
19 team: String
20 quarter: String
21 timeRemaining: String
22 recordedAt: Timestamp
23
24FlutterFlow Components:
25
26Ticker (on HomePage)
27 Container (fixed height: 60px, background: dark)
28 ListView (horizontal, real-time Backend Query: status == InProgress)
29 GameCard (200px wide)
30 Row: awayTeam + awayScore
31 Text: 'vs'
32 Row: homeTeam + homeScore
33 Text: quarter + timeRemaining
34
35GameDetail Page (param: gameId)
36 Backend Query: sports_scores/{gameId} (real-time)
37 ScoreHeader: team names + logos + score + quarter
38 TabBar:
39 Tab 1: Play-by-Play
40 ListView (Backend Query: play_by_play, realtime)
41 Tab 2: Stats Table
42 Tab 3: Standings
43
44Cloud Function: updateSportsScores
45 Trigger: Cloud Scheduler (every 1 min)
46 Fetches: SportsData.io scores endpoint
47 Writes: sports_scores/{gameId} (merge)
48 Notifies: users following changed-status games via FCM

Common mistakes

Why it's a problem: Polling the sports API from each user's device on page load or on a timer

How to avoid: Use ONE scheduled Cloud Function that polls for all users combined. The Cloud Function writes to Firestore, and all clients read from Firestore — one API call serves unlimited concurrent users.

Why it's a problem: Using real-time Backend Queries for all data on the ticker page including completed games

How to avoid: Filter the real-time ticker query to InProgress games only. Use Single Time Query for completed game details and standings — they update infrequently and do not need persistent listeners.

Why it's a problem: Storing team logos as hardcoded image URLs from a third-party CDN

How to avoid: Download team logos once and upload them to Firebase Storage. Store the permanent Firebase Storage URLs in a Firestore teams collection. Reference them by team abbreviation from your score data.

Best practices

  • Pause Cloud Scheduler polling during the off-season or when no games are scheduled to avoid unnecessary API calls and Cloud Function costs
  • Add a sport selector (NFL, NBA, MLB, Soccer) so users can filter the ticker to sports they follow — store the preference in App State or the user's Firestore profile
  • Include a last-updated timestamp visible to users so they know how fresh the scores are — 'Updated 45 seconds ago' manages expectations
  • Handle the pre-game state gracefully — show kickoff time and team records for Scheduled games rather than blank scores
  • Cache team names and logos in Firestore so the ticker renders instantly even before the first Cloud Function run after app start
  • Use batch writes in the Cloud Function to update all game documents atomically — this is more efficient than individual document updates
  • Test the real-time update behavior by manually updating a score in Firebase Console and watching the ticker update in the running FlutterFlow app

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am building a FlutterFlow sports app that needs live scores. Write a Firebase Cloud Function in Node.js that: (1) is triggered by Cloud Scheduler every 1 minute, (2) calls the SportsData.io NFL scores API endpoint for the current week using the API key from Firebase config, (3) batch-writes the game data to a Firestore sports_scores collection with merge:true so only changed fields are updated, and (4) sends FCM push notifications to users following any game whose status just changed from InProgress to Final. Include error handling and the Firestore batch write pattern.

FlutterFlow Prompt

Create a live sports ticker in my FlutterFlow app at the top of the home page. It should be a horizontally scrolling ListView showing in-progress games from Firestore's sports_scores collection filtered by status == InProgress. Each card should show both teams, their scores, and the current quarter. The ListView should use a real-time Backend Query so scores update automatically. Make the ticker auto-scroll slowly from left to right.

Frequently asked questions

Which sports data API should I use for a FlutterFlow sports ticker?

TheSportsDB (thesportsdb.com) is completely free and works well for schedules, team info, and historical results. For live in-progress scores with real-time updates, SportsData.io ($9/month per sport) and SportRadar (enterprise pricing) are the top choices. The ESPN unofficial API works for hobbyist projects but has no guarantees of availability or support.

Can I show scores for multiple sports (NFL, NBA, Soccer) in the same ticker?

Yes. Query the sports_scores collection without a sport filter to get all active games, or add a sport field to your query as a Where filter and let users select their sport. If using multiple sports APIs, each gets its own Cloud Function writing to the same sports_scores collection with a sport field on each document.

How do I make the ticker scroll automatically without user interaction?

Create a Custom Action using a ScrollController that advances the scroll position every 3-4 seconds using scrollController.animateTo(position + 200, duration: 500ms, curve: Curves.linear). Attach this as a periodic action using a Timer. When the scroll reaches the end, reset to position 0 to create an infinite loop effect.

How do I add push notifications when a team scores or a game ends?

In the Cloud Function that polls scores, compare the new score to the previous Firestore value before writing. If homeScore or awayScore increased, or if status changed to Final, query users who have the team in their followedTeams array and send them an FCM notification via admin.messaging().sendMulticast().

Does the sports ticker work offline if the user has no internet connection?

Firestore's offline persistence (enabled by default on mobile) caches the last-read data locally. The ticker will show the most recently cached scores when offline but will not update. Show a connection status indicator so users know they are seeing potentially stale data. The ticker resumes live updates automatically when connectivity is restored.

What if I need a full sports app with betting features, fantasy leagues, and multiple leagues?

A comprehensive sports app requires multiple API integrations, complex Firestore schemas, user preference systems, and significant real-time architecture. RapidDev has built production sports applications in FlutterFlow and can design the complete data architecture for your requirements.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.