This workflow corresponds to n8n.io template #11228 — we link there as the canonical source.
This workflow follows the Execute Workflow Trigger → Google Drive 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": "O6vEiybPAvV7wzV2",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "PDF Research Report Collector & Processor",
"tags": [],
"nodes": [
{
"id": "29309be7-f23d-4747-9b5b-01c6154ff55a",
"name": "Sticky Note - Introduction",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
-16
],
"parameters": {
"width": 616,
"height": 592,
"content": "## PDF Research Report Collector & Processor\n\nAutomatically download PDFs from discovered URLs, upload to Google Drive, and track metadata.\n\n## How it works:\n1. **Read PDF URLs** \u2192 Get pending PDFs from Google Sheets\n2. **Download PDF** \u2192 Binary HTTP request with file response\n3. **Extract Metadata** \u2192 Parse filename, size, content type\n4. **Upload to Drive** \u2192 Store in organized folder\n5. **Save Metadata** \u2192 Link file info in Google Sheets\n6. **Update Status** \u2192 Mark URL as processed\n\n## Setup steps \n1. **Google Sheets Integration**: Connect your Google Sheets account and provide the necessary credentials. \n2. **Configure Sheet Names**: Set the sheet names for \"PDF URLs\", \"PDF Library\", and \"Error Log\". \n3. **Set Up PDF URL Extraction**: Ensure URLs are correctly placed in the \"PDF_URL\" column of \"PDF URLs\". \n4. **Run Workflow**: Trigger the workflow manually or set it to run every 12 hours."
},
"typeVersion": 1
},
{
"id": "b9f3962f-d4ed-4352-a2eb-e5c24cd5a110",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"position": [
48,
0
],
"parameters": {},
"typeVersion": 1
},
{
"id": "47f4dd5b-2adc-4f0f-9cbd-cd31c78635ba",
"name": "Schedule (Every 12 Hours)",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
32,
240
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 12
}
]
}
},
"typeVersion": 1.2
},
{
"id": "77d0c109-cfe0-421f-ab0b-77da9f5b0c20",
"name": "Called by Another Workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
32,
448
],
"parameters": {
"inputSource": "passthrough"
},
"typeVersion": 1.1
},
{
"id": "fcd36d1f-613e-4448-a343-e6c1e8ddb1aa",
"name": "Read Pending PDF URLs",
"type": "n8n-nodes-base.googleSheets",
"position": [
400,
240
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "PDF URLs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SPREADSHEET"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "e3ad7ecf-65e7-4fdc-9445-129ff8d461fe",
"name": "Loop Over PDFs",
"type": "n8n-nodes-base.splitInBatches",
"position": [
656,
336
],
"parameters": {
"options": {
"reset": false
}
},
"typeVersion": 3
},
{
"id": "fc9f12ae-00e0-4b97-8dd7-3c41da23d6a6",
"name": "Prepare Download Info",
"type": "n8n-nodes-base.code",
"position": [
896,
352
],
"parameters": {
"jsCode": "// Extract filename from URL and check for valid PDF\nconst results = [];\n\nfor (const item of items) {\n const pdfUrl = item.json.PDF_URL || item.json.pdf_url || item.json.url || \"\";\n \n if (!pdfUrl) {\n results.push({\n json: {\n ...item.json,\n isValid: false,\n skipReason: \"No PDF URL provided\"\n }\n });\n continue;\n }\n \n // Extract filename from URL\n let fileName = \"\";\n try {\n const urlObj = new URL(pdfUrl);\n const pathParts = urlObj.pathname.split(\"/\");\n fileName = pathParts[pathParts.length - 1] || \"\";\n \n // Decode URL-encoded characters\n fileName = decodeURIComponent(fileName);\n \n // If no filename or no extension, generate one\n if (!fileName || !fileName.includes(\".\")) {\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n fileName = \"report-\" + timestamp + \".pdf\";\n }\n } catch (e) {\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n fileName = \"report-\" + timestamp + \".pdf\";\n }\n \n // Validate it looks like a PDF URL\n const isPdfUrl = pdfUrl.toLowerCase().includes(\".pdf\") || \n pdfUrl.toLowerCase().includes(\"pdf\") ||\n pdfUrl.toLowerCase().includes(\"download\");\n \n results.push({\n json: {\n ...item.json,\n pdfUrl: pdfUrl,\n fileName: fileName,\n isValid: true,\n isPdfUrl: isPdfUrl\n }\n });\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "d5a40004-4b38-4aea-9ade-743c9dfda063",
"name": "Is Valid URL?",
"type": "n8n-nodes-base.if",
"position": [
1136,
352
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "valid-check",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.isValid }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "a83b06dd-48ed-4c6b-a238-53796d4b82f7",
"name": "Download PDF",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
1440,
80
],
"parameters": {
"url": "={{ $json.pdfUrl }}",
"options": {
"timeout": 60000,
"response": {
"response": {
"fullResponse": true,
"responseFormat": "file"
}
}
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/0.0.0.0 Safari/537.36"
},
{
"name": "Accept",
"value": "application/pdf,application/octet-stream,*/*"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "6bf86e24-9628-4577-8890-7b43267fbc05",
"name": "Download Success?",
"type": "n8n-nodes-base.if",
"position": [
1664,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "has-binary",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ Object.keys($binary).length > 0 }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "b38fd492-657a-463d-ba1f-a7089669aaf2",
"name": "Upload to Google Drive",
"type": "n8n-nodes-base.googleDrive",
"onError": "continueRegularOutput",
"position": [
2192,
64
],
"parameters": {
"name": "={{ $('Prepare Download Info').item.json.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "PDF_Reports"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "ade19256-0bc7-4f75-86f8-dbbcd381d880",
"name": "Extract File Metadata",
"type": "n8n-nodes-base.code",
"position": [
2416,
64
],
"parameters": {
"jsCode": "// Extract metadata from uploaded file\nconst results = [];\n\nfor (const item of items) {\n const prepData = $('Prepare Download Info').item.json;\n const driveData = item.json;\n \n // Get file info from Google Drive response\n const fileId = driveData.id || \"\";\n const fileName = driveData.name || prepData.fileName || \"unknown.pdf\";\n const mimeType = driveData.mimeType || \"application/pdf\";\n const fileSize = driveData.size || 0;\n const webViewLink = driveData.webViewLink || \"\";\n const webContentLink = driveData.webContentLink || \"\";\n \n results.push({\n json: {\n pdfUrl: prepData.pdfUrl,\n title: prepData.Title || prepData.title || fileName.replace(\".pdf\", \"\"),\n source: prepData.Source || prepData.source || \"Unknown\",\n fileName: fileName,\n fileId: fileId,\n mimeType: mimeType,\n fileSize: fileSize,\n driveUrl: webViewLink || (\"https://drive.google.com/file/d/\" + fileId + \"/view\"),\n downloadUrl: webContentLink,\n downloadedAt: new Date().toISOString(),\n status: \"Downloaded\"\n }\n });\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "f68461c6-90d9-424b-bd10-d4f1b0d47995",
"name": "Mark as Failed",
"type": "n8n-nodes-base.set",
"position": [
1888,
176
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "status-failed",
"name": "status",
"type": "string",
"value": "Failed"
},
{
"id": "error-msg",
"name": "errorMessage",
"type": "string",
"value": "Download failed - file may not exist or access denied"
},
{
"id": "pdf-url",
"name": "pdfUrl",
"type": "string",
"value": "={{ $('Prepare Download Info').item.json.pdfUrl }}"
},
{
"id": "title",
"name": "title",
"type": "string",
"value": "={{ $('Prepare Download Info').item.json.Title }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "093eb8ab-6d40-42d0-b76f-2a5dc7208d5f",
"name": "Mark as Invalid",
"type": "n8n-nodes-base.set",
"position": [
1888,
368
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "status-invalid",
"name": "status",
"type": "string",
"value": "Invalid"
},
{
"id": "skip-reason",
"name": "errorMessage",
"type": "string",
"value": "={{ $json.skipReason }}"
},
{
"id": "pdf-url",
"name": "pdfUrl",
"type": "string",
"value": "={{ $json.PDF_URL }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "d8b68d65-8d3a-46e1-aca4-41b4e7ff161b",
"name": "Save to PDF Library",
"type": "n8n-nodes-base.googleSheets",
"position": [
2640,
64
],
"parameters": {
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "PDF Library"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SPREADSHEET"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "d037741f-44fe-4966-b946-eb1b6168c73d",
"name": "Update Source Status",
"type": "n8n-nodes-base.googleSheets",
"position": [
2640,
352
],
"parameters": {
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "PDF URLs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SPREADSHEET"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "456cdecf-2595-40c4-85c2-e5986d3af2ae",
"name": "Log Error",
"type": "n8n-nodes-base.googleSheets",
"position": [
2192,
272
],
"parameters": {
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Error Log"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SPREADSHEET"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "b34cfab8-f1a1-46bf-b937-062fa5610921",
"name": "Completion Summary",
"type": "n8n-nodes-base.set",
"position": [
896,
144
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "count",
"name": "pdfsProcessed",
"type": "number",
"value": "={{ $items().length }}"
},
{
"id": "timestamp",
"name": "completedAt",
"type": "string",
"value": "={{ $now.toISO() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "31591f02-59cd-4aa5-b28f-a3892d3cf250",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
2112,
-16
],
"parameters": {
"color": 7,
"width": 720,
"height": 576,
"content": "## Save PDF to Drive and Log in Google Sheet"
},
"typeVersion": 1
},
{
"id": "bfdcfc23-e5d5-42f5-99c4-d20dfac705ac",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1600,
-16
],
"parameters": {
"color": 7,
"width": 496,
"height": 576,
"content": "## Validate the Downloaded PDF"
},
"typeVersion": 1
},
{
"id": "14fff295-df64-4b51-859d-ead8b8934702",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1088,
-16
],
"parameters": {
"color": 7,
"width": 496,
"height": 576,
"content": "## Validate URL and Downloaded PDF"
},
"typeVersion": 1
},
{
"id": "fa06b8c5-8f72-4182-9da9-fe407b6878e9",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
320,
-16
],
"parameters": {
"color": 7,
"width": 256,
"height": 576,
"content": "## Read PDF URLs"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "554bfcfc-0b6b-438e-a7ca-0f5d99bcefcb",
"connections": {
"Log Error": {
"main": [
[
{
"node": "Update Source Status",
"type": "main",
"index": 0
}
]
]
},
"Download PDF": {
"main": [
[
{
"node": "Download Success?",
"type": "main",
"index": 0
}
]
]
},
"Is Valid URL?": {
"main": [
[
{
"node": "Download PDF",
"type": "main",
"index": 0
}
],
[
{
"node": "Mark as Invalid",
"type": "main",
"index": 0
}
]
]
},
"Loop Over PDFs": {
"main": [
[
{
"node": "Completion Summary",
"type": "main",
"index": 0
}
],
[
{
"node": "Prepare Download Info",
"type": "main",
"index": 0
}
]
]
},
"Manual Trigger": {
"main": [
[
{
"node": "Read Pending PDF URLs",
"type": "main",
"index": 0
}
]
]
},
"Mark as Failed": {
"main": [
[
{
"node": "Log Error",
"type": "main",
"index": 0
}
]
]
},
"Mark as Invalid": {
"main": [
[
{
"node": "Log Error",
"type": "main",
"index": 0
}
]
]
},
"Download Success?": {
"main": [
[
{
"node": "Upload to Google Drive",
"type": "main",
"index": 0
}
],
[
{
"node": "Mark as Failed",
"type": "main",
"index": 0
}
]
]
},
"Save to PDF Library": {
"main": [
[
{
"node": "Update Source Status",
"type": "main",
"index": 0
}
]
]
},
"Update Source Status": {
"main": [
[
{
"node": "Loop Over PDFs",
"type": "main",
"index": 0
}
]
]
},
"Extract File Metadata": {
"main": [
[
{
"node": "Save to PDF Library",
"type": "main",
"index": 0
}
]
]
},
"Prepare Download Info": {
"main": [
[
{
"node": "Is Valid URL?",
"type": "main",
"index": 0
}
]
]
},
"Read Pending PDF URLs": {
"main": [
[
{
"node": "Loop Over PDFs",
"type": "main",
"index": 0
}
]
]
},
"Upload to Google Drive": {
"main": [
[
{
"node": "Extract File Metadata",
"type": "main",
"index": 0
}
]
]
},
"Schedule (Every 12 Hours)": {
"main": [
[
{
"node": "Read Pending PDF URLs",
"type": "main",
"index": 0
}
]
]
},
"Called by Another Workflow": {
"main": [
[
{
"node": "Read Pending PDF URLs",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleDriveOAuth2ApigoogleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Intelligent URL Validation - Validates PDF URLs before attempting download, extracting filenames from URLs and generating fallback names when needed, preventing wasted processing time Binary File Handling - Properly handles PDF downloads as binary files with appropriate headers…
Source: https://n8n.io/workflows/11228/ — 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