# How to Design a News Aggregator Platform in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 25-35 min
- Compatibility: FlutterFlow Free+
- Last updated: March 2026

## TL;DR

Build a news aggregator that fetches articles from multiple RSS and API sources via a scheduled Cloud Function, normalizes them into a Firestore articles collection, and displays them in FlutterFlow with category TabBar navigation. Each tab shows a ListView of article cards sorted by publish date. Users can tap to read articles in an in-app WebView or open them externally. A bookmark feature saves articles to a user subcollection. The Cloud Function runs hourly, deduplicates by URL, and parses RSS XML into structured Firestore documents.

## Building a News Aggregator Platform in FlutterFlow

This tutorial creates a news aggregator that pulls articles from multiple sources, organizes them by category, and presents them in a clean reading interface. Unlike a single-source RSS reader, this platform aggregates from multiple feeds, deduplicates articles, and stores them in Firestore for fast querying. Users browse by category, read articles in-app, and save favorites. This pattern works for industry news portals, content curation apps, and company internal news boards.

## Before you start

- A FlutterFlow project with Firestore configured
- Firebase Cloud Functions enabled (Blaze plan)
- At least 3-4 RSS feed URLs to aggregate
- Basic understanding of TabBar and ListView in FlutterFlow

## Step-by-step guide

### 1. Create the Firestore data model and identify RSS sources

Create an articles collection with fields: title (String), summary (String), imageUrl (String), sourceUrl (String, the original article link), sourceName (String, e.g., 'TechCrunch'), category (String: Tech, Business, Sports, Science, Entertainment), publishedAt (Timestamp), fetchedAt (Timestamp). Create a users/{uid}/saved_articles subcollection with fields: articleId (String), savedAt (Timestamp). Identify 3-4 RSS feed URLs for your categories. Store them in a feed_sources collection with fields: url (String), sourceName (String), category (String), isActive (bool).

**Expected result:** Firestore has articles, feed_sources, and saved_articles collections ready for the aggregation pipeline.

### 2. Build the Cloud Function to fetch and normalize RSS feeds

Create a scheduled Cloud Function that runs every hour. The function reads all active feed_sources documents, fetches each RSS feed URL using node-fetch or axios, parses the XML response using the xml2js package to extract title, link, description, pubDate, and any media content URL for the image. For each parsed entry, check if an article with the same sourceUrl already exists in Firestore to deduplicate. If it is new, create an articles document with the normalized fields including the source category. Set fetchedAt to the current server timestamp. Log the count of new articles added per run.

```
// Cloud Function: fetchNewsFeeds (scheduled hourly)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const axios = require('axios');
const { parseStringPromise } = require('xml2js');
admin.initializeApp();

exports.fetchNewsFeeds = functions.pubsub
  .schedule('every 1 hours')
  .onRun(async () => {
    const sourcesSnap = await admin.firestore()
      .collection('feed_sources').where('isActive', '==', true).get();

    for (const sourceDoc of sourcesSnap.docs) {
      const { url, sourceName, category } = sourceDoc.data();
      try {
        const res = await axios.get(url, { timeout: 10000 });
        const parsed = await parseStringPromise(res.data);
        const items = parsed.rss?.channel?.[0]?.item || [];

        for (const item of items.slice(0, 20)) {
          const sourceUrl = item.link?.[0] || '';
          const existing = await admin.firestore()
            .collection('articles')
            .where('sourceUrl', '==', sourceUrl).limit(1).get();

          if (existing.empty && sourceUrl) {
            await admin.firestore().collection('articles').add({
              title: item.title?.[0] || '',
              summary: (item.description?.[0] || '').replace(/<[^>]*>/g, '').slice(0, 300),
              imageUrl: item['media:content']?.[0]?.$?.url || '',
              sourceUrl,
              sourceName,
              category,
              publishedAt: admin.firestore.Timestamp.fromDate(
                new Date(item.pubDate?.[0] || Date.now())
              ),
              fetchedAt: admin.firestore.FieldValue.serverTimestamp(),
            });
          }
        }
      } catch (e) {
        console.error(`Failed to fetch ${sourceName}: ${e.message}`);
      }
    }
  });
```

**Expected result:** The Cloud Function fetches RSS feeds hourly, deduplicates articles, and stores new ones in Firestore.

### 3. Build the news feed with category TabBar and article cards

Create a NewsPage. Add a TabBar with tabs for each category: Tech, Business, Sports, Science, Entertainment, and an All tab. Each tab contains a ListView bound to a Backend Query on the articles collection filtered by category (or no filter for All), ordered by publishedAt descending, with a limit of 20 documents. Each article card Container shows: the imageUrl on the left as a small thumbnail, the title in bold, the summary truncated to 2 lines, a Row with sourceName and a relative time label (e.g., '2 hours ago'). Add a pull-to-refresh RefreshIndicator that re-runs the query.

**Expected result:** Articles display in category tabs with thumbnails, titles, summaries, and source labels.

### 4. Add in-app article reading with WebView and bookmarks

Tap an article card to navigate to an ArticleReaderPage with Route Parameter articleId. Query the article document. Display the title and source name at the top, then embed a Custom Widget WebView that loads the sourceUrl for the full article content. Add a bookmark IconButton in the AppBar. On tap, check if a saved_articles document exists for the current user and articleId. If not, create one with savedAt timestamp. If it exists, delete it. Fill the icon when bookmarked. Create a SavedArticlesPage that queries the user's saved_articles subcollection, joins each articleId to the articles collection, and displays them as the same card layout.

