
Published 13 June 2026 | Updated 29 October 2026
AI/ML
How to Build a Content-Based Recommendation System: A Practical Guide With Python Code
What Is a Content-Based Recommendation System?
A content-based recommendation system recommends items whose features are similar to items a user has already shown interest in. If a reader finishes three articles about electric cars, it suggests other articles about electric cars and batteries; if a shopper views running shoes with a certain cushioning and price, it suggests shoes with similar attributes. The system only needs to understand the items and one user's own history, not the behaviour of other users.
If you'd rather have one built into your product, our AI integration services team can add recommendations to your existing app or website.
Quick answer
A content-based recommendation system suggests items that are similar to what a user already liked, by comparing the items' own attributes, such as text, category, tags, price or images. You build one in five steps: collect item data, turn each item into a numeric vector (with TF-IDF or modern text embeddings), build a profile of each user from the items they interacted with, score candidate items by similarity (usually cosine similarity) and rank, filter and serve the top results. Content-based systems work from day one for new items and need no data about other users, which makes them the best starting point for most catalogues, content sites and job or property platforms. This guide explains how they work, compares them with collaborative and hybrid systems, and walks through working Python code, evaluation and scaling to millions of items with vector search.
- Content-based filtering recommends items similar to a user's past likes, using item features rather than other users' behaviour.
- It solves the new-item cold start problem and is easy to explain (“because you read…”), but it can become repetitive.
- In 2026, sentence embeddings and multimodal embeddings beat TF-IDF on most text and product catalogues; TF-IDF is still a strong, cheap baseline.
- Vector databases such as pgvector, Qdrant, Milvus or OpenSearch make similarity search fast at millions of items.
- Most production systems end up hybrid: content-based for new items and users, collaborative filtering once interaction data grows, and a re-ranking step for business rules.
Content-Based vs Collaborative vs Hybrid Recommendations
| Comparison | Content-based filtering | Collaborative filtering | Hybrid |
|---|---|---|---|
| What it uses | Item features (text, tags, category, price, images) and the user's own history | Interactions of many users (views, purchases, ratings) | Both, plus context and business rules |
| New items | Recommended immediately | Can't be recommended until people interact with them | Handled by the content part |
| New users | Need a few interactions or stated interests | Need interactions | Use popularity or onboarding choices first |
| Discovery of new interests | Low: tends to suggest more of the same | High: finds what similar people liked | High |
| Explainability | Easy (“similar to X”) | Harder | Medium |
| Data needed | Good item metadata | Large volumes of interaction data | Both |
| Best for | News, blogs, jobs, real estate, new catalogues, B2B | Large marketplaces, streaming, social apps | Most mature products |
How a Content-Based Recommender Works
- 1. Represent Each Item. Turn each item's content into a vector: TF-IDF weights for words, embeddings from a language or image model, plus encoded categories, tags and numeric attributes.
- 2. Build a User Profile. Combine the vectors of items the user viewed, saved or bought, weighting stronger signals (purchase over view) and recent actions more heavily.
- 3. Measure Similarity. Compare the user profile, or the item being viewed, with all candidate items, usually with cosine similarity.
- 4. Rank and Filter. Take the top matches, remove items already seen or out of stock, and apply rules such as availability, region or price range.
- 5. Serve and Learn. Show recommendations, log clicks and conversions, and use that feedback to tune weights or move to a hybrid model.
Item-to-Item vs User-Profile Recommendations
| Type | Question it answers | Example |
|---|---|---|
| Item-to-item (“similar items”) | What else is like this item? | “More like this” on a product or article page |
| User profile (“for you”) | What will this person like next? | A personalised home feed or weekly email |
| Query-based | What matches what the user just described? | “Show me laptops like this but lighter” in an AI shopping assistant |
Build a Content-Based Recommender in Python, Step by Step
The example below recommends products, but the same code works for articles, jobs, courses or properties. It uses pandas and scikit-learn (pip install pandas scikit-learn).
- Step 1: Prepare Item Data. Put one row per item with an ID and the fields that describe it: title, category, tags and description. Clean the text (remove HTML, fix duplicates) and fill missing values; poor metadata is the most common reason content-based recommendations look random.
- Step 2: Turn Items Into Vectors. Combine the text fields and convert them to TF-IDF vectors, which weight words that are frequent in one item but rare across the catalogue.
- Step 3: Find Similar Items. Compare one item's vector with all others using cosine similarity and return the closest matches.
- Step 4: Build User Profiles. Average the vectors of items a user interacted with, giving stronger actions such as purchases more weight than views.
- Step 5: Rank, Filter and Serve. Remove items the user already has, apply business rules and return the top results through an API.
import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
# 1. Item data: one row per item
items = pd.DataFrame({
"item_id": [1, 2, 3, 4, 5],
"title": ["Trail running shoes", "Road running shoes", "Waterproof hiking boots",
"Lightweight running jacket", "Yoga mat"],
"category": ["shoes", "shoes", "boots", "apparel", "fitness"],
"description": [
"Grippy trail shoes with rock plate for off-road running",
"Cushioned road shoes for daily running and marathons",
"Leather hiking boots, waterproof, ankle support for trails",
"Breathable, packable jacket for running in wind and rain",
"Non-slip mat for yoga and home workouts",
],
})
# 2. Turn each item into a vector (title + category + description)
items["text"] = items["title"] + " " + items["category"] + " " + items["description"]
vectorizer = TfidfVectorizer(stop_words="english", ngram_range=(1, 2))
item_vectors = vectorizer.fit_transform(items["text"])
# 3. "More like this": items similar to one item
def similar_items(item_id, top_n=3):
idx = items.index[items["item_id"] == item_id][0]
scores = cosine_similarity(item_vectors[idx], item_vectors).ravel()
scores[idx] = -1 # don't recommend the item itself
best = np.argsort(scores)[::-1][:top_n]
return items.iloc[best][["item_id", "title"]].assign(score=scores[best].round(3))
# 4 and 5. "For you": a weighted user profile, then rank and filter
def recommend_for_user(interactions, top_n=3):
# interactions: {item_id: weight}, e.g. view=1, add to cart=3, purchase=5
idx = [items.index[items["item_id"] == i][0] for i in interactions]
weights = np.array(list(interactions.values()), dtype=float)
profile = np.asarray(item_vectors[idx].T.dot(weights) / weights.sum()).reshape(1, -1)
scores = cosine_similarity(profile, item_vectors).ravel()
scores[idx] = -1 # hide items the user already has
best = np.argsort(scores)[::-1][:top_n]
return items.iloc[best][["item_id", "title"]].assign(score=scores[best].round(3))
print(similar_items(1)) # road running shoes ranks first
print(recommend_for_user({1: 5, 4: 1})) # bought trail shoes, viewed a jacketTF-IDF only matches exact words, so “trail” and “trails” or “sneakers” and “running shoes” look unrelated. That is why most teams now move to embeddings.
Upgrade to Embeddings for Better Results
Text embeddings place items with similar meaning close together even when they use different words, and multimodal models such as CLIP can compare product images too. Swap the TF-IDF step for an embedding model (pip install sentence-transformers):
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2") # small, fast, runs on CPU
item_vectors = model.encode(items["text"].tolist(), normalize_embeddings=True)
# With normalised vectors, cosine similarity is a dot product
scores = item_vectors @ item_vectors[0] # similarity to item 1For large catalogues, store the vectors in a vector index and query the nearest neighbours instead of comparing every item. With PostgreSQL and pgvector:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE items (id bigint PRIMARY KEY, title text, embedding vector(384));
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
-- 10 items most similar to item 42
SELECT id, title, 1 - (embedding <=> (SELECT embedding FROM items WHERE id = 42)) AS score
FROM items
WHERE id <> 42
ORDER BY embedding <=> (SELECT embedding FROM items WHERE id = 42)
LIMIT 10;Choosing How to Represent Items
| Method | Best for | Pros | Cons |
|---|---|---|---|
| TF-IDF or BM25 | Small catalogues, keyword-heavy text, a quick baseline | Fast, cheap, explainable | Misses synonyms and meaning |
| Structured features (one-hot categories, scaled price, tags) | Products, jobs, property listings | Precise control over what matters | Needs good metadata and feature weighting |
| Sentence embeddings (open-source or API) | Articles, products, courses, support content | Understands meaning across different wording and languages | Needs a model and vector storage |
| Multimodal embeddings (text plus image) | Fashion, furniture, art, real estate photos | Matches visual style | More compute and storage |
| Combined vector | Most real catalogues | Text meaning plus hard attributes | Requires tuning weights |
How to Evaluate Your Recommender
| Metric | What it tells you | When to use it |
|---|---|---|
| Precision@K and Recall@K | How many of the top K suggestions the user actually engaged with | Offline tests on historical data |
| NDCG@K | Whether the best items appear near the top | Offline ranking quality |
| Coverage | Share of the catalogue that ever gets recommended | Spotting a system that only promotes a few items |
| Diversity and novelty | How different recommendations are from each other and from what the user has seen | Avoiding repetitive feeds |
| Click-through and conversion rate | Real user behaviour | Online A/B tests |
| Revenue or watch time per session | Business impact | Final decision on a new model |
Test offline first by hiding each user's most recent interactions and checking whether the system recommends them, then confirm with an A/B test against your current experience (for example “most popular”).
Common Problems and How to Fix Them
Recommendations Are Too Similar
Add diversity re-ranking such as maximal marginal relevance, mix in popular or trending items, and limit how many items come from one category or brand.
New Users Have No History
Ask for interests during onboarding, use the current session or search query, and fall back to popular items in the user's region.
Poor Item Metadata
Enrich listings with consistent categories and tags; an LLM can generate structured attributes and summaries from messy descriptions.
Some Features Matter More Than Others
Weight fields separately (for example title higher than description) or learn the weights from click data.
Stale or Unavailable Items
Filter by stock, date, location and eligibility at query time, not when vectors are built.
Slow Responses at Scale
Precompute item-to-item neighbours, use approximate nearest-neighbour indexes and cache results for popular items.
Scaling to Millions of Items
| Scale | Recommended setup |
|---|---|
| Up to about 100,000 items | Embeddings in memory or PostgreSQL with pgvector; nightly batch updates |
| 100,000 to 10 million items | A vector database (Qdrant, Milvus, Weaviate, OpenSearch or Elasticsearch k-NN) with HNSW indexes, streaming updates for new items |
| Very large or real-time | Two stages: fast candidate retrieval from the vector index, then a learning-to-rank model that adds user, context and business signals |
Adding LLMs to Content-Based Recommendations
Better item understanding
use an LLM to extract attributes, tags and summaries from long descriptions before embedding them.
Natural-language requests
let users ask for “a waterproof jacket like this but cheaper” and turn the request into a vector search plus filters.
Explanations
generate short, honest reasons such as “because you read three articles on EV batteries”.
Keep the LLM out of the hot path
for speed and cost, use it offline or for re-ranking a short list, not for scoring the whole catalogue.
Where Content-Based Recommendations Work Best
| Industry | Example |
|---|---|
| Media and publishing | Related articles, newsletters and podcast episodes based on topics and entities |
| Ecommerce | “Similar products” and visually similar items for new or long-tail catalogues |
| Jobs and recruitment | Matching candidates and jobs by skills, seniority and location |
| Real estate | Properties similar in location, price, size and amenities |
| Education | Courses and lessons matched to a learner's goals and level |
| B2B and SaaS | Help articles, templates and integrations based on what a customer uses |
| Travel | Hotels and experiences similar in style, area and price |
How Much Does It Cost to Build a Recommendation System?
| Scope | What's included | Cost | Timeline |
|---|---|---|---|
| Content-based MVP | Item vectors, similar items and “for you” API, basic filters, offline evaluation | $10,000–$25,000 | 3–6 weeks |
| Production recommender | Embeddings, vector database, real-time updates, A/B testing, dashboards, diversity and business rules | $25,000–$70,000 | 2–4 months |
| Hybrid personalisation platform | Content plus collaborative models, learning-to-rank, real-time events, LLM features, multiple surfaces (web, app, email) | $70,000–$200,000+ | 4–8 months |
Running costs are usually modest: embedding a catalogue of 100,000 items with an open-source model costs little more than a few hours of compute, and a managed vector database typically costs from $50 to a few hundred dollars a month at that size.
Frequently Asked Questions
Quick answers related to this article from PerfectionGeeks.
1. What is a content-based recommendation system?
2. How is content-based filtering different from collaborative filtering?
3. What are the advantages of content-based filtering?
4. What are the limitations?
5. Which similarity measure should I use?
6. Should I use TF-IDF or embeddings?
7. How do I solve the cold start problem?
8. Which Python libraries are used?
9. How do I evaluate recommendations?
10. Can a content-based system work with millions of items?
11. When should I move to a hybrid system?
12. How much does it cost to build a recommendation system?
Conclusion
PerfectionGeeks builds recommendation systems for ecommerce, media, jobs, education and SaaS products, from a content-based MVP to hybrid personalisation with vector search and LLMs. Share your catalogue size, data and goals, and within 2 business days we'll recommend an approach, a cost range and a timeline, under an NDA.Need a Recommendation Engine for Your Product?

Shrey Bhardwaj is the Director & Founder of PerfectionGeeks Technologies, bringing extensive experience in software development and digital innovation. His expertise spans mobile app development, custom software solutions, UI/UX design, and emerging technologies such as Artificial Intelligence and Blockchain. Known for delivering scalable, secure, and high-performance digital products, Shrey helps startups and enterprises achieve sustainable growth. His strategic leadership and client-centric approach empower businesses to streamline operations, enhance user experience, and maximize long-term ROI through technology-driven solutions.