This workflow corresponds to n8n.io template #13219 — we link there as the canonical source.
This workflow follows the Google Drive → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "UwWFNPUauG6I7NdKhcV1V",
"name": "Bulk certificate generator from Google Sheets and Slides",
"tags": [],
"nodes": [
{
"id": "f352d49c-d9bc-49fa-8b0a-c43a94d321fa",
"name": "When clicking 'Test workflow'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-272,
-32
],
"parameters": {},
"typeVersion": 1
},
{
"id": "4651f9ff-07a3-4857-9d69-06cf864315e5",
"name": "Read Unprocessed Recipients",
"type": "n8n-nodes-base.googleSheets",
"position": [
-48,
-32
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "FALSE",
"lookupColumn": "Processed"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "5b34aeac-f173-4c22-8826-930bb392182f",
"name": "Process One at a Time",
"type": "n8n-nodes-base.splitInBatches",
"position": [
224,
-32
],
"parameters": {
"options": {
"reset": false
}
},
"typeVersion": 3
},
{
"id": "0d054ec2-6ac2-43f9-a5f7-3ce5a4399556",
"name": "Copy Slides Template",
"type": "n8n-nodes-base.httpRequest",
"position": [
480,
-16
],
"parameters": {
"url": "=https://www.googleapis.com/drive/v3/files/YOUR_TEMPLATE_SLIDES_ID/copy",
"method": "POST",
"options": {},
"jsonBody": "={{ JSON.stringify({ name: 'Certificate_' + $json['CertificateID'] }) }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleDriveOAuth2Api"
},
"typeVersion": 4.2
},
{
"id": "546fe323-348e-4345-9658-abb66e898a19",
"name": "Replace Template Placeholders",
"type": "n8n-nodes-base.httpRequest",
"position": [
688,
-16
],
"parameters": {
"url": "=https://slides.googleapis.com/v1/presentations/{{ $json.id }}:batchUpdate",
"method": "POST",
"options": {},
"jsonBody": "={\n \"requests\": [\n {\n \"replaceAllText\": {\n \"containsText\": { \"text\": \"{{name}}\", \"matchCase\": false },\n \"replaceText\": \"{{ $('Process One at a Time').item.json.Name }}\"\n }\n },\n {\n \"replaceAllText\": {\n \"containsText\": { \"text\": \"{{date}}\", \"matchCase\": false },\n \"replaceText\": \"{{ $('Process One at a Time').item.json.Date }}\"\n }\n },\n {\n \"replaceAllText\": {\n \"containsText\": { \"text\": \"{{certificateid}}\", \"matchCase\": false },\n \"replaceText\": \"{{ $('Process One at a Time').item.json['CertificateID'] }}\"\n }\n }\n ]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleSlidesOAuth2Api"
},
"typeVersion": 4.2
},
{
"id": "404a9f32-2653-46f1-ae0f-da5e517b85f1",
"name": "Export to PDF",
"type": "n8n-nodes-base.httpRequest",
"position": [
912,
-16
],
"parameters": {
"url": "=https://www.googleapis.com/drive/v3/files/{{ $('Copy Slides Template').item.json.id }}/export?mimeType=application/pdf",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleSlidesOAuth2Api"
},
"typeVersion": 4.2
},
{
"id": "e1d0a513-024c-49c5-b5b0-6af8145ccf09",
"name": "Save PDF to Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
1152,
-16
],
"parameters": {
"name": "={{ $('Process One at a Time').item.json['CertificateID']}}.pdf",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "YOUR_OUTPUT_FOLDER_ID"
}
},
"typeVersion": 3,
"alwaysOutputData": true
},
{
"id": "beda0ef7-7376-431c-b753-2565efa28f5f",
"name": "Mark as Processed",
"type": "n8n-nodes-base.googleSheets",
"position": [
1376,
-16
],
"parameters": {
"columns": {
"value": {
"DriveLink": "={{ $('Save PDF to Drive').item.json.webViewLink }}",
"Processed": "TRUE",
"CertificateID": "={{ $('Read Unprocessed Recipients').item.json['CertificateID'] }}"
},
"mappingMode": "defineBelow",
"matchingColumns": [
"CertificateID"
]
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "e85e5469-bfeb-43d2-a9d1-e478f06695a6",
"name": "Delete Temporary Slide",
"type": "n8n-nodes-base.httpRequest",
"position": [
1600,
-16
],
"parameters": {
"url": "=https://www.googleapis.com/drive/v3/files/{{ $('Copy Slides Template').item.json.id }}",
"method": "DELETE",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleSlidesOAuth2Api"
},
"typeVersion": 4.2
},
{
"id": "420a078e-5d83-416f-9b23-0c16e89222d3",
"name": "Wait 2s (Rate Limit)",
"type": "n8n-nodes-base.wait",
"position": [
1824,
-16
],
"parameters": {
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "4cfca671-cf3d-48c5-905a-3f86db1d4433",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-928,
-240
],
"parameters": {
"width": 560,
"height": 550,
"content": "## How it works\nThis workflow generates personalized PDF certificates in bulk using Google Sheets as the data source and Google Slides as the template engine.\n\n1. Reads recipient data from a Google Sheet (only rows where Processed = FALSE)\n2. For each recipient, copies your Slides template and replaces placeholders with actual values\n3. Exports the personalized slide as a PDF and saves it to Google Drive\n4. Updates the spreadsheet with the Drive link and marks the row as processed\n5. Cleans up by deleting the temporary slide copy\n\n## Setup steps\n1. **Google Sheet**: Create a sheet with columns: Name, Date, CertificateID, Processed, DriveLink. Set Processed to FALSE for new entries.\n2. **Slides Template**: Create a template with placeholders: {{name}}, {{date}}, {{certificateid}}\n3. **Credentials**: Connect Google Sheets, Drive, and Slides OAuth2 credentials\n4. **Configure IDs**: Replace YOUR_GOOGLE_SHEET_ID, YOUR_TEMPLATE_SLIDES_ID, and YOUR_OUTPUT_FOLDER_ID in the nodes\n5. **Test**: Run with one row first to verify everything works correctly"
},
"typeVersion": 1
},
{
"id": "2da79aa7-186f-4239-9946-611867eb56de",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
-176
],
"parameters": {
"color": 7,
"width": 652,
"height": 336,
"content": "### \ud83d\udce5 Data Input\nReads recipients from Google Sheets and processes them one at a time to avoid API rate limits."
},
"typeVersion": 1
},
{
"id": "8b5724f3-07ab-4e46-ad57-b2d9730ea818",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
400,
-176
],
"parameters": {
"color": 7,
"width": 680,
"height": 336,
"content": "### \ud83c\udfa8 Certificate Generation\nCopies the Slides template, replaces placeholders with recipient data, and exports as PDF."
},
"typeVersion": 1
},
{
"id": "73124c2f-6c78-49f3-8571-c3e59487c0c4",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
-176
],
"parameters": {
"color": 7,
"width": 450,
"height": 336,
"content": "### \ud83d\udcbe Save & Update\nSaves the PDF to Drive and updates the spreadsheet with the file link."
},
"typeVersion": 1
},
{
"id": "28057c2a-b7e1-4228-abb0-36b5a76af4d0",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1584,
-176
],
"parameters": {
"color": 7,
"width": 414,
"height": 336,
"content": "### \ud83e\uddf9 Cleanup & Loop\nDeletes temporary files and waits 2 seconds before processing the next recipient."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "6a20ac22-9b29-452b-a4c3-0447ac481c28",
"connections": {
"Export to PDF": {
"main": [
[
{
"node": "Save PDF to Drive",
"type": "main",
"index": 0
}
]
]
},
"Mark as Processed": {
"main": [
[
{
"node": "Delete Temporary Slide",
"type": "main",
"index": 0
}
]
]
},
"Save PDF to Drive": {
"main": [
[
{
"node": "Mark as Processed",
"type": "main",
"index": 0
}
]
]
},
"Copy Slides Template": {
"main": [
[
{
"node": "Replace Template Placeholders",
"type": "main",
"index": 0
}
]
]
},
"Wait 2s (Rate Limit)": {
"main": [
[
{
"node": "Process One at a Time",
"type": "main",
"index": 0
}
]
]
},
"Process One at a Time": {
"main": [
[],
[
{
"node": "Copy Slides Template",
"type": "main",
"index": 0
}
]
]
},
"Delete Temporary Slide": {
"main": [
[
{
"node": "Wait 2s (Rate Limit)",
"type": "main",
"index": 0
}
]
]
},
"Read Unprocessed Recipients": {
"main": [
[
{
"node": "Process One at a Time",
"type": "main",
"index": 0
}
]
]
},
"Replace Template Placeholders": {
"main": [
[
{
"node": "Export to PDF",
"type": "main",
"index": 0
}
]
]
},
"When clicking 'Test workflow'": {
"main": [
[
{
"node": "Read Unprocessed Recipients",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Categories: Productivity, Education, Google, Automation
Source: https://n8n.io/workflows/13219/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
PCN. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 60 nodes.
The workflow automates the process of gathering extensive keyword data for a "Main Keyword." It starts by reading initial parameters from a Google Sheets template, creates a new dedicated Google Sheet
🔥 March Sale – n8n Community Members Get ideoGener8r for Just $27! (Reg. $47) Use Coupon Code: (Valid until 3/31/2025 for n8n community members)
📄 Documentation: Notion Guide
Overview