AutomationFlowsData & Sheets › Automated PDF Report Downloader & Organizer with Google Drive & Sheets

Automated PDF Report Downloader & Organizer with Google Drive & Sheets

ByOmer Fayyaz @omerfayyaz on n8n.io

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…

Event trigger★★★★☆ complexity22 nodesExecute Workflow TriggerGoogle SheetsHTTP RequestGoogle Drive
Data & Sheets Trigger: Event Nodes: 22 Complexity: ★★★★☆ Added:

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 →

Download .json
{
  "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.

Pro

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 →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

PCN. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 60 nodes.

Google Sheets, HTTP Request, @N Octo N/N8N Nodes Json Database +3
Data & Sheets

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

Google Sheets, Google Drive, HTTP Request
Data & Sheets

🔥 March Sale – n8n Community Members Get ideoGener8r for Just $27! (Reg. $47) Use Coupon Code: (Valid until 3/31/2025 for n8n community members)

HTTP Request, Google Drive, Google Sheets
Data & Sheets

📄 Documentation: Notion Guide

Google Sheets, Google Drive, HTTP Request +2
Data & Sheets

Overview

Google Sheets, Google Drive, HTTP Request