How I Built a Simple Movie Recommender Website (Without Hollywood Budget)

Ever opened Netflix, spent 40 minutes scrolling, and then closed it without watching anything?
Yeah. Me too.
That’s why I decided to build a simple movie recommendation web app—a clean, lightweight tool to help users discover movies based on their favorite genres.
Project Goals
Recommend similar movies based on user input
Keep it simple, minimal, and fast
Use basic ML, not deep learning (yet)
Learn Flask + deploy a real working web app
Tech Stack
Python (core logic + ML)
Flask (web framework)
Scikit-Learn (vectorizing + similarity)
HTML/CSS (UI)
TMDB Dataset (from Kaggle)
Hosted with Netlify (frontend) or Render (backend API)
The Building Blocks
1. Getting the Data
I started with a movie metadata dataset from Kaggle that included:
Movie titles
Genres
Tags
Overview descriptions
I cleaned and preprocessed it using pandas
and selected a few key features to combine into a “bag of words.”
data['tags'] = data['overview'] + data['genres'] + data['keywords']
2. Vectorizing the Data
To compare movies, I used CountVectorizer
from scikit-learn to convert text into a numeric form:
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
cv = CountVectorizer(max_features=5000, stop_words='english')
vectors = cv.fit_transform(data['tags']).toarray()
similarity = cosine_similarity(vectors)
3. Recommendation Logic
Simple cosine similarity:
def recommend(movie):
index = data[data['title'] == movie].index[0]
distances = similarity[index]
movie_list = sorted(list(enumerate(distances)), reverse=True, key=lambda x:x[1])[1:6]
for i in movie_list:
print(data.iloc[i[0]].title)
Later, I wrapped this into a function used in the Flask app.
4. Building Frontend
Although I don’t barge too much behind the frontend, I tried to give my application a basic clean UI, with the knowledge I gained by harsh training( learnt in uni class).
<form action="/recommend" method="post">
<input type="text" name="movie" placeholder="Enter a movie...">
<button type="submit">Recommend</button>
</form>
Integrating Flask Backend
My Flask app had a basic structure:
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route("/", methods=["GET"])
def home():
return render_template("index.html")
@app.route("/recommend", methods=["POST"])
def recommend():
movie = request.form['movie']
result = recommend_movie(movie)
return render_template("recommend.html", movies=result)
See, it's basic—just simple GET and POST requests, and wham! The application is ready.
(Although I did have to spend some time figuring out why it wasn’t serving the CSS stylesheet. Flask static routing can be tricky at 2 am.)
Lesson learned: always link your CSS via the proper /static/
folder and use url_for('static', filename='styles.css')
.
What I Learned
Clean data = smart app
Cosine similarity is simple but powerful
Flask is great for quick MVPs
UI design matters (even for tech demos).
Try It Yourself!
Code: GitHub Repository
Future
In the future, I would like to make some enhancements:
Add content-based + collaborative filtering
Add user login + saved watchlists
Maybe a React frontend later.
Final Thoughts
It’s not IMDb, and it won’t win an Oscar — but it works.
This project taught me that sometimes, building something simple and functional is better than overengineering.
If you’re learning Python or Flask, this is a great starting point.
And if you ever feel stuck... just pick a movie and start coding
That’s enough larping for me, till next story. bye.. bye..
Subscribe to my newsletter
Read articles from vin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

vin
vin
Ojisan here! I write C++ like it’s the 90s, train AI models like they owe me money, and build dungeon crawlers from scratch because game engines are for younglings. By day, I study machine learning, tinker with systems, and occasionally yell at Go compilers. By night, I’m building games, dreaming of agents that dodge roll, and trying to reach code nirvana one segfault at a time. You’ll find me somewhere between main.cpp and a markdown devlog, sipping tea, breaking loops, and muttering: “It’s not a bug... It’s a lesson.”