Introduction
This project guides you through building an Interactive Quiz App using Python and Streamlit. The app presents multiple-choice questions one at a time, tracks the user’s score with st.session_state, and gives instant feedback after every answer. If you like data-driven apps, this quiz pairs naturally with the Pandas dashboard tutorial.
Prerequisites
- Python 3.8+ — python.org
- Streamlit:
pip install streamlit
Step 1: Create the Script
Create quiz_app.py and paste the following:
import streamlit as st
st.set_page_config(page_title="Quiz App", page_icon="🧠")
st.title("🧠 Interactive Quiz App")
QUESTIONS = [
{
"question": "What is the capital of France?",
"options": ["Berlin", "Madrid", "Paris", "Rome"],
"answer": "Paris",
},
{
"question": "Which planet is known as the Red Planet?",
"options": ["Earth", "Mars", "Jupiter", "Venus"],
"answer": "Mars",
},
{
"question": "What is the highest mountain in the world?",
"options": ["K2", "Kangchenjunga", "Mount Everest", "Lhotse"],
"answer": "Mount Everest",
},
{
"question": "How many sides does a hexagon have?",
"options": ["5", "6", "7", "8"],
"answer": "6",
},
{
"question": "Which language is primarily used for web styling?",
"options": ["Python", "JavaScript", "CSS", "SQL"],
"answer": "CSS",
},
]
for key, default in [("score", 0), ("current", 0), ("finished", False)]:
if key not in st.session_state:
st.session_state[key] = default
if st.session_state.finished:
total = len(QUESTIONS)
score = st.session_state.score
st.balloons()
st.subheader("🎉 Quiz Complete!")
st.metric("Your Score", f"{score} / {total}")
pct = score / total * 100
if pct >= 80:
st.success("Excellent work! 🌟")
elif pct >= 60:
st.info("Good job! Keep practising. 📚")
else:
st.warning("Keep trying — you will get there! 💪")
if st.button("🔄 Restart Quiz"):
st.session_state.update({"score": 0, "current": 0, "finished": False})
st.rerun()
else:
idx = st.session_state.current
q = QUESTIONS[idx]
st.progress(idx / len(QUESTIONS), text=f"Question {idx + 1} of {len(QUESTIONS)}")
st.subheader(q["question"])
selected = st.radio("Choose your answer:", q["options"], key=f"q_{idx}")
if st.button("Submit Answer"):
if selected == q["answer"]:
st.success("✅ Correct!")
st.session_state.score += 1
else:
st.error(f"❌ Wrong! The correct answer was **{q['answer']}**.")
st.session_state.current += 1
if st.session_state.current >= len(QUESTIONS):
st.session_state.finished = True
st.rerun()
Step 2: Run the App
streamlit run quiz_app.py
Step 3: Use the App
The quiz shows one question at a time with a progress bar at the top. Select an answer and click Submit Answer to get instant feedback. After the final question the score screen appears with a performance message.
How It Works
The quiz is a state machine: questions live in a Python list of dicts, and st.session_state["q_num"] tracks where the user is. Each rerun renders the current question with st.radio, and the Submit button checks the answer, stores the result, and increments the counter — triggering a rerun that shows the next question.
Because Streamlit re-executes the whole script per interaction, all progress must live in st.session_state; anything stored in a plain variable evaporates on rerun. That single concept — session state as the app’s memory — is the core lesson of this project.
At the end, results render as a score plus st.balloons(). With a few more lines the answers list becomes a DataFrame and you get per-question analytics with st.bar_chart, exactly the technique from the data dashboard.
Key Concepts
st.session_state— Persists the score and current question index across app reruns.st.radio()— Renders the multiple-choice options as radio buttons.st.progress()— Displays a progress bar showing how far through the quiz the user is.st.rerun()— Re-runs the script to advance to the next question instantly.st.balloons()— Plays a fun balloon animation on the results screen.
What to Try Next
- Load questions from a JSON file so you can add new ones without editing code.
- Add a countdown timer for each question using
time.time(). - Show a brief explanation for each answer after the user submits.
- Save high scores to a CSV file and display a leaderboard with
pandas.
Common Errors & Fixes
-
Quiz restarts on every answer — the question index is a local variable instead of
st.session_state. -
Double-submit counts twice — the button check runs before the state increments; use the
on_clickcallback form or guard withif st.button(...) and not answered. -
KeyError: 'q_num'— session keys must be initialized before first read:st.session_state.setdefault("q_num", 0). -
Radio shows previous selection — give the radio a
keyand reset it when advancing questions.
FAQ
How do I load questions from a file?
Read a JSON/CSV into the questions list at startup — the structure matches the blog content files pattern: one object per question.
Can I add a timer per question?
Yes — record time.time() when the question renders and compare on submit; Streamlit’s st_autorefresh component can force the check.
How do I show a results breakdown?
Convert the results list to a DataFrame and use st.bar_chart(df) — five lines, covered in the dashboard tutorial.