Learn how to use user interaction history and feedback loops to make smarter, personalized recommendations in your JavaScript-based recommendation engine.
🧠 Introduction
Basic recommendation engines suggest items based on fixed logic (e.g., content similarity). But what if we could learn from user behavior over time?
In this blog, we’ll upgrade a JavaScript-based recommendation engine to:
- Track what users click on or rate
- Learn from past choices
- Use a feedback loop to adjust future recommendations
🔄 What is a Feedback Loop?
A feedback loop in recommendation systems is a cycle where user actions (clicks, views, ratings) are used to continuously improve recommendations. This helps personalize results dynamically.
🛠️ Architecture Overview
🧱 Components:
- Item dataset: List of books/movies/products
- User profile: What the user has interacted with
- Scoring function: How well an item matches the user’s preferences
- Update logic: Update user preferences as they interact
📦 Step 1: Sample Dataset
const items = [
{ id: 1, title: "The Hobbit", features: [1, 0, 1, 0, 1] },
{ id: 2, title: "1984", features: [0, 1, 0, 1, 1] },
{ id: 3, title: "Dune", features: [1, 0, 1, 1, 0] },
{ id: 4, title: "Brave New World", features: [0, 1, 0, 1, 1] }
];
🧑💻 Step 2: User Profile Initialization
We represent a user’s preference as a weighted feature vector that updates with each interaction.
let userProfile = [0, 0, 0, 0, 0]; // initial preference vector
function updateUserProfile(item, rating = 1) {
item.features.forEach((val, i) => {
userProfile[i] += val * rating;
});
}
⚙️ Step 3: Recommendation Function Using Profile Similarity
function getPersonalizedRecommendations(items, userProfile, topN = 2) {
return items
.map(item => {
const similarity = cosineSimilarity(userProfile, item.features);
return { ...item, score: similarity };
})
.sort((a, b) => b.score - a.score)
.slice(0, topN);
}
You’ll reuse the cosine similarity function from the previous blog.
🖱️ Step 4: Simulate User Feedback (Click or Rate)
// User "likes" The Hobbit (id: 1)
const likedItem = items.find(i => i.id === 1);
updateUserProfile(likedItem, 1); // positive rating
// User "dislikes" 1984 (id: 2)
const dislikedItem = items.find(i => i.id === 2);
updateUserProfile(dislikedItem, -1); // negative rating
🧠 Step 5: Loop and Learn
After each interaction, the user profile evolves:
console.log("Updated user profile:", userProfile);
console.log("New recommendations:");
console.table(getPersonalizedRecommendations(items, userProfile));
🔁 How the Feedback Loop Works
- User interacts
- User profile updates based on the item’s feature vector
- Future scores change, modifying the next batch of recommendations
🚀 Advanced Extensions
- 📊 Weighted decay: Older interactions have less influence
- ❤️ Explicit vs. Implicit feedback: Use clicks, time spent, or ratings
- 📁 localStorage or Backend Sync: Persist user profile between sessions
- 🧠 Neural collaborative filtering: Use ML models with real training (outside of JS)
✅ Conclusion
By incorporating user history and a feedback loop, your JavaScript recommendation engine evolves into a personalized system that learns in real time—without needing a complex backend or ML pipeline.
This approach:
- Mimics how modern systems adapt to user preferences
- Is fully doable in JavaScript using simple math and logic
- Can be integrated with frameworks like React or Next.js