Auto-generate & Auto-send Certificates from Google Forms

Published on September 28, 2025 by @mritxperts

Short description: Step-by-step tutorial to auto-create PDF certificates from a Google Slides template and email them automatically when someone submits your Google Form. Includes ready-to-use Google Apps Script, troubleshooting tips, and optional extras you can add.


Why this? Who it’s for

If you run workshops, online classes, events, or assessments and want to automatically give participants a certificate when they complete a Google Form, this tutorial shows a simple, free method using:

  • Google Forms (collect responses)
  • Google Sheets (response storage)
  • Google Slides (certificate template)
  • Google Apps Script (automation + email)

Perfect for teachers, trainers, event organizers, and small course creators.


Prerequisites

  • A Google account with permission to create Forms/Slides/Sheets.
  • A Google Form that collects at least Name and Email (both required). If your Form uses different field names, this tutorial shows how to adapt.
  • A Google Slides presentation you will use as the certificate template (placeholders required — details below).

Quick overview of steps

  1. Create and link your Google Form to a Google Sheet.
  2. Design a Google Slides certificate template with placeholders (e.g., {{Name}}, {{Event}}, {{Date}}).
  3. Open the linked Google Sheet → Extensions → Apps Script and paste the script below.
  4. Add an Installable trigger: On form submitsendCertificate.
  5. Test a form submission and verify the emailed PDF certificate.

1) Create the Google Form & link to a Sheet

  1. Create a Google Form (forms.google.com).
  2. Add required fields: Name and Email (exact header names are helpful but not required).
  3. Click the Responses tab → click the green Sheets icon to create or choose a linked Google Sheet. The Sheet will receive each submission as a new row (timestamp + fields).

Tip: Keep the first sheet (tab) as the response sheet (it’s where the script will look by default).


2) Create a Google Slides certificate template

  1. Open Google Slides (slides.google.com) and create a new presentation.
  2. Set the page size: File → Page setup → Custom — I like 11 x 8.5 in (landscape).
  3. Design your certificate. Wherever you want to insert dynamic text, write placeholders exactly like these (including braces):
  • {{Name}}
  • {{Event}}
  • {{Date}}

You can add additional placeholders such as {{Serial}} or {{Score}} if you want to merge more fields.

  1. Get the Slides file ID from the URL, for example:
https://docs.google.com/presentation/d/XXXXXXXXXXXXXXXXXXXXXXXXXXXX/edit

Copy the long XXXXXXXXXXXXXXXX... part — that is your template ID.


3) The Apps Script (paste into the linked Google Sheet)

Open the linked Google Sheet → ExtensionsApps Script. In the code editor replace any default content with the script below. Update the configuration variables at the top: TEMPLATE_SLIDES_ID, EVENT_NAME, and optionally CERTIFICATES_FOLDER_ID.

Important: This script is written to be resilient: it will try to find Name and Email using common header names. If your Sheet uses different column titles, either change them or edit the header-name lists inside the script.

Copy‑paste ready script

// ===================== CONFIG =====================
var TEMPLATE_SLIDES_ID = 'YOUR_SLIDES_TEMPLATE_ID'; // replace with your Slides template ID
var EVENT_NAME = 'AI Workshop 2025';                // replace with your event name
var CERTIFICATES_FOLDER_ID = '';                    // optional: Google Drive folder ID to save copies (leave blank to skip)

// ==================================================

