Guide
Generate a certificate PDF in n8n
A cohort finishes a course, someone passes a training, a member earns an award — and every one of them needs a branded certificate with their name on it. This is the honest, working version: a real n8n workflow that turns a row of roster data into a certificate PDF and files it in Google Drive, with the copy-paste JSON and a step-by-step walkthrough. First, the thing that shapes the whole workflow — a certificate is a mail-merge.
A certificate is a mail-merge
You rarely make one certificate. The job shows up when a class graduates, a training wraps, or a membership renews — and suddenly there are tens or hundreds to issue, every one identical in design but personalised with a different name, program, and date. That is a mail-merge: one row of data produces one document.
- The data — a roster: a Google Sheet, an LMS’s completion export, a form’s responses. Each row is one recipient (name, program, grade, dates).
- The template — one fixed certificate design that every recipient shares.
- The output — one certificate per row, saved or emailed to that recipient.
So this guide builds the single-row version first — trigger → data → certificate → Drive — then points the front at a real roster so n8n runs it once per row (the last section). Only ever need one certificate? The same workflow makes one; the shape does not change.
What you’ll need
- An n8n instance that can install community nodes (self-hosted, or n8n Cloud on a plan that allows them).
- The Generate PDF community node. In n8n: Settings → Community Nodes → Install, and enter the package name:
n8n-nodes-generate-pdfThis is a community node with n8n verification in progress — not a verified node (yet). It installs like any community package and works today; verification only adds an in-editor badge later.
- A pdfmill API credential. Create a key in the pdfmill dashboard (it looks like
pk_live_…), add a credential of type pdfmill API, paste the key, and leave Base URL ashttps://api.pdfmill.dev. Click Test for a green check. - A Google Drive credential if you want each certificate filed automatically (the sample does). Prefer to send them? Add a Gmail or SMTP credential instead — same idea, different destination node.
No headless Chrome, no server — pdfmill renders the certificate on its side and hands the binary back to your workflow. The full click-by-click is the five-minute quickstart.
The workflow, end to end
Here’s a complete, working certificate workflow. Copy it, and in n8n paste it straight onto the canvas (or Workflows → Import from File). It’s four nodes: manual trigger → Set (sample roster row) → Generate PDF (Certificate) → Google Drive.
{
"name": "pdfmill — Sheet row to certificate PDF, saved to Drive",
"nodes": [
{
"parameters": {},
"id": "07-8ee2ec82-b7ac-4527-8922-e64d422d5600",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
300
]
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "{\n \"certificateNumber\": \"CERT-2026-00893\",\n \"organization\": \"Hangang Institute of Automation\",\n \"recipientName\": \"김민준 (Kim Min-jun)\",\n \"programName\": \"業務自動化マスターコース — Workflow Automation Master Course\",\n \"hours\": 40,\n \"grade\": \"A\",\n \"completedAt\": \"2026-07-18\",\n \"issuedAt\": \"2026-07-20\",\n \"issuerName\": \"박서연 (Park Seo-yeon)\",\n \"issuerTitle\": \"Program Director\"\n}",
"options": {}
},
"id": "08-e948006e-75d1-4c01-baf9-da52e1717e06",
"name": "Roster row (sample)",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
300
]
},
{
"parameters": {
"operation": "template",
"template": "certificate",
"data": "={{ $json }}",
"format": "pdf",
"binaryPropertyName": "data",
"options": {}
},
"id": "09-0c2f5c5f-5ff3-4e31-ba2a-66d64a8d6a07",
"name": "Generate certificate PDF",
"type": "n8n-nodes-generate-pdf.generatePdf",
"typeVersion": 1,
"position": [
440,
300
]
},
{
"parameters": {
"operation": "upload",
"inputDataFieldName": "data",
"name": "=Certificate - {{ $json.recipientName }}.pdf",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"folderId": {
"__rl": true,
"mode": "list",
"value": "root"
},
"options": {}
},
"id": "10-755b6b98-7688-40fc-a00b-910846d65de4",
"name": "Upload to Google Drive",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
660,
300
]
},
{
"parameters": {
"content": "## 🎓 Row → Certificate PDF → Drive\nTurn each row (a course completion, an attendee) into a personalised certificate and file it in Drive.\n\n**Setup:** a **pdfmill** credential on the Generate node and a **Google Drive** credential on the upload node.",
"height": 200,
"width": 560,
"color": 5
},
"id": "11-6b834c5a-4aa8-46e8-a441-06f7a9e0b03f",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
0,
40
]
},
{
"parameters": {
"content": "### In production\nReplace the manual trigger with a **Google Sheets Trigger** (or loop rows) so one certificate is generated per attendee.",
"height": 200,
"width": 300,
"color": 4
},
"id": "12-7617f676-966c-472d-adec-c430281fd267",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
220,
520
]
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Roster row (sample)",
"type": "main",
"index": 0
}
]
]
},
"Roster row (sample)": {
"main": [
[
{
"node": "Generate certificate PDF",
"type": "main",
"index": 0
}
]
]
},
"Generate certificate PDF": {
"main": [
[
{
"node": "Upload to Google Drive",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": [
{
"name": "pdfmill"
}
],
"versionId": "135b4e37-a6db-47b2-976a-42bc87bea8c1"
}Walking it left to right:
- When clicking ‘Execute workflow’ — a manual trigger, so you can run it once and see a real certificate. In production you swap this for your roster source (last section).
- Roster row (sample) — a Set node holding one sample roster row as JSON (recipient, program,
hours,grade, the two dates, issuer, and a certificate number). This stands in for one row of your real roster. - Generate certificate PDF — the pdfmill node. Operation: Generate from Template; Template: Certificate; Data:
{{ $json }}(the incoming row); Format: PDF; Put Output File in Field:data. Out comes the certificate as a binary ondata, plus a small JSON summary (pages,bytes,requestId, file name). - Upload to Google Drive — a Google Drive node that uploads the
databinary, naming the fileCertificate - {{ $json.recipientName }}.pdf. Swap Google Drive for Gmail, SMTP, Outlook, S3, or Slack without touching the Generate step.
The two sticky notes in the JSON say the same on the canvas — one marks the setup (a pdfmill credential on the Generate node, a Google Drive credential on the upload node), the other the production step. Add those credentials, then Execute workflow — you get a rendered certificate PDF in your Drive.
The Certificate template and its data shape
Generate from Template means you supply data, not layout — the built-in Certificate starter handles the design. The Data field defaults to {{ $json }}, which passes the whole incoming row through; to feed specific fields instead, map them with an expression. The Certificate template reads these fields:
- The award —
recipientName,programName,hours(hours of instruction), andgrade(final grade). - The issuer —
organization(printed at the top and signed at the foot) andissuerName/issuerTitle(the signatory, e.g. Program Director). - Dates and id —
completedAtandissuedAt(passed as plain dates like2026-07-18; the template formats them), pluscertificateNumber(printed along the bottom edge).
It’s a landscape certificate — gold double border, serif type — and the built-in font pack covers non-Latin scripts, so a recipient’s real name renders correctly rather than as boxes (the sample row is deliberately Korean and Japanese to prove it). Want your own logo, seal, or brand colours? Switch the operation to Generate from HTML and pass your own markup, or start from the other starters (invoice, quote, report, certificate, packing slip). The templates guide covers both. Each certificate counts as one document toward your plan.
PDF or PNG?
The Format field takes PDF or PNG — same node, same data.
- PDF for the certificate of record: selectable text, the file the recipient downloads, prints, or keeps, and what a “download your certificate” button should serve. This is the default.
- PNG when they want to share it rather than file it — and a certificate is one of the most common share cases: an image to post on LinkedIn, embed in a profile or email signature, or drop inline into Slack. It’s a flat image, so use it for display, not as the archival record.
Saving to Drive or emailing the recipient
Because the certificate comes out as a binary on data, anything downstream that takes a binary can consume it. The sample files it to Drive; point that property wherever you need:
- Save it — Google Drive (the sample), S3, or Dropbox, uploading the
databinary — a durable copy per recipient, named from the row. - Email it — Gmail / SMTP / Outlook to the recipient, attaching
data(subject likeYour certificate for {{ $json.programName }}). - Notify — post it to Slack or Telegram as a file.
Swapping the destination never touches the Generate step — the certificate is made once and handed to whichever node comes next.
Generating certificates in bulk
One certificate is the demo; a cohort is the point. To do the whole roster, replace the front of the workflow — the manual trigger and the sample Set — with a real source, and let n8n fan out one item per row:
- Google Sheets → Get rows — read your roster; each row becomes an item, so the Generate node runs once per row and you get one certificate per attendee, each filed under their own name. The workflow’s own note says it: replace the manual trigger with a Google Sheets Trigger (or loop the rows) so one certificate is generated per attendee.
- An LMS or course webhook on completion — issue a certificate the moment someone finishes, rather than in a batch.
- A form submission (n8n Form, Typeform) — a certificate on registration or after an assessment.
n8n runs a node once per incoming item, so a Get-rows node returning 200 rows produces 200 certificates without an explicit loop; add a Loop Over Items (SplitInBatches) node only when you want to throttle or batch a large run.
A 200-person cohort is 200 documents, so size your plan to your biggest run. pdfmill is flat-priced: a permanent Free tier of 75 documents a month (no card), then $9/500, $19/2,000, and $49/10,000 per month. The plan is a hard cap — at the limit the node returns a clear QUOTA_EXCEEDED (402) with an upgrade prompt, never a silent overage or a surprise bill. Current numbers are on the pricing page. Weighing options? See how to generate PDFs in n8n and the best PDF API for n8n.
FAQ
How do I generate certificates in bulk in n8n?
Point the workflow at a source that returns many items — a Google Sheets “Get rows” node reading your roster, an LMS/course-completion webhook, or a form. n8n runs the Generate PDF node once per incoming item, so a sheet of 200 rows produces 200 certificates, each rendered from that row with the recipient’s own name. Add a Loop Over Items (SplitInBatches) node only if you want to throttle a large run. The sample workflow on this page does one row; swap its manual trigger for the sheet to do the whole cohort.
Can I save the certificate to Google Drive automatically?
Yes — that is exactly what the sample workflow does. The Generate PDF node returns the certificate as a binary on the “data” property, and a Google Drive node uploads that binary, naming the file from the row (like “Certificate - {{ recipientName }}.pdf”). Point it at any folder. Swap Google Drive for S3, Dropbox, Gmail, or Slack without changing the Generate step.
PDF or PNG for a certificate?
PDF for the certificate of record — the file the recipient downloads, prints, or keeps; it has selectable text and is what a “download your certificate” button should serve. PNG when they want to share it: a certificate is one of the most common PNG-for-sharing cases — an image to post on LinkedIn, embed in a profile, or drop into an email. Same node and same data; you just switch the Format field.
Does n8n have a certificate node?
No. Nothing in n8n’s core palette generates a completion or award certificate — or turns data into any kind of PDF. You add a community node such as Generate PDF (pdfmill), which renders a branded Certificate template from your data, self-host a headless Chrome, or call a document API. (If you meant an SSL/TLS certificate, that is a different, security thing — not this.)
Can I email the certificate to the recipient?
Yes. The certificate comes out as a binary on the “data” property, so add a Gmail, SMTP, or Outlook node after the Generate step and attach that binary — for example subject “Your certificate for {{ programName }}”, sent to the recipient’s email from the same row. The sample workflow saves to Google Drive instead; emailing is the same shape with a mail node in place of the Drive node.
Is the pdfmill n8n node verified?
It is a community node (n8n-nodes-generate-pdf) with n8n verification in progress — not yet verified. You install it via Settings → Community Nodes like any community package. Everything in this guide works today; verification only adds an in-editor badge and a listing on n8n.io.
The workflow above is the real gallery template that ships with the node — checked July 30, 2026. Options and prices change; this guide links the pricing and comparison pages rather than repeating numbers that go stale here.
See for yourself
Render your first PDF from an n8n workflow in about five minutes — the Free plan is 75 documents a month, no card required.