# How to build content recommendations in Bubble

- Tool: Bubble
- Difficulty: Beginner
- Time required: 20-25 min
- Compatibility: All Bubble plans
- Last updated: March 2026

## TL;DR

Build a content recommendation system in Bubble by tracking user interactions (views, likes, saves), tagging content with categories, and using search constraints to find related items users have not seen yet. Display personalized 'Recommended for You' sections using Repeating Groups filtered by the user's interest profile, combining collaborative filtering signals with category-based matching.

## Building a Content Recommendation System in Bubble

Content recommendations keep users engaged by showing them articles, products, or media they are likely to enjoy. This tutorial teaches you how to build a simple but effective recommendation engine in Bubble — tracking what users view and like, building interest profiles from their behavior, and serving personalized content suggestions. No machine learning required — just smart database queries and Bubble's native search capabilities.

## Before you start

- A Bubble account with an app open in the editor
- Content stored in a Data Type (articles, products, or any content type)
- User authentication set up
- Basic familiarity with searches and Repeating Groups

## Step-by-step guide

### 1. Set up content categories and user interaction tracking

Ensure your content Data Type (e.g., 'Article') has a 'categories' field (list of texts or list of an Option Set 'Category'). Create a 'UserInteraction' Data Type with fields: user (User), content (Article), interaction_type (text: 'view', 'like', 'save', 'share'), timestamp (date). Also add a 'user_interests' field (list of texts) to the User Data Type to store accumulated interest categories.

**Expected result:** Data types are set up to track content categories and user interactions.

### 2. Log user interactions throughout the app

On your article/content detail page, add a 'Page is loaded' workflow: Create a new thing UserInteraction (user = Current User, content = Current Page Article, interaction_type = 'view', timestamp = Current date/time). When a user clicks a 'Like' button, create another UserInteraction with type 'like.' When they click 'Save,' create one with type 'save.' These interaction records form the basis of the recommendation engine — likes and saves carry more weight than views.

> Pro tip: Add an 'Only when' condition to the view logging: 'Do a search for UserInteractions where user = Current User and content = Current Page Article and interaction_type = view:count is 0' to prevent logging duplicate views.

**Expected result:** Every content view, like, and save is recorded as a UserInteraction with the user and content reference.

### 3. Build the user interest profile from interactions

Create a backend workflow called 'update_user_interests' that recalculates a user's interest profile. Search all UserInteractions where user = the target user and interaction_type is 'like' or 'save' (weighted interactions). Collect the categories from each interacted content item. Find the top 5 most frequent categories. Update the User's user_interests field with this list. Schedule this workflow to run after every like or save action, or run it daily via a scheduled workflow.

**Expected result:** Each user has an automatically-updated list of their top interest categories based on their behavior.

### 4. Create the recommendation search logic

On your homepage or content feed page, add a Repeating Group for recommendations. Set Type of content to 'Article' and Data source to: 'Do a search for Articles' with constraints: categories contains list Current User's user_interests (matches any of the user's interests). Add an advanced filter: ':filtered' where This Article's unique id is not in 'Do a search for UserInteractions where user = Current User:each item's content's unique id' — this excludes content the user has already seen. Sort by Created Date descending to show newest first. Limit to 10 items.

> Pro tip: The advanced filter is expensive on large datasets. For better performance, maintain a 'viewed_content' list field on the User and use it as a database constraint instead of the filtered operator.

**Expected result:** A 'Recommended for You' section shows content matching the user's interests that they have not yet viewed.

### 5. Add a fallback for new users with no interaction history

New users have no interests data, so the recommendation search returns nothing. Add a conditional on the Repeating Group: 'When Current User's user_interests:count is 0 → Data source = Do a search for Articles sorted by most liked (a popularity_score field or search UserInteractions grouped by content with count).' This shows popular content as a starting point. As the user interacts, personalized recommendations replace the popular defaults. Add a 'Trending' section that always shows high-engagement content regardless of personalization.

**Expected result:** New users see popular content, while returning users see personalized recommendations that improve over time.

### 6. Add feedback controls to improve recommendations