function sendCertificate(e) {
  try {
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getActiveSheet();

    // Determine the row that was just submitted.
    var row;
    if (e && e.range && typeof e.range.getRow === 'function') {
      row = e.range.getRow();
    } else {
      // fallback — use last row in sheet
      row = sheet.getLastRow();
    }

    var lastColumn = sheet.getLastColumn();
    var headers = sheet.getRange(1, 1, 1, lastColumn).getValues()[0];
    var rowData = sheet.getRange(row, 1, 1, lastColumn).getValues()[0];

    // Build a normalized header -> value map (lowercased keys)
    var normalized = {};
    for (var i = 0; i < headers.length; i++) {
      var key = headers[i] ? headers[i].toString().trim().toLowerCase() : ('column' + (i+1));
      normalized[key] = rowData[i];
    }

    function getByHeaders(candidates) {
      for (var j = 0; j < candidates.length; j++) {
        var test = candidates[j].toLowerCase();
        if (normalized[test]) return normalized[test];
      }
      return null;
    }

    // Try common header names for name and email
    var name = getByHeaders(['name', 'full name', 'participant name', 'your name', 'student name']) || rowData[1] || 'Participant';
    var email = getByHeaders(['email', 'e-mail', 'email address', 'your email', 'email id']) || rowData[2];

    if (!email) {
      Logger.log('No email address found in row ' + row + '. Aborting sending certificate.');
      return;
    }

    // Extra dynamic placeholders you can set here
    var dateStr = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'dd MMM yyyy');
    var certSerial = 'CERT-' + new Date().getTime(); // unique-ish serial

    // Make a copy of the Slides template
    var templateFile = DriveApp.getFileById(TEMPLATE_SLIDES_ID);
    var copyFile = templateFile.makeCopy('Certificate - ' + name + ' - ' + certSerial);
    var copyId = copyFile.getId();

    // Open the copy and replace placeholders on every slide
    var presentation = SlidesApp.openById(copyId);
    var slides = presentation.getSlides();
    for (var s = 0; s < slides.length; s++) {
      slides[s].replaceAllText('{{Name}}', name);
      slides[s].replaceAllText('{{Event}}', EVENT_NAME);
      slides[s].replaceAllText('{{Date}}', dateStr);
      slides[s].replaceAllText('{{Serial}}', certSerial);

      // If you added other placeholders in your Slides (e.g. {{Score}}), replace them here.
      // Example: slides[s].replaceAllText('{{Score}}', getByHeaders(['score','marks']) || '');
    }
    presentation.saveAndClose();

    // Convert the copy to PDF
    var pdfBlob = DriveApp.getFileById(copyId).getAs('application/pdf').setName('Certificate - ' + name + '.pdf');

    // Optionally move/add the copy to a folder (if CERTIFICATES_FOLDER_ID is set)
    if (CERTIFICATES_FOLDER_ID && CERTIFICATES_FOLDER_ID.length > 5) {
      try {
        var folder = DriveApp.getFolderById(CERTIFICATES_FOLDER_ID);
        folder.addFile(DriveApp.getFileById(copyId));
      } catch (folderErr) {
        Logger.log('Error adding file to folder: ' + folderErr);
      }
    }

    // Email the PDF
    var subject = 'Your Certificate - ' + EVENT_NAME;
    var body = 'Dear ' + name + ',\n\nThank you for participating in ' + EVENT_NAME + '. Please find attached your certificate.\n\nRegards,\n[Your Organization]';

    MailApp.sendEmail({
      to: email,
      subject: subject,
      body: body,
      attachments: [pdfBlob]
    });

    // Optional cleanup: put the copy in trash if you don't want to store it
    // DriveApp.getFileById(copyId).setTrashed(true);

    // Optional: write "Certificate Sent" status into a column (create column if needed)
    var statusColIndex = -1;
    for (var h = 0; h < headers.length; h++) {
      if (headers[h] && headers[h].toString().trim().toLowerCase() === 'certificate sent') {
        statusColIndex = h + 1; // 1-based
        break;
      }
    }
    if (statusColIndex === -1) {
      // create the column at the end
      statusColIndex = lastColumn + 1;
      sheet.getRange(1, statusColIndex).setValue('Certificate Sent');
    }
    sheet.getRange(row, statusColIndex).setValue('Yes - ' + new Date());

  } catch (err) {
    Logger.log('Error in sendCertificate: ' + err);
  }
}

4) Install the trigger (so script runs automatically on form submit)

  1. In the Apps Script editor click the Triggers icon (clock) on the left.
  2. Click Add trigger (bottom right).
  3. Configure:
    • Choose which function to run: sendCertificate
    • Select event source: From spreadsheet
    • Select event type: On form submit
    • Leave the rest default and save.
  4. The first time you run or trigger the script you’ll be asked to authorize permissions — follow prompts and accept.

5) Test the flow

  • Fill the Google Form with a test name and your email.
  • Check the linked Sheet: a new row should appear.
  • After form submission the script should run (triggered) and you should receive an email with the attached certificate PDF.

6) Optional improvements & ideas

  • Add more placeholders to your Slides template (e.g. {{Score}}, {{Roll}}, {{Organization}}) and replace them in the script.
  • Store certificates in a dedicated Drive folder by setting CERTIFICATES_FOLDER_ID.
  • Add a QR code or certificate verification link (requires additional API or service).
  • Use GmailApp with htmlBody if you want prettier emails (but watch quotas).
  • Limit sending to unique submissions by checking if the email already has Certificate Sent set.

7) Troubleshooting

  • No email sent / script doesn’t run: Check that you added an installable trigger (On form submit). Also open the Apps Script editor and look at Executions or Logs for errors.
  • Authorization required: The script uses DriveApp and MailApp — grant permission when prompted.
  • Wrong name/email picked: The script tries to find common header names. If your sheet uses custom headers, either rename them or update the getByHeaders([...]) candidate lists in the script.
  • Quotas: Google Apps Script has daily email/Drive quotas for consumer accounts. For large mailings, consider batching or use a G Suite/Workspace account.

9) Licensing & credit

You are free to reuse and modify this script for your organization. If you publish it publicly, a short credit back (e.g., “Tutorial adapted from Itxperts“) is appreciated.