**Expected result:** Users can read articles in-app via WebView and bookmark favorites for later reading.

### 5. Add search and source management

Add a search TextField at the top of the NewsPage above the TabBar. On text change, filter the current tab's query by title prefix match (where title >= searchTerm and title <= searchTerm + unicode high char). For admin users, create a SourceManagementPage that lists all feed_sources with their name, URL, category, and an isActive Switch toggle. Add a form to create new feed sources. Changes to feed sources take effect on the next hourly Cloud Function run. Display the last fetchedAt timestamp so admins know when articles were last updated.

**Expected result:** Users can search articles by title, and admins can manage RSS feed sources.

## Complete code example

File: `FlutterFlow News Aggregator Setup`

```text
FIRESTORE DATA MODEL:
  feed_sources/{sourceId}
    url: String (RSS feed URL)
    sourceName: String
    category: String (Tech / Business / Sports / Science / Entertainment)
    isActive: bool

  articles/{articleId}
    title: String
    summary: String (max 300 chars, HTML stripped)
    imageUrl: String
    sourceUrl: String (original article URL)
    sourceName: String
    category: String
    publishedAt: Timestamp
    fetchedAt: Timestamp

  users/{uid}/saved_articles/{docId}
    articleId: String
    savedAt: Timestamp

CLOUD FUNCTION: fetchNewsFeeds
  Schedule: every 1 hour
  Flow:
    1. Read active feed_sources
    2. For each source: fetch RSS URL → parse XML
    3. For each item: check dedup by sourceUrl
    4. If new: create articles doc with normalized fields

PAGE: NewsPage
  WIDGET TREE:
    Column
      ├── TextField (search)
      ├── TabBar (All / Tech / Business / Sports / Science / Entertainment)
      └── TabBarView
            └── Per tab:
                  RefreshIndicator
                    ListView (articles, orderBy publishedAt desc, limit 20)
                      └── ArticleCard Container
                            Row
                              ├── Image (thumbnail, 80x80)
                              └── Column
                                    ├── Text (title, bold, max 2 lines)
                                    ├── Text (summary, max 2 lines)
                                    └── Row (sourceName + relative time)
                            On Tap: navigate to ArticleReaderPage

PAGE: ArticleReaderPage
  Route Parameter: articleId
  WIDGET TREE:
    Column
      ├── Row (title + bookmark IconButton)
      ├── Text (sourceName + publishedAt)
      └── Custom Widget: WebView (sourceUrl)

PAGE: SavedArticlesPage
  Backend Query: saved_articles subcollection
  ListView (same ArticleCard layout)
```

## Common mistakes

- **Fetching RSS feeds from the FlutterFlow client instead of a Cloud Function** — CORS blocks most RSS feed URLs in web builds, and it exposes your feed source URLs to users. Client-side fetching also hammers external servers with every page load. Fix: Fetch feeds in a scheduled Cloud Function and store normalized articles in Firestore. The FlutterFlow client only reads from Firestore.
- **Not deduplicating articles by sourceUrl before writing to Firestore** — The same article appears multiple times in the feed because RSS feeds include recently published items on every fetch. Without dedup, duplicates multiply with each hourly run. Fix: Before creating an article document, query Firestore for an existing document with the same sourceUrl. Only write if no match exists.
- **Storing raw HTML from RSS descriptions without stripping tags** — RSS description fields often contain HTML tags that render as raw text in FlutterFlow Text widgets, showing ugly markup like '<p>Article text</p>' to users. Fix: Strip HTML tags from the summary in the Cloud Function using a regex like replace(/<[^>]*>/g, '') before saving to Firestore.

## Best practices

- Fetch and normalize RSS feeds server-side in a Cloud Function, never from the client
- Deduplicate articles by sourceUrl before writing to prevent duplicate entries
- Strip HTML tags from RSS descriptions for clean text display
- Use category-based TabBar for organized browsing with each tab querying independently
- Limit article queries to 20-30 items per page for fast loading
- Show relative timestamps like '2 hours ago' instead of absolute dates for freshness context
- Store feed sources in Firestore so admins can add or remove sources without code changes

## Frequently asked questions

### How often should the Cloud Function fetch new articles?

Hourly is a good default. For breaking news sources, consider every 15 minutes. For slower-moving categories, every 4-6 hours. Balance freshness against Cloud Function invocation costs.

### Can I add article images if the RSS feed does not include them?

Yes. In the Cloud Function, if media:content is empty, fetch the article page HTML and extract the Open Graph image meta tag. Store that URL as imageUrl. This adds processing time but improves the visual experience.

### How do I handle feeds that require authentication?

Store API keys or credentials in Cloud Function environment variables. Pass the credentials as headers in the fetch request within the Cloud Function. Never expose credentials to the client.

### Can users submit their own RSS feeds?

Yes. Add a form where users submit a feed URL. Validate the URL by attempting to parse it in a Cloud Function. If valid, add it to feed_sources with a review or auto-approve workflow.

### How do I clean up old articles to manage Firestore costs?

Create a scheduled Cloud Function that deletes articles older than 30 days. Also delete corresponding saved_articles entries to prevent broken bookmarks. Run it daily during low-traffic hours.

### Can RapidDev help build a full content aggregation platform?

Yes. RapidDev can build news platforms with ML-powered personalization, push notification alerts for breaking news, social sharing, reading analytics, and multi-language content support.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-design-a-news-aggregator-platform-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-design-a-news-aggregator-platform-in-flutterflow
