Home▸Articles▸Recommender Systems

Content-Based Recommendations

Building content-based recommender systems - item similarity, embeddings, cold-start handling, and hybrid approaches.

mysimulator teamUpdated 2026-01≈ 6 min read▶ Open the simulation

Content-based recommendation uses item attributes to recommend similar items to what a user has liked before. Unlike collaborative filtering which uses user-item interactions, content-based methods analyze item features - text descriptions, categories, images, metadata. This approach excels at handling the cold-start problem for new items.

Where It Is Used

Content-based recommendations power personalization across industries:

Products: Google News (topic similarity), Spotify (audio features + content), Indeed (job matching).

How Content-Based Differs from Collaborative

Aspect Content-Based Collaborative Filtering
Data needed Item attributes User-item interactions
Cold-start items Handles well Struggles
Cold-start users Needs some history Struggles
Serendipity Low (similar to past) Higher
Interpretability High (feature-based) Lower
Scalability Scales with items Scales with users × items

When to use content-based: - New items frequently added - Rich item metadata available - User history limited - Explainability important - Domain where similarity is well-defined

Typical Data You Will See

Aspect Typical Values
Items 1K to 10M+
Item features Text, categories, images, numeric
User history 5 to 1000+ interactions
Feature dimensions 50 to 1000+
Update frequency Real-time to daily

Item feature types: - Text: Titles, descriptions, reviews - Categorical: Genre, brand, category - Numeric: Price, rating, duration - Images: Product photos, thumbnails - Structured: Tags, specifications

What You Do in Practice

  1. Define item representation - What features describe items?
  2. Extract features - Text embeddings, category encoding, image features
  3. Build item profiles - Combined feature vectors
  4. Create user profiles - Aggregation of liked item profiles
  5. Compute similarity - Cosine similarity, nearest neighbors
  6. Generate recommendations - Top-K most similar items
  7. Handle cold-start - New item/user strategies
  8. Evaluate offline - Precision, recall, diversity
  9. A/B test online - CTR, engagement, conversions
  10. Iterate and improve - Feature engineering, hybrid approaches

Baseline First

Start with TF-IDF on text features:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

# Create TF-IDF vectors from item descriptions
tfidf = TfidfVectorizer(max_features=5000, stop_words='english')
item_vectors = tfidf.fit_transform(items['description'])

# Compute similarity matrix
similarity_matrix = cosine_similarity(item_vectors)