On each recommended item in the Repeating Group, add small 'Not interested' and 'Show more like this' buttons. 'Not interested' creates a UserInteraction with type 'dismiss' and removes the content from the current view (using a custom state list of dismissed IDs to filter). 'Show more like this' creates a 'like' interaction, which feeds back into the interest profile. This feedback loop continuously improves recommendation quality as users interact with the suggestions.

**Expected result:** Users can actively improve their recommendations by providing positive and negative signals on suggested content.

## Complete code example

File: `Workflow summary`

```text
CONTENT RECOMMENDATION SYSTEM
===============================

Data Types:
  Article: title, body, categories (list of text), author,
           created_date, like_count, view_count
  UserInteraction: user (User), content (Article),
                   interaction_type (view/like/save/dismiss),
                   timestamp
  User (extended): user_interests (list of text)

Interaction Logging:
  Page Load (article page):
    Only when: not already viewed by this user
    Create UserInteraction (user, content, 'view', now)
  
  Like Button Click:
    Create UserInteraction (user, content, 'like', now)
    Make changes to Article: like_count + 1
    Schedule: update_user_interests for Current User

Interest Profile Update (Backend Workflow):
  Search UserInteractions where user = target, type = like/save
  Collect categories from interacted content
  Find top 5 most frequent categories
  Update User's user_interests list

Recommendation Query:
  Primary (returning users):
    Search Articles where
      categories contains list Current User's user_interests
      AND unique id NOT IN user's viewed content
    Sorted by: Created Date descending
    Limit: 10
  
  Fallback (new users):
    Search Articles sorted by like_count descending
    Limit: 10

Feedback Loop:
  'Not interested' → Create dismiss interaction, hide item
  'More like this' → Create like interaction, update interests
```

## Common mistakes

- **Using the :filtered operator on large content databases** — The :filtered operator downloads all results to the client and filters there, which is slow for databases with thousands of articles. Fix: Maintain a 'viewed_content' list on the User Data Type and use it as a database constraint. Or use a 'not in' exclusion approach with smaller result sets.
- **Treating all interactions equally** — A page view is much weaker signal than a like or save. If you weigh them equally, casual browsing drowns out intentional interest signals. Fix: Only use likes and saves (not views) for building the interest profile. Use views only for the 'already seen' exclusion filter.
- **Not providing recommendations for new users** — New users with no interaction history see an empty recommendations section, which is a poor first impression. Fix: Always have a popularity-based fallback that shows trending or most-liked content when the user's interest profile is empty.

## Best practices

- Track interactions at different weights: views for exclusion, likes and saves for interest profiling
- Update user interest profiles asynchronously via backend workflows to avoid slowing down the UI
- Always provide a fallback (popular/trending content) for new users with no interaction history
- Exclude already-viewed content from recommendations to keep suggestions fresh
- Add explicit feedback controls (not interested / show more) to improve recommendation quality
- Limit recommendation queries to 10-15 items per load with a 'Load more' button for performance
- Use Option Sets for categories instead of free text to ensure consistent matching

## Frequently asked questions

### Do I need machine learning for a recommendation system?

No. A category-matching system built with Bubble's native search capabilities works well for most apps. ML-based recommendations are only needed at scale (millions of users and content items).

### How do I handle users who interact with many different categories?

Limit the interest profile to the top 5 most frequent categories. This prevents the recommendations from becoming too broad. Update the profile regularly to reflect changing interests.

### Can I show recommendations in real time as users browse?

Yes. After each interaction, trigger an interest profile update and refresh the recommendation section. However, for performance, it is better to update interests periodically (e.g., after every 5 interactions).

### How do I measure if my recommendations are working?

Track the click-through rate on recommended items versus non-recommended items. If users are clicking on recommendations at a higher rate, the system is working. Log these metrics in your engagement tracking system.

### Can RapidDev help build an advanced recommendation engine?

Yes. RapidDev can implement sophisticated recommendation systems in Bubble, including collaborative filtering, content-based filtering, and hybrid approaches that combine multiple signals for better accuracy.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/build-a-content-recommendation-system-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/build-a-content-recommendation-system-in-bubble
