As a kid, I had a folder filled with certificates. Drawing, quizzes, sports day — even participation ones. Each one felt like a little trophy. I’d rush home, show it to my parents, and sometimes even tell the same story multiple times just to relive the moment. That sense of achievement, of being appreciated — it meant a lot. And I think, somewhere, it made me a little more competitive, a little more curious.
That memory came back when we got a request from KEF and ATECF:
They wanted to give certificates to students and parents after completing a task. A small gesture, but a powerful way to keep learners motivated and appreciated..
Starting with the Ask
So the request was simple and clear:
- There should be a way to upload and manage certificate templates.
- Each certificate should be auto-filled with personalized data (like name, task, date, etc.) once a task is completed, and then sent to the user.
We nodded. Sounds doable.
After a few rounds of discussion and back-and-forth on what was needed, we finalized the flow, and just like that — we were off.
Our Initial Thought – Cloud Functions
At first, we thought we’d use cloud functions The idea was:
- When a certificate is needed, trigger a cloud function.
- The cloud function would take the template, fill in the user data, generate the certificate, upload it to the NGO’s GCS bucket, and return the image.
- Finally, we would send that certificate image to the user.
But then reality hit us:
- The cloud function would need access to both the user’s personal data and the NGO’s GCS credentials.
- Mixing access like that didn’t seem like a good security practice.
- Also, there were concerns around reliability and debugging issues if anything failed midway in the cloud function.
So we stepped back and decided to rethink the approach
The Final Approach – Keep It Local, Keep It Clean
After a few experiments (and a couple of dead ends), we decided to pull certificate generation entirely into our own backend
It gave us full control, easier debugging, better visibility, and just a cleaner developer experience overall. No detours, no magic behind the curtain — everything lives inside our system now.
While exploring options for certificate generation, we came across an implementation by the Udhyam team, where they used Google Slides effectively for this purpose. Their approach was well-documented and worked seamlessly for them, which encouraged us to dig deeper into it. Inspired by their setup, we decided to build our solution around Google Slides — and it turned out to be the perfect fit for our needs. Big shout-out to the Udhyam team for paving the way with such a solid reference implementation!
So we chose Google Slides as the foundation for certificate generation.
Why Google Slides?
Three reasons:
- It’s super flexible and visually editable — NGOs can design certificates however they want.
- Most design tools (like canva) support exporting to ppt which google slides support
- We already use GCS (Google Cloud Storage) in Glific, so integrating it into our pipeline was smooth sailing.
But the real magic? Slides support programmatic text replacement. That means we could take a clean-looking certificate, drop in placeholders like {1} or {2}, and replace them dynamically via the Slides API.
Step 1: Getting Set Up
Before using this feature, a few things need to be done (don’t worry, it’s a one-time thing):
Before using this feature, a few things need to be done (don’t worry, it’s a one-time thing):
- Enable the Slides and Drive APIs in the NGO’s GCP project.
- Create a service account with editor access to google cloud resources
- Share the template Google Slide with that service account (yes, this is critical — or nothing will work).
Then create the certificate in Glific UI and use that certificate
We’ve put together a detailed guide here: Glific Docs – Custom Certificates
Step 2: Designing the Certificate
Once everything’s in place, NGOs can upload their certificate design as a Google Slide.
All we need to do is insert placeholders — like {1}, {2}, {3} — in the slide where we want data to appear.
Example:
- {1} could be the student’s name
- {2} might be the worksheet title
- {3} could be the teacher’s signature
This gives full creative freedom while keeping the structure simple and developer-friendly.
Schema changes:
To support the certificate issuance feature, we made changes in the database by introducing:
- CertificateTemplate represents reusable templates for generating certificates.
- IssuedCertificate records every certificate issued to a contact and logs any errors encountered during the generation process.

- Each Organization can own multiple certificate templates.
- Each CertificateTemplate can be used to issue multiple certificates.
- Each IssuedCertificate is linked to a Contact.
Step 3: Integrating with Flows
We added a webhook called create_certificate, which can be triggered inside any flow (like after someone completes a worksheet).
Here’s how the payload looks:

Why Not Just Use @contact.xx Directly in the Slide?
Note: @contact refers to information about the user you’re messaging, while @results refers to the responses they give during a flow.
That’s actually what we tried first. We thought: “Hey, why not just put @contact.name or @results.message directly in the slide?”
Turns out — that’s not how Glific’s webhook system works.
By the time the request hits our create certificate function, those variables are already parsed and replaced. We couldn’t tell what the original placeholders were anymore. That meant we’d either have to hack around how all webhooks work (bad idea) or find another way.
So we ditched that plan and introduced {1}, {2}… a clean key-value pair system. It made things way more predictable, and it didn’t break the rest of Glific.
Step 4: How Certificate Generation Actually Works
Here’s the behind-the-scenes flow, once a webhook hits our backend:
- We make a copy of the original certificate template using the Drive API.
- Using the Slides BatchUpdate API, we replace all placeholders ({1}, {2}, etc.) with real values pulled from the contact or worksheet data.
- After updating the content, we generate a thumbnail of the slide
- Then:
- We download the file.
- Upload it to the NGO’s GCS bucket.
- Send the file back to the user (in PNG format).
- We download the file.
5. We delete the copied slide using the Drive API.
We’ve covered unit tests for this feature, and Cypress (end-to-end) tests are currently in progress.
What About Privacy?
We were careful about access control.
- Templates should always be private.
- Only the service account should have access.
- Once a copy of the slide is made, that copy is only accessible to the service account.
This means no one outside the intended system can access certificates unless they’re explicitly given permission.
No public links. No accidental sharing. Just clean, private, and secure.
Final Thoughts
This feature started with a simple idea: “Let’s help NGOs appreciate their learners.”
But building it meant stitching together multiple APIs, solving some weird edge cases, and finding the right balance between flexibility and simplicity.
We learned a lot along the way — not just about Slides or Drive, but about making tools that feel empowering, not overwhelming.
And seeing those beautiful certificates get sent out automatically? That’s the good stuff.
We recently used the certificate feature during our internal team sprint, and it turned out wonderfully! A special shoutout to Akansha, who used it so beautifully to recognize everyone’s contributions — it truly added a personal and celebratory touch. You can read more about the experience in this blog: Dogfooding Glific: What I Learned by Being a User for a Week.
Moments like these really show how even small features can make a big impact.
Leave a Reply