Build a personalized news aggregator where users toggle which RSS sources appear in their feed. A Cloud Function fetches each unique RSS source once on a schedule, stores articles centrally in Firestore, and the app filters articles based on the user's selectedSources array. This avoids redundant fetching while giving each user a unique, customizable feed.
Building a User-Configurable Personalized News Feed in FlutterFlow
A customizable news aggregator differs from a generic one because each user selects which sources they follow. The technical challenge is efficiency: fetching RSS feeds once centrally rather than per user, while still delivering a personalized feed. This tutorial uses Cloud Functions for centralized RSS parsing, Firestore for article storage, and per-user source selection for personalization.
Prerequisites
- A FlutterFlow project with Firestore and Firebase Authentication configured
- Firebase Blaze plan for Cloud Functions and Cloud Scheduler
- A list of RSS feed URLs from news sources you want to offer
- Basic understanding of Firestore queries and document structure
Step-by-step guide
Set up the Firestore data model for sources, articles, and user preferences
Set up the Firestore data model for sources, articles, and user preferences
Create a news_sources collection with fields: name (String, e.g., TechCrunch), rssUrl (String, the RSS feed URL), category (String: Tech/Business/Science/Sports/Entertainment), logoUrl (String), isDefault (Boolean, true for sources pre-selected for new users), isActive (Boolean, admin control). Create an articles collection with: sourceId (Reference to news_sources), title (String), description (String, first 200 chars of content), url (String, link to full article), imageUrl (String, from RSS media:content or enclosure), publishedAt (Timestamp), sourceName (String, denormalized for display). On the users collection, add a selectedSources field: Array of References to news_sources documents. For new users, initialize selectedSources with all sources where isDefault is true.
Expected result: Firestore has sources with RSS URLs, centrally stored articles, and per-user source preference arrays.
Build the Cloud Function to fetch and parse RSS feeds centrally
Build the Cloud Function to fetch and parse RSS feeds centrally
Deploy a Cloud Function fetchAllRSSFeeds() that queries all news_sources where isActive is true. For each source, make an HTTP GET request to the rssUrl. Parse the XML response using a Node.js RSS parser like rss-parser. For each article item, check if an article doc already exists with the same url (deduplication). If not, create an articles doc with title, description (strip HTML tags), url, imageUrl (extract from media:content, enclosure, or og:image), publishedAt (parse pubDate), sourceId, and sourceName. Use Firestore batch writes for efficiency. Delete articles older than 30 days to manage storage.
Expected result: The Cloud Function fetches all active RSS feeds, parses articles, deduplicates by URL, and stores them centrally in Firestore.
Schedule the RSS sync and optimize for efficiency
Schedule the RSS sync and optimize for efficiency
Configure Cloud Scheduler to trigger fetchAllRSSFeeds every 2 hours. The function fetches each unique source only once regardless of how many users follow it. Track the last fetch time per source in a fetch_metadata subcollection to support conditional fetching (if the source supports ETag or Last-Modified headers). Log each fetch cycle: sources processed, new articles added, errors encountered. For sources that fail, retry once with a 5-second delay. If a source fails consistently for 3 cycles, set a failCount on the source doc and alert the admin.
Expected result: RSS feeds are fetched centrally every 2 hours with deduplication, error handling, and admin alerting for failed sources.
Build the source selection page with Switch toggles
Build the source selection page with Switch toggles
Create a ManageSourcesPage. Query all news_sources where isActive is true, grouped by category. For each category, show a Text section header (e.g., Tech, Business). Under each header, display a ListView of source items. Each item is a Row containing: Image (logoUrl, 40x40), Column (source name Text + category Text in grey), and a trailing Switch widget. Initialize each Switch's value by checking if the source's document reference exists in the current user's selectedSources array. On Switch toggle, immediately update the user's selectedSources array — add the reference on toggle on, remove on toggle off. Show a count at the top: 'Following X of Y sources'. Add a Reset to Defaults button that sets selectedSources back to sources where isDefault is true.
Expected result: Users see all available sources grouped by category, can toggle each on or off, and changes persist immediately to their user document.
Build the personalized news feed filtered by user's selected sources
Build the personalized news feed filtered by user's selected sources
Create a NewsFeedPage. On page load, read the current user's selectedSources array. Query the articles collection where sourceId is in the selectedSources list, ordered by publishedAt desc, limited to 50 articles. Because Firestore's whereIn supports a maximum of 10 values, batch the query if the user follows more than 10 sources: split selectedSources into groups of 10, run parallel queries, merge results client-side, and sort by publishedAt. Display articles in a ListView with a RefreshIndicator for pull-to-refresh. Each article card shows: imageUrl (if available), title (bodyLarge, bold, maxLines 2), description (bodyMedium, maxLines 3), Row with source logo + sourceName + time ago. Tapping a card opens the full article URL in a WebView.
Expected result: The feed shows articles only from the user's selected sources, sorted by recency, with pull-to-refresh and tap-to-read functionality.
Complete working example
1FIRESTORE DATA MODEL:2 news_sources/{sourceId}3 name: String (e.g., 'TechCrunch')4 rssUrl: String (e.g., 'https://techcrunch.com/feed/')5 category: String (Tech | Business | Science | Sports | Entertainment)6 logoUrl: String7 isDefault: Boolean8 isActive: Boolean9 failCount: Int (default 0)1011 articles/{articleId}12 sourceId: Reference (news_sources)13 title: String14 description: String (first 200 chars, no HTML)15 url: String (full article link)16 imageUrl: String (nullable)17 publishedAt: Timestamp18 sourceName: String (denormalized)1920 users/{userId}21 ... existing fields ...22 selectedSources: Array of References (news_sources)2324CLOUD FUNCTION: fetchAllRSSFeeds (scheduled every 2 hours)25 1. Query news_sources where isActive == true26 2. For each source: HTTP GET rssUrl → parse XML27 3. For each article: dedup by url → create articles doc28 4. Delete articles older than 30 days29 5. Log: sources processed, articles added, errors3031PAGE: NewsFeedPage32 Column33 AppBar (title: "My Feed", action: gear icon → ManageSourcesPage)34 RefreshIndicator35 ListView36 Query: articles where sourceId in user.selectedSources37 ordered by publishedAt desc, limit 5038 Card (padding: 12)39 Row40 Image (imageUrl, 100x80, fit: cover) — if exists41 SizedBox(12)42 Expanded Column43 Text (title, bodyLarge, bold, maxLines: 2)44 Text (description, bodySmall, maxLines: 2, grey)45 Row: Image(logoUrl, 16x16) + Text(sourceName) + Text(timeAgo)46 On Tap → Open url in WebView4748PAGE: ManageSourcesPage49 Column50 Text "Following X of Y sources" (bodyMedium)51 Button "Reset to Defaults" (outlined)52 For each category:53 Text (category name, titleMedium, bold, paddingTop: 16)54 ListView55 Row56 Image (logoUrl, 40x40)57 Expanded Column58 Text (name, bodyLarge)59 Text (category, bodySmall, grey)60 Switch (value: sourceRef in user.selectedSources)61 On Changed → update user.selectedSources arrayCommon mistakes when building a Customizable News Aggregator with User Preferences in FlutterFlow
Why it's a problem: Fetching RSS feeds independently for each user instead of centrally
How to avoid: Fetch each unique source once via a scheduled Cloud Function. Store articles centrally in Firestore. Filter per user's selectedSources on read.
Why it's a problem: Not handling Firestore's 10-value limit on whereIn queries
How to avoid: Split the selectedSources array into groups of 10, run parallel queries for each group, merge the results on the client side, and sort by publishedAt.
Why it's a problem: Storing raw HTML from RSS content descriptions without stripping tags
How to avoid: Strip all HTML tags in the Cloud Function before storing the description. Use a regex or an HTML-to-text library to extract plain text content.
Best practices
- Fetch RSS sources centrally on a schedule — never per-user — to minimize API calls and avoid IP blocking
- Deduplicate articles by URL before writing to Firestore to prevent duplicate entries from consecutive syncs
- Delete articles older than 30 days to manage Firestore storage costs and keep queries fast
- Denormalize sourceName on each article doc so the feed ListView does not need to join with the sources collection
- Initialize new users with default sources so they see content immediately without manual source selection
- Batch whereIn queries into groups of 10 for users following many sources
- Add a RefreshIndicator on the feed page so users can pull to refresh for the latest articles
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a personalized news aggregator in FlutterFlow where users pick their RSS sources. Show me how to fetch RSS centrally in a Cloud Function, store articles in Firestore, and filter the feed per user's source preferences.
Create a news feed page with an app bar containing a settings gear icon. The main content is a scrollable list of news article cards, each showing a thumbnail image on the left and title, description snippet, source name, and time ago on the right.
Frequently asked questions
How do I add a new RSS source to the aggregator?
Create a new document in the news_sources Firestore collection with the source name, RSS URL, category, and logo. Set isActive to true. The next scheduled Cloud Function run will automatically fetch articles from the new source.
Can users add their own custom RSS feed URLs?
Yes. Add a TextField on the ManageSourcesPage for custom URL entry. On submit, create a news_sources doc with isDefault false and the user as creator. The Cloud Function will pick it up on the next sync cycle.
How do I handle RSS feeds that are slow or frequently down?
Track a failCount on each source document. If fetching fails, increment failCount. After 3 consecutive failures, set isActive to false and alert the admin. Reset failCount to 0 on successful fetch.
Can I add a search feature across all articles?
Firestore does not support full-text search natively. For basic search, query articles where title contains the search term using Firestore's inequality queries. For full-text search, sync articles to Algolia or Typesense and query from there.
How do I categorize articles beyond the source category?
Add a tags array to each article document. In the Cloud Function, analyze the article title and description with keyword matching or an AI classification API to assign tags like AI, Startups, Finance automatically.
What if I need a production news aggregator with AI-powered recommendations?
RapidDev has built news and content aggregation platforms in FlutterFlow with personalized feeds, AI-powered topic classification, saved articles, offline reading, and push notification digests.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation