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

How to Build a Social Media Feed with Custom Content Filters in FlutterFlow

Create a filtered social feed with ChoiceChips for content type (Photos, Videos, Text), a Following-only toggle Switch, and a sort DropDown for Recent, Popular, and Trending. Compose Firestore compound queries that combine these filters dynamically. Use a Cloud Function to calculate trending scores based on engagement recency. Handle blocked users by filtering them client-side since Firestore whereNotIn is limited to 10 values.

What you'll learn

  • How to build a filter bar with ChoiceChips, Switch, and DropDown for feed customization
  • How to compose dynamic Firestore compound queries based on active filters
  • How to calculate trending scores with a Cloud Function using engagement and recency
  • How to exclude blocked users from the feed when Firestore limits apply
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read20-25 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Create a filtered social feed with ChoiceChips for content type (Photos, Videos, Text), a Following-only toggle Switch, and a sort DropDown for Recent, Popular, and Trending. Compose Firestore compound queries that combine these filters dynamically. Use a Cloud Function to calculate trending scores based on engagement recency. Handle blocked users by filtering them client-side since Firestore whereNotIn is limited to 10 values.

Building a Filtered Social Media Feed in FlutterFlow

A great social feed is not just a list of posts — it needs smart filtering so users see content they care about. This tutorial builds a feed with content type filters, a following-only mode, multiple sort options including trending, and blocked user exclusion. Each filter composes into a dynamic Firestore query.

Prerequisites

  • A FlutterFlow project with Firebase authentication enabled
  • Firestore database with a posts collection (content, imageUrl, type, authorId, likeCount, commentCount, timestamp)
  • A users collection with a followingIds array or following subcollection
  • Basic familiarity with FlutterFlow Backend Queries and Page State

Step-by-step guide

1

Set up the feed schema with filter-supporting fields

Ensure your posts collection has these fields: content (String), imageUrl (String, optional), videoUrl (String, optional), type (String: photo/video/text), authorId (String), likeCount (Integer), commentCount (Integer), timestamp (Timestamp), trendingScore (Double, updated by Cloud Function). On the users collection, ensure you have a followingIds array (List of Strings) containing UIDs of followed users, and a blockedIds array for blocked users. Create composite Firestore indexes for the query combinations you will use: type + timestamp, type + trendingScore, type + likeCount. Register the collections in FlutterFlow.

Expected result: The posts collection has type, trendingScore, and engagement fields. Composite indexes are created for common filter + sort combinations.

2

Build the filter bar with ChoiceChips, Following toggle, and sort DropDown

At the top of your FeedPage, add a Column containing three filter widgets. First, a ChoiceChips widget with options: All, Photos, Videos, Text. Bind the selected value to a Page State variable called contentTypeFilter (String, default 'All'). Second, a Row with a Text 'Following Only' and a Switch. Bind the Switch to a Page State boolean followingOnly (default false). Third, a DropDown with options: Recent, Popular, Trending. Bind to a Page State variable sortBy (String, default 'Recent'). Style the filter bar in a horizontal Row or Wrap so it scrolls horizontally on small screens. Each filter change should trigger a re-query of the feed ListView below.

Expected result: A filter bar appears above the feed with content type chips, a following toggle, and a sort dropdown. Changing any filter updates the Page State.

3

Compose dynamic Firestore queries based on active filters

Below the filter bar, add a ListView bound to a Backend Query on the posts collection. Build the query dynamically based on Page State: (1) If contentTypeFilter is not 'All', add a where clause: type == selectedType. (2) If followingOnly is true, add a where clause: authorId whereIn currentUser.followingIds (note: Firestore whereIn is limited to 10 values, so if the user follows more than 10 people, batch into groups of 10 and merge results). (3) For sortBy: 'Recent' orders by timestamp descending, 'Popular' orders by likeCount descending, 'Trending' orders by trendingScore descending. Since FlutterFlow's visual query builder may not support fully dynamic queries, use a Custom Function or multiple conditional Backend Queries that switch based on the active filter combination.