def get_recommendations(item_id, n=10):
    """Get top-N similar items"""
    idx = item_id_to_idx[item_id]
    sim_scores = list(enumerate(similarity_matrix[idx]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    sim_scores = sim_scores[1:n+1]  # Exclude self
    return [idx_to_item_id[i] for i, score in sim_scores]

Why TF-IDF baseline: - Simple, fast, interpretable - Works well for text-heavy items - No training required - Good starting point

Move to embeddings when TF-IDF limitations are clear.

Feature Extraction Methods

Text features:

Method Description Best For
TF-IDF Term frequency weighting Short text, keywords
Word2Vec avg Average word vectors Medium text
Doc2Vec Document embeddings Longer documents
BERT/Sentence-BERT Contextual embeddings Semantic similarity
from sentence_transformers import SentenceTransformer

# Modern approach: Sentence embeddings
model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(items['description'].tolist())

Categorical features: - One-hot encoding (small cardinality) - Embedding layers (large cardinality) - Target encoding (with caution)

Image features: - Pre-trained CNN (ResNet, EfficientNet) - CLIP embeddings (text-image alignment)

Combined features:

# Concatenate normalized feature vectors
from sklearn.preprocessing import normalize

text_emb = normalize(text_embeddings)
cat_emb = normalize(category_embeddings)
img_emb = normalize(image_embeddings)

# Weighted combination
item_vectors = np.hstack([
    0.5 * text_emb,
    0.3 * cat_emb,
    0.2 * img_emb
])

User Profile Construction

Build user profiles from their interaction history:

def build_user_profile(user_id, item_vectors, interactions):
    """Aggregate item vectors user has interacted with"""
    user_items = interactions[interactions['user_id'] == user_id]

    # Simple: Average of liked item vectors
    liked_vectors = item_vectors[user_items['item_idx']]
    user_profile = liked_vectors.mean(axis=0)

    # Better: Weight by recency or engagement
    weights = np.exp(-0.1 * user_items['days_ago'])
    weights = weights / weights.sum()
    user_profile = np.average(liked_vectors, weights=weights, axis=0)

    return user_profile

def recommend_for_user(user_id, item_vectors, n=10):
    user_profile = build_user_profile(user_id, item_vectors, interactions)
    similarities = cosine_similarity([user_profile], item_vectors)[0]

    # Exclude already seen items
    seen_items = get_user_history(user_id)
    similarities[seen_items] = -1

    top_indices = similarities.argsort()[-n:][::-1]
    return [idx_to_item_id[i] for i in top_indices]

Evaluation and Metrics

Metric Description Use Case
Precision@K Relevant items in top K Accuracy of recommendations
Recall@K Fraction of relevant items retrieved Coverage
NDCG@K Ranking quality Position matters
Coverage Fraction of items recommended Catalog exploration
Diversity Dissimilarity within recommendations Avoid repetition
Novelty Recommendation of less popular items Discovery

Offline evaluation:

def evaluate_recommendations(test_interactions, recommend_func, k=10):
    precisions, recalls = [], []

    for user_id in test_interactions['user_id'].unique():
        actual = set(test_interactions[test_interactions['user_id'] == user_id]['item_id'])
        predicted = set(recommend_func(user_id, n=k))

        if len(predicted) > 0:
            precision = len(actual & predicted) / len(predicted)
            recall = len(actual & predicted) / len(actual) if len(actual) > 0 else 0
            precisions.append(precision)
            recalls.append(recall)

    return np.mean(precisions), np.mean(recalls)

Failure Modes and Debugging Checklist

Production Checklist

Before deployment: - [ ] Item features extracted and indexed - [ ] Similarity computation optimized (ANN) - [ ] User profile computation tested - [ ] Cold-start handling defined - [ ] Latency requirements met - [ ] A/B test designed

After deployment: - [ ] Recommendation CTR tracked - [ ] User engagement monitored - [ ] Feature freshness maintained - [ ] Index updated with new items - [ ] Feedback loop for improvements - [ ] Diversity metrics tracked

Scaling with Approximate Nearest Neighbors

For large catalogs, exact similarity is too slow:

import faiss

# Build FAISS index
dimension = item_vectors.shape[1]
index = faiss.IndexFlatIP(dimension)  # Inner product (cosine with normalized vectors)
index.add(item_vectors.astype('float32'))

# Fast similarity search
def get_similar_items(item_id, n=10):
    query = item_vectors[item_id_to_idx[item_id]].reshape(1, -1)
    distances, indices = index.search(query.astype('float32'), n + 1)
    return [idx_to_item_id[i] for i in indices[0][1:]]  # Exclude self

ANN options: FAISS, Annoy, ScaNN, Milvus.

Tools and Stack

Category Tools
Text embeddings Sentence-Transformers, OpenAI, Cohere
Image features torchvision, CLIP, timm
Vector similarity FAISS, Annoy, ScaNN
Vector databases Pinecone, Weaviate, Milvus
Frameworks LensKit, Surprise, RecBole

Example Mini-Case

Scenario: News platform needs article recommendations based on content similarity.

Data: 500K articles, text content, categories, publication date.

Approach: 1. Baseline: TF-IDF on article text - Precision@10: 0.12 2. Better embeddings: Sentence-BERT - Precision@10: 0.18 3. Add metadata: Category + recency weighting - Precision@10: 0.22 4. Hybrid: + collaborative signals - Precision@10: 0.28 5. Optimization: FAISS index for 10ms latency

Architecture:

Articles → Embedding Service → Vector Index (FAISS)
                                      ↓
User Request → User Profile → ANN Search → Recommendations

Results: - Recommendation latency: 15ms p99 - CTR improvement: +35% vs popularity baseline - User engagement: +20% time on site - New article coverage: 95% recommended within 24h

Related Pages

Further Reading

Try it live

Everything above runs in your browser — open Music Recommender — Matrix Factorization (ALS) Live and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.

▶ Open Music Recommender — Matrix Factorization (ALS) Live simulation

What did you find?

Add reproduction steps (optional)