Building a certificate generator may sound complex, but with Python and Streamlit, it’s surprisingly simple. In this guide, you’ll learn how to automate certificate creation using a sleek web interface — no graphic design skills required.
Imagine you’ve just wrapped up a successful workshop or event. Now comes the not-so-fun part: creating certificates for all participants — one by one. 😩
But what if you could automate this entire task with a sleek, interactive tool built in Streamlit, powered by Python and PIL?
In this guide, I’ll walk you through building your very own automatic certificate generator that lets you:
- Upload a certificate template
- Upload a CSV file with participant names
- Choose the name’s placement and font size
- Generate personalized certificates in bulk
- Download them all in one neat ZIP file 🎉
Let’s get coding!
🛠 What You’ll Need
Before we dive into code, here’s what you need:
| Tool / File | Purpose |
|---|---|
Streamlit | To build the interactive web app |
Pillow (PIL) | For image manipulation |
pandas | For reading and managing CSV data |
| Certificate template | Background image (PNG or JPG) |
| Font file (e.g., TTF) | For stylish name placement |
| CSV file | With a column called name |
📝 Sample list.csv format:
name
Aisha Khan
Mohammed Al-Faraj
Noura Al-Qahtani
📄 Certificate template: Upload a clean image with space to add names.
🔤 Font: Use a TTF file like arial.ttf or any elegant Arabic/English font you like.
🧩 Step-by-Step Implementation
1. Set Up the Project
First, install the required libraries if you haven’t already:
pip install streamlit pillow pandas
Create a Python file, e.g., certificate_generator.py.
2. Build the Core Functions
Here’s how we define the logic to generate certificates:
from PIL import Image, ImageDraw, ImageFont
import pandas as pd
import zipfile
from io import BytesIO
👉 Generate One Certificate
def generate_certificate(base_image, name, font, coordinates):
img = base_image.copy().convert('RGBA')
draw = ImageDraw.Draw(img)
draw.text(coordinates, name, fill=(0, 0, 0), font=font)
return img
👉 Generate All Certificates
def generate_certificates(df, base_image, font, coordinates):
certificates = []
for _, row in df.iterrows():
cert = generate_certificate(base_image, row['name'], font, coordinates)
certificates.append((row['name'], cert))
return certificates
👉 Create a ZIP File
def zip_certificates(certificates):
zip_buffer = BytesIO()
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
for name, img in certificates:
img_buffer = BytesIO()
img.save(img_buffer, format='PNG')
zip_file.writestr(f"{name}.png", img_buffer.getvalue())
zip_buffer.seek(0)
return zip_buffer
3. Build the Streamlit App Interface
import streamlit as st
st.title("🎓 Automatic Certificate Generator")
Upload Files
uploaded_image = st.file_uploader("Upload Certificate Base Image", type=["png", "jpg", "jpeg"])
uploaded_csv = st.file_uploader("Upload CSV File with Names", type=["csv"])
Get Default Coordinates
if uploaded_image:
base_image = Image.open(uploaded_image)
img_width, img_height = base_image.size
default_x = img_width // 2
default_y = img_height // 2
else:
default_x, default_y = 250, 250 # Safe defaults
Let Users Choose Name Placement
x_coord = st.number_input("Enter X Coordinate for Name", min_value=0, value=default_x)
y_coord = st.number_input("Enter Y Coordinate for Name", min_value=0, value=default_y)
coordinates = (x_coord, y_coord)
Select Font Size
font_size = st.number_input("Enter Font Size", min_value=10, value=60)
try:
font = ImageFont.truetype("arial.ttf", font_size) # Replace with your font path
except:
font = ImageFont.load_default()
4. Generate & Preview Certificates
if uploaded_image and uploaded_csv:
df = pd.read_csv(uploaded_csv)
if 'name' not in df.columns:
st.error("CSV file must contain a 'name' column.")
else:
first_name = df.iloc[0]['name']
preview_cert = generate_certificate(base_image, first_name, font, coordinates)
st.image(preview_cert, caption=f"Preview: {first_name}", use_container_width=True)
certificates = generate_certificates(df, base_image, font, coordinates)
zip_buffer = zip_certificates(certificates)
st.download_button(
label="📦 Download All Certificates",
data=zip_buffer,
file_name="certificates.zip",
mime="application/zip"
)
Screenshots

✅ Final Thoughts
With just a few lines of code, you’ve created a powerful tool that can automate a tedious task, save hours of work, and ensure every certificate looks polished and professional. 👏
You can even deploy this on the web with:
streamlit run certificate_generator.py
🚀 What Next?
- Add Arabic font support for bilingual certificates 🇸🇦
- Save to PDF instead of PNG
- Integrate email automation to send certificates directly
💬 Have You Tried It?
Drop a comment if you built your version, or let us know if you’d like us to host this tool for you!
For enterprise automation needs, explore our AI services at Ossels AI.