Expected result: The feed ListView updates its query whenever a filter changes, showing only matching content sorted by the selected criteria.

4

Create the trending score Cloud Function

Create a scheduled Cloud Function that runs every hour (or on demand). For each post created within the last 7 days, calculate a trending score using a time-decay formula: trendingScore = (likeCount * 2 + commentCount * 3) / hoursAge^1.5. This gives recent posts with high engagement a boost, while older posts decay regardless of total engagement. Update the trendingScore field on each post document. Posts older than 7 days get a trendingScore of 0. This allows the Trending sort option to show posts that are gaining momentum right now, not just all-time popular posts.

functions/calculateTrending.js
1// Cloud Function: Calculate trending scores
2const functions = require('firebase-functions');
3const admin = require('firebase-admin');
4admin.initializeApp();
5
6exports.calculateTrending = functions.pubsub
7 .schedule('every 1 hours').onRun(async () => {
8 const db = admin.firestore();
9 const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
10 const posts = await db.collection('posts')
11 .where('timestamp', '>=', admin.firestore.Timestamp.fromDate(weekAgo))
12 .get();
13
14 const batch = db.batch();
15 posts.docs.forEach(doc => {
16 const data = doc.data();
17 const hoursAge = Math.max(1,
18 (Date.now() - data.timestamp.toMillis()) / 3600000);
19 const score = (data.likeCount * 2 + data.commentCount * 3)
20 / Math.pow(hoursAge, 1.5);
21 batch.update(doc.ref, { trendingScore: score });
22 });
23 await batch.commit();
24 });

Expected result: The Cloud Function runs hourly, calculating trending scores for recent posts. The Trending sort option shows currently hot content.

5

Handle blocked user exclusion in the feed

Firestore's whereNotIn operator is limited to 10 values, which is insufficient for users who have blocked many accounts. Instead, handle blocking client-side. After the feed query returns results, apply a filter in a Custom Function that removes posts where the authorId appears in the current user's blockedIds array. In FlutterFlow, bind the ListView to the filtered result rather than the raw query. For the block action itself, add a 'Block User' option in a post's three-dot menu. On tap, add the author's UID to the current user's blockedIds array using arrayUnion, then refresh the feed to remove their content immediately.

Expected result: Posts from blocked users are filtered out of the feed. Blocking a user immediately removes their content from the current user's view.

Complete working example

FlutterFlow Action Flow — Filtered Social Feed
1// Firestore Schema
2// Collection: posts
3// - content: String
4// - imageUrl: String (optional)
5// - videoUrl: String (optional)
6// - type: String (photo | video | text)
7// - authorId: String
8// - likeCount: Integer
9// - commentCount: Integer
10// - timestamp: Timestamp
11// - trendingScore: Double (updated by Cloud Function)
12
13// User doc fields:
14// - followingIds: List<String> (max ~10 for direct query)
15// - blockedIds: List<String>
16
17// Required Composite Indexes:
18// posts: type ASC + timestamp DESC
19// posts: type ASC + likeCount DESC
20// posts: type ASC + trendingScore DESC
21// posts: authorId ASC + timestamp DESC
22
23// Page State Variables:
24// contentTypeFilter: String (default 'All')
25// followingOnly: Boolean (default false)
26// sortBy: String (default 'Recent')
27
28// Filter Bar Layout:
29// Row (scrollable):
30// → ChoiceChips [All, Photos, Videos, Text]
31// onChange → set contentTypeFilter
32// → Spacer
33// → Text "Following" + Switch
34// onToggle → set followingOnly
35// → DropDown [Recent, Popular, Trending]
36// onChange → set sortBy
37
38// Feed Query Composition:
39// Base: collection('posts')
40// if contentTypeFilter != 'All':
41// .where('type', '==', contentTypeFilter.toLowerCase())
42// if followingOnly:
43// .where('authorId', 'in', currentUser.followingIds[:10])
44// Sort:
45// 'Recent' → .orderBy('timestamp', 'desc')
46// 'Popular' → .orderBy('likeCount', 'desc')
47// 'Trending' → .orderBy('trendingScore', 'desc')
48// .limit(20)
49
50// Post-query filter (Custom Function):
51// results.where((post) =>
52// !currentUser.blockedIds.contains(post.authorId))
53
54// Post Card Component:
55// Container:
56// → Row: CircleImage(authorAvatar) + Text(authorName) + IconButton(⋮)
57// → Conditional: if type==photo → Image(imageUrl)
58// → Conditional: if type==video → VideoPlayer(videoUrl)
59// → Text(content)
60// → Row: IconButton(❤) + Text(likeCount)
61// + IconButton(💬) + Text(commentCount)
62// + IconButton(↗ Share)

