How to Automate Certificate Generation with Streamlit and Python

Create a professional certificate generator in Python using Streamlit, Pillow, and Pandas. Upload names, customize placement, and generate hundreds of certificates instantly!

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 / FilePurpose
StreamlitTo build the interactive web app
Pillow (PIL)For image manipulation
pandasFor reading and managing CSV data
Certificate templateBackground image (PNG or JPG)
Font file (e.g., TTF)For stylish name placement
CSV fileWith 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.

Posted by Ananya Rajeev

Ananya Rajeev is a Kerala-born data scientist and AI enthusiast who simplifies generative and agentic AI for curious minds. B.Tech grad, code lover, and storyteller at heart.