Common mistakes when building a Social Media Feed with Custom Content Filters in FlutterFlow

Why it's a problem: Using Firestore whereNotIn to exclude blocked users when the list exceeds 10

How to avoid: Fetch the feed without the block filter, then apply client-side filtering using a Custom Function that removes posts from blocked authors before displaying in the ListView.

Why it's a problem: Not creating composite Firestore indexes for filter and sort combinations

How to avoid: Create composite indexes for every filter + sort combination you support: type + timestamp, type + likeCount, type + trendingScore. Check Firebase Console logs for missing index errors.

Why it's a problem: Using Firestore whereIn for following feed when the user follows more than 10 people

How to avoid: Batch followingIds into groups of 10, run parallel queries, and merge the results. For large-scale apps, use a Cloud Function to pre-compute personalized feeds.

Best practices

  • Cache the blocked user list in App State on login to avoid re-fetching it for every feed query
  • Create Firestore composite indexes for all filter + sort combinations proactively
  • Use a time-decay trending formula so recent engaging content surfaces above old viral posts
  • Limit feed queries to 20 items with pagination for performance
  • Show a skeleton loading shimmer while the feed query is running after a filter change
  • Batch whereIn queries for following lists longer than 10 users
  • Update trending scores on a schedule rather than on every like/comment to reduce Cloud Function invocations

Still stuck?

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

ChatGPT Prompt

I'm building a social media feed in FlutterFlow with content filters. I need ChoiceChips for content type (Photos/Videos/Text), a Following-only Switch, a sort DropDown (Recent/Popular/Trending), and a Cloud Function that calculates trending scores using time-decay. Also need to handle blocked user exclusion client-side since Firestore whereNotIn is limited to 10. Show me the schema, query composition, and Cloud Function.

FlutterFlow Prompt

Create a feed page with a filter bar: ChoiceChips (All, Photos, Videos, Text), a Following Only switch, and a Sort dropdown (Recent, Popular, Trending). Below, show a ListView of posts that updates when any filter changes.

Frequently asked questions

How do I handle infinite scrolling with filters?

Use Firestore cursor pagination with startAfterDocument. After the first 20 results, store the last document. When the user scrolls to the bottom, run the same filtered query with startAfter(lastDoc) to fetch the next page.

Can I save filter preferences so they persist across sessions?

Yes. Store the user's preferred contentTypeFilter, followingOnly, and sortBy values on their user document or in App State (persisted). Load these on page init to restore their last filter configuration.

What happens when a user follows more than 10 people and uses the Following filter?

Firestore whereIn is limited to 10 values. Split the followingIds into batches of 10, run parallel queries, merge the results, and sort client-side. For very large following lists, pre-compute feeds server-side.

How often should the trending score Cloud Function run?

Every 1-2 hours is a good balance for most apps. More frequent updates make trending feel more responsive but increase Cloud Function costs. Less frequent updates may show stale trending content.

Can I add a mute feature that is different from blocking?

Yes. Create a separate mutedIds array on the user document. Muted users' posts are hidden from the feed (client-side filter) but the muted user can still see the muter's content and interact with them. Blocking is bidirectional.

Can RapidDev help build an algorithmically ranked social feed?

Yes. RapidDev can implement ML-based feed ranking, engagement prediction models, A/B testing for feed algorithms, and real-time personalization that goes beyond simple trending formulas.